From e174961ca1a0b28f7abf0be47973ad57cb74e5f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Oct 2008 15:59:26 -0700 Subject: net: convert print_mac to %pM This converts pretty much everything to print_mac. There were a few things that had conflicts which I have just dropped for now, no harm done. I've built an allyesconfig with this and looked at the files that weren't built very carefully, but it's a huge patch. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/wireless/adm8211.c | 5 +- drivers/net/wireless/airo.c | 17 +- drivers/net/wireless/arlan-main.c | 26 ++- drivers/net/wireless/ath9k/core.c | 3 - drivers/net/wireless/ath9k/hw.c | 5 +- drivers/net/wireless/ath9k/main.c | 19 +- drivers/net/wireless/ath9k/rc.c | 9 +- drivers/net/wireless/ath9k/xmit.c | 1 - drivers/net/wireless/atmel.c | 5 +- drivers/net/wireless/b43/main.c | 5 +- drivers/net/wireless/hostap/hostap_80211_rx.c | 59 +++---- drivers/net/wireless/hostap/hostap_80211_tx.c | 15 +- drivers/net/wireless/hostap/hostap_ap.c | 241 +++++++++----------------- drivers/net/wireless/hostap/hostap_hw.c | 10 +- drivers/net/wireless/hostap/hostap_info.c | 16 +- drivers/net/wireless/hostap/hostap_ioctl.c | 16 +- drivers/net/wireless/hostap/hostap_main.c | 26 +-- drivers/net/wireless/hostap/hostap_proc.c | 15 +- drivers/net/wireless/ipw2100.c | 31 +--- drivers/net/wireless/ipw2200.c | 217 ++++++++++------------- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 5 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 5 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 18 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 47 ++--- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 - drivers/net/wireless/iwlwifi/iwl-sta.c | 38 ++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 17 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 54 ++---- drivers/net/wireless/libertas/assoc.c | 32 ++-- drivers/net/wireless/libertas/cmd.c | 5 +- drivers/net/wireless/libertas/debugfs.c | 6 +- drivers/net/wireless/libertas/main.c | 9 +- drivers/net/wireless/libertas/scan.c | 11 +- drivers/net/wireless/libertas/wext.c | 3 +- drivers/net/wireless/libertas_tf/cmd.c | 5 +- drivers/net/wireless/mac80211_hwsim.c | 15 +- drivers/net/wireless/netwave_cs.c | 5 +- drivers/net/wireless/orinoco.c | 10 +- drivers/net/wireless/p54/p54common.c | 5 +- drivers/net/wireless/p54/p54pci.c | 1 - drivers/net/wireless/p54/p54usb.c | 1 - drivers/net/wireless/prism54/isl_ioctl.c | 24 ++- drivers/net/wireless/ray_cs.c | 9 +- drivers/net/wireless/rndis_wlan.c | 9 +- drivers/net/wireless/rt2x00/rt2400pci.c | 4 +- drivers/net/wireless/rt2x00/rt2500pci.c | 5 +- drivers/net/wireless/rt2x00/rt2500usb.c | 4 +- drivers/net/wireless/rt2x00/rt61pci.c | 4 +- drivers/net/wireless/rt2x00/rt73usb.c | 4 +- drivers/net/wireless/rtl8180_dev.c | 5 +- drivers/net/wireless/rtl8187_dev.c | 5 +- drivers/net/wireless/wavelan.c | 33 ++-- drivers/net/wireless/wavelan_cs.c | 30 ++-- drivers/net/wireless/wl3501_cs.c | 10 +- drivers/net/wireless/zd1211rw/zd_chip.c | 4 +- drivers/net/wireless/zd1211rw/zd_mac.c | 6 +- 56 files changed, 437 insertions(+), 754 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index b2c050b..6e18c9d 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1791,7 +1791,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, int err; u32 reg; u8 perm_addr[ETH_ALEN]; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -1925,8 +1924,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, pdev->revision); return 0; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 370133e..7c99f5a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2757,7 +2757,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, struct net_device *dev; struct airo_info *ai; int i, rc; - DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_netdev(sizeof(*ai), "", ether_setup); @@ -2860,8 +2859,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, goto err_out_reg; set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %s", - print_mac(mac, dev->dev_addr)); + airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) @@ -2918,7 +2916,6 @@ int reset_airo_card( struct net_device *dev ) { int i; struct airo_info *ai = dev->priv; - DECLARE_MAC_BUF(mac); if (reset_card (dev, 1)) return -1; @@ -2927,8 +2924,7 @@ int reset_airo_card( struct net_device *dev ) airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - airo_print_info(dev->name, "MAC enabled %s", - print_mac(mac, dev->dev_addr)); + airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) @@ -5330,7 +5326,6 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { int i; char *ptr; APListRid APList_rid; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5354,8 +5349,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { // We end when we find a zero MAC if ( !*(int*)APList_rid.ap[i] && !*(int*)&APList_rid.ap[i][2]) break; - ptr += sprintf(ptr, "%s\n", - print_mac(mac, APList_rid.ap[i])); + ptr += sprintf(ptr, "%pM\n", APList_rid.ap[i]); } if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); @@ -5374,7 +5368,6 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { int rc; /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5411,8 +5404,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%s %*s rssi = %d", - print_mac(mac, BSSList_rid.bssid), + ptr += sprintf(ptr, "%pM %*s rssi = %d", + BSSList_rid.bssid, (int)BSSList_rid.ssidLen, BSSList_rid.ssid, le16_to_cpu(BSSList_rid.dBm)); diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index dec5e87..b608643 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1467,19 +1467,17 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short else if (hw_dst_addr[1] == 0x40) printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); while (dmi) - { if (dmi->dmi_addrlen == 6) - { - DECLARE_MAC_BUF(mac); + { + if (dmi->dmi_addrlen == 6) { if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_ERR "%s mcl %s\n", - dev->name, print_mac(mac, dmi->dmi_addr)); + printk(KERN_ERR "%s mcl %pM\n", + dev->name, dmi->dmi_addr); for (i = 0; i < 6; i++) if (dmi->dmi_addr[i] != hw_dst_addr[i]) break; if (i == 6) break; - } - else + } else printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); dmi = dmi->next; } @@ -1512,18 +1510,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short { char immedDestAddress[6]; char immedSrcAddress[6]; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); - printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n", - dev->name, print_mac(mac, skbtmp), - print_mac(mac2, &skbtmp[6]), - print_mac(mac3, immedDestAddress), - print_mac(mac4, immedSrcAddress)); + printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n", + dev->name, skbtmp, + &skbtmp[6], + immedDestAddress, + immedSrcAddress); } skb->protocol = eth_type_trans(skb, dev); IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index c5033f6..0089e02 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1325,7 +1325,6 @@ struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) { struct ath_vap *avp; struct ath_node *an; - DECLARE_MAC_BUF(mac); avp = sc->sc_vaps[if_id]; ASSERT(avp != NULL); @@ -1355,8 +1354,6 @@ void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag) { unsigned long flags; - DECLARE_MAC_BUF(mac); - ath_chainmask_sel_timerstop(&an->an_chainmask_sel); an->an_flags |= ATH_NODE_CLEAN; ath_tx_node_cleanup(sc, an, bh_flag); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 98bc25c..d5b513e 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -1291,7 +1291,6 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah) int i; u16 eeval; struct ath_hal_5416 *ahp = AH5416(ah); - DECLARE_MAC_BUF(mac); sum = 0; for (i = 0; i < 3; i++) { @@ -1302,8 +1301,8 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah) } if (sum == 0 || sum == 0xffff * 3) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: mac address read failed: %s\n", __func__, - print_mac(mac, ahp->ah_macaddr)); + "%s: mac address read failed: %pM\n", __func__, + ahp->ah_macaddr); return -EADDRNOTAVAIL; } diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f05f584..186d75a 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -362,7 +362,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_channel *curchan = hw->conf.channel; struct ath_vap *avp; int pos; - DECLARE_MAC_BUF(mac); if (bss_conf->assoc) { DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", @@ -397,9 +396,9 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_update_chainmask(sc, bss_conf->assoc_ht); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", + "%s: bssid %pM aid 0x%x\n", __func__, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + sc->sc_curbssid, sc->sc_curaid); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", __func__, @@ -1278,7 +1277,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, struct ath_vap *avp; u32 rfilt = 0; int error, i; - DECLARE_MAC_BUF(mac); avp = sc->sc_vaps[0]; if (avp == NULL) { @@ -1333,9 +1331,9 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", + "%s: RX filter 0x%x bssid %pM aid 0x%x\n", __func__, rfilt, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + sc->sc_curbssid, sc->sc_curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -1424,7 +1422,6 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an; unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&sc->node_lock, flags); an = ath_node_find(sc, sta->addr); @@ -1435,8 +1432,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, spin_lock_irqsave(&sc->node_lock, flags); if (!an) { ath_node_attach(sc, sta->addr, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, print_mac(mac, sta->addr)); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %pM\n", + __func__, sta->addr); } else { ath_node_get(sc, sta->addr); } @@ -1449,9 +1446,9 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, __func__); else { ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %pM\n", __func__, - print_mac(mac, sta->addr)); + sta->addr); } break; default: diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index cca2fc5..b1e535b 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1942,7 +1942,6 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, s8 lowest_idx; __le16 fc = hdr->frame_control; u8 *qc, tid; - DECLARE_MAC_BUF(mac); DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); @@ -2003,14 +2002,14 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, if (ret) DPRINTF(sc, ATH_DBG_AGGR, "%s: Unable to start tx " - "aggr for: %s\n", + "aggr for: %pM\n", __func__, - print_mac(mac, hdr->addr1)); + hdr->addr1); else DPRINTF(sc, ATH_DBG_AGGR, - "%s: Started tx aggr for: %s\n", + "%s: Started tx aggr for: %pM\n", __func__, - print_mac(mac, hdr->addr1)); + hdr->addr1); } else if (chk == AGGR_EXCHANGE_PROGRESS) ath_tx_aggr_resp(sc, sband, sta, an, tid); } diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3a47579..1386604 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2416,7 +2416,6 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, u8 tidno) { struct ath_atx_tid *txtid; - DECLARE_MAC_BUF(mac); if (!(sc->sc_flags & SC_OP_TXAGGR)) return AGGR_NOT_REQUIRED; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index ecb02bd..6e20552 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1479,7 +1479,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, struct net_device *dev; struct atmel_private *priv; int rc; - DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_etherdev(sizeof(*priv)); @@ -1591,8 +1590,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, if (!ent) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); return dev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 14c44df..6e77301 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3445,7 +3445,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; - DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ @@ -3533,9 +3532,9 @@ out_unlock: mutex_unlock(&wl->mutex); if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " - "mac: %s\n", + "mac: %pM\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - print_mac(mac, addr)); + addr); } return err; } diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index f106bc1..bbb8ec6 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -19,7 +19,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; u16 fc; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -45,11 +44,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); - printk(" A2=%s", print_mac(mac, hdr->addr2)); - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(KERN_DEBUG " A1=%pM", hdr->addr1); + printk(" A2=%pM", hdr->addr2); + printk(" A3=%pM", hdr->addr3); if (skb->len >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } @@ -557,7 +556,6 @@ static int hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { - DECLARE_MAC_BUF(mac); /* FIX: is this really supposed to accept WDS frames only in Master * mode? What about Repeater or Managed with WDS frames? */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != @@ -573,10 +571,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { /* RA (or BSSID) is not ours - drop */ PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " - "not own or broadcast %s=%s\n", + "not own or broadcast %s=%pM\n", local->dev->name, fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - print_mac(mac, hdr->addr1)); + hdr->addr1); return -1; } @@ -589,8 +587,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, /* require that WDS link has been registered with TA or the * frame is from current AP when using 'AP client mode' */ PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=%s\n", - local->dev->name, print_mac(mac, hdr->addr2)); + "from unknown TA=%pM\n", + local->dev->name, hdr->addr2); if (local->ap && local->ap->autom_ap_wds) hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); return -1; @@ -667,10 +665,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, strcmp(crypt->ops->name, "TKIP") == 0) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from " MAC_FMT "\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "received packet from %pM\n", + local->dev->name, hdr->addr2); } return -1; } @@ -679,12 +675,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=" MAC_FMT - ") res=%d\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - res); + printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", + local->dev->name, hdr->addr2, res); local->comm_tallies.rx_discards_wep_undecryptable++; return -1; } @@ -700,7 +692,6 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; - DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -713,8 +704,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=%s keyidx=%d)\n", - local->dev->name, print_mac(mac, hdr->addr2), keyidx); + " (SA=%pM keyidx=%d)\n", + local->dev->name, hdr->addr2, keyidx); return -1; } @@ -822,10 +813,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + " (SA=%pM)\n", + local->dev->name, hdr->addr2); #endif local->comm_tallies.rx_discards_wep_undecryptable++; goto rx_dropped; @@ -839,9 +828,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "from %pM\n", dev->name, hdr->addr2); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -1009,10 +996,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, "unencrypted EAPOL frame\n", local->dev->name); } else { printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=" MAC_FMT ")\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "frame not encrypted (SA=%pM)\n", + local->dev->name, hdr->addr2); goto rx_dropped; } } @@ -1021,10 +1006,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, !hostap_is_eapol_frame(local, skb)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from " MAC_FMT " (drop_unencrypted=1)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "frame from %pM (drop_unencrypted=1)\n", + dev->name, hdr->addr2); } goto rx_dropped; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 921c984..0752471 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -17,7 +17,6 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { struct ieee80211_hdr_4addr *hdr; u16 fc; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -41,11 +40,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); - printk(" A2=%s", print_mac(mac, hdr->addr2)); - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(KERN_DEBUG " A1=%pM", hdr->addr1); + printk(" A2=%pM", hdr->addr2); + printk(" A3=%pM", hdr->addr3); if (skb->len >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } @@ -328,10 +327,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + "TX packet to %pM\n", + local->dev->name, hdr->addr1); } kfree_skb(skb); return NULL; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index af3d4ef..dec3dbe 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -94,7 +94,6 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) { struct sta_info *s; - DECLARE_MAC_BUF(mac); s = ap->sta_hash[STA_HASH(sta->addr)]; if (s == NULL) return; @@ -109,20 +108,18 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) if (s->hnext != NULL) s->hnext = s->hnext->hnext; else - printk("AP: could not remove STA %s" - " from hash table\n", - print_mac(mac, sta->addr)); + printk("AP: could not remove STA %pM from hash table\n", + sta->addr); } static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) { - DECLARE_MAC_BUF(mac); if (sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); if (ap->proc != NULL) { char name[20]; - sprintf(name, "%s", print_mac(mac, sta->addr)); + sprintf(name, "%pM", sta->addr); remove_proc_entry(name, ap->proc); } @@ -185,7 +182,6 @@ static void ap_handle_timer(unsigned long data) struct ap_data *ap; unsigned long next_time = 0; int was_assoc; - DECLARE_MAC_BUF(mac); if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); @@ -242,8 +238,8 @@ static void ap_handle_timer(unsigned long data) if (sta->ap) { if (ap->autom_ap_wds) { PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP %s\n", - local->dev->name, print_mac(mac, sta->addr)); + "connection to AP %pM\n", + local->dev->name, sta->addr); hostap_wds_link_oper(local, sta->addr, WDS_DEL); } } else if (sta->timeout_next == STA_NULLFUNC) { @@ -259,11 +255,11 @@ static void ap_handle_timer(unsigned long data) } else { int deauth = sta->timeout_next == STA_DEAUTH; __le16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s" + PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" "(last=%lu, jiffies=%lu)\n", local->dev->name, deauth ? "deauthentication" : "disassociation", - print_mac(mac, sta->addr), sta->last_rx, jiffies); + sta->addr, sta->last_rx, jiffies); resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); @@ -275,10 +271,10 @@ static void ap_handle_timer(unsigned long data) if (sta->timeout_next == STA_DEAUTH) { if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA %s" + PDEBUG(DEBUG_AP, "%s: STA %pM" " would have been removed, " "but it has 'perm' flag\n", - local->dev->name, print_mac(mac, sta->addr)); + local->dev->name, sta->addr); } else ap_free_sta(ap, sta); return; @@ -332,7 +328,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; char *policy_txt; struct mac_entry *entry; - DECLARE_MAC_BUF(mac); if (off != 0) { *eof = 1; @@ -363,7 +358,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, break; } - p += sprintf(p, "%s\n", print_mac(mac, entry->addr)); + p += sprintf(p, "%pM\n", entry->addr); } spin_unlock_bh(&ap->mac_restrictions.lock); @@ -520,7 +515,6 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; struct sta_info *sta; int i; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -533,8 +527,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, if (!sta->ap) continue; - p += sprintf(p, "%s %d %d %d %d '", - print_mac(mac, sta->addr), + p += sprintf(p, "%pM %d %d %d %d '", + sta->addr, sta->u.ap.channel, sta->last_rx_signal, sta->last_rx_silence, sta->last_rx_rate); for (i = 0; i < sta->u.ap.ssid_len; i++) @@ -683,11 +677,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth_cb - alg=%d " + PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " "trans#=%d status=%d - %s\n", - dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], + dev->name, hdr->addr1, auth_alg, auth_transaction, status, txt); } dev_kfree_skb(skb); @@ -754,11 +746,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " assoc_cb - %s\n", - dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - txt); + PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", + dev->name, hdr->addr1, txt); } dev_kfree_skb(skb); } @@ -781,11 +770,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) sta->flags &= ~WLAN_STA_PENDING_POLL; spin_unlock(&ap->sta_table_lock); } else { - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " did not ACK activity poll frame\n", - ap->local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, + "%s: STA %pM did not ACK activity poll frame\n", + ap->local->dev->name, hdr->addr1); } fail: @@ -1002,7 +989,6 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, char *p = page; struct sta_info *sta = (struct sta_info *) data; int i; - DECLARE_MAC_BUF(mac); /* FIX: possible race condition.. the STA data could have just expired, * but proc entry was still here so that the read could have started; @@ -1013,11 +999,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n" + p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n" "flags=0x%04x%s%s%s%s%s%s%s\n" "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", sta->ap ? "AP" : "STA", - print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid, + sta->addr, atomic_read(&sta->users), sta->aid, sta->flags, sta->flags & WLAN_STA_AUTH ? " AUTH" : "", sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", @@ -1078,7 +1064,6 @@ static void handle_add_proc_queue(struct work_struct *work) struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; - DECLARE_MAC_BUF(mac); entry = ap->add_sta_proc_entries; ap->add_sta_proc_entries = NULL; @@ -1091,7 +1076,7 @@ static void handle_add_proc_queue(struct work_struct *work) spin_unlock_bh(&ap->sta_table_lock); if (sta) { - sprintf(name, "%s", print_mac(mac, sta->addr)); + sprintf(name, "%pM", sta->addr); sta->proc = create_proc_read_entry( name, 0, ap->proc, prism2_sta_proc_read, sta); @@ -1318,9 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (len < 6) { PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from " MAC_FMT "\n", dev->name, len, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "(len=%d) from %pM\n", dev->name, len, hdr->addr2); return; } @@ -1385,10 +1368,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (time_after(jiffies, sta->u.ap.last_beacon + (10 * sta->listen_interval * HZ) / 1024)) { PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP " MAC_FMT " is now STA\n", - dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + " assuming AP %pM is now STA\n", + dev->name, sta->addr); sta->ap = 0; sta->flags = 0; sta->u.sta.challenge = NULL; @@ -1503,11 +1484,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, } if (resp) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth (alg=%d " + PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + dev->name, hdr->addr2, auth_alg, auth_transaction, status_code, len, fc, resp, txt); } @@ -1533,10 +1512,8 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, if (len < (reassoc ? 10 : 4)) { PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from " MAC_FMT "\n", - dev->name, len, reassoc, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "(len=%d, reassoc=%d) from %pM\n", + dev->name, len, reassoc, hdr->addr2); return; } @@ -1613,12 +1590,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from " MAC_FMT + PDEBUG(DEBUG_AP, "%s: assoc from %pM" " with extra data (%d bytes) [", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - left); + dev->name, hdr->addr2, left); while (left > 0) { PDEBUG2(DEBUG_AP, "<%02x>", *u); u++; left--; @@ -1717,14 +1691,12 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } #if 0 - PDEBUG(DEBUG_AP, "%s: " MAC_FMT" %sassoc (len=%d " - "prev_ap=" MAC_FMT") => %d(%d) (%s)\n", + PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " + "prev_ap=%pM) => %d(%d) (%s)\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + hdr->addr2, reassoc ? "re" : "", len, - prev_ap[0], prev_ap[1], prev_ap[2], - prev_ap[3], prev_ap[4], prev_ap[5], + prev_ap, resp, send_deauth, txt); #endif } @@ -1741,7 +1713,6 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, u16 reason_code; __le16 *pos; struct sta_info *sta = NULL; - DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1753,10 +1724,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, pos = (__le16 *) body; reason_code = le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: deauthentication: " MAC_FMT " len=%d, " - "reason_code=%d\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " + "reason_code=%d\n", dev->name, hdr->addr2, len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1768,11 +1737,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: deauthentication from " MAC_FMT ", " + printk("%s: deauthentication from %pM, " "reason_code=%d, but STA not authenticated\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - reason_code); + hdr->addr2, reason_code); } } @@ -1799,10 +1766,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, pos = (__le16 *) body; reason_code = le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: disassociation: " MAC_FMT " len=%d, " - "reason_code=%d\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " + "reason_code=%d\n", dev->name, hdr->addr2, len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1814,12 +1779,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: disassociation from " MAC_FMT ", " + printk("%s: disassociation from %pM, " "reason_code=%d, but STA not authenticated\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - reason_code); + dev->name, hdr->addr2, reason_code); } } @@ -1909,19 +1871,14 @@ static void handle_pspoll(local_info_t *local, u16 aid; struct sk_buff *skb; - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MAC_FMT - ", TA=" MAC_FMT " PWRMGT=%d\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", + hdr->addr1, hdr->addr2, !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MAC_FMT - " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, + "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", + hdr->addr1); return; } @@ -2007,11 +1964,10 @@ static void handle_wds_oper_queue(struct work_struct *work) while (entry) { PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP " MAC_FMT "\n", + "to AP %pM\n", local->dev->name, entry->type == WDS_ADD ? "adding" : "removing", - entry->addr[0], entry->addr[1], entry->addr[2], - entry->addr[3], entry->addr[4], entry->addr[5]); + entry->addr); if (entry->type == WDS_ADD) prism2_wds_add(local, entry->addr, 0); else if (entry->type == WDS_DEL) @@ -2215,10 +2171,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" - MAC_FMT " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" + " not own MAC\n", hdr->addr1); goto done; } @@ -2254,18 +2208,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MAC_FMT - " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" + " not own MAC\n", hdr->addr1); goto done; } if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MAC_FMT - " not own MAC\n", - hdr->addr3[0], hdr->addr3[1], hdr->addr3[2], - hdr->addr3[3], hdr->addr3[4], hdr->addr3[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" + " not own MAC\n", hdr->addr3); goto done; } @@ -2366,10 +2316,9 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) memcpy(hdr->addr2, sta->addr, ETH_ALEN); hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA " - MAC_FMT "\n", local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + PDEBUG(DEBUG_PS2, + "%s: Scheduling buffered packet delivery for STA %pM\n", + local->dev->name, sta->addr); skb->dev = local->dev; @@ -2723,12 +2672,8 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " TX rate raised to %d\n", - dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5], - sta->tx_rate); + PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", + dev->name, sta->addr, sta->tx_rate); } sta->tx_since_last_failure = 0; } @@ -2781,9 +2726,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) * print out any errors here. */ if (net_ratelimit()) { printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA " MAC_FMT "\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + "STA %pM\n", hdr->addr1); } #endif local->ap->tx_drop_nonassoc++; @@ -2821,11 +2764,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) } if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (" MAC_FMT - ")'s PS mode buffer\n", - local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" + "PS mode buffer\n", + local->dev->name, sta->addr); /* Make sure that TIM is set for the station (it might not be * after AP wlan hw reset). */ /* FIX: should fix hw reset to restore bits based on STA @@ -2897,12 +2838,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) sta = ap_get_sta(local->ap, hdr->addr1); if (!sta) { spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA " MAC_FMT + PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" " for this TX error (@%lu)\n", - local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - jiffies); + local->dev->name, hdr->addr1, jiffies); return; } @@ -2929,12 +2867,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " TX rate lowered to %d\n", - local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5], - sta->tx_rate); + PDEBUG(DEBUG_AP, + "%s: STA %pM TX rate lowered to %d\n", + local->dev->name, sta->addr, sta->tx_rate); } sta->tx_consecutive_exc = 0; } @@ -2945,17 +2880,16 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, int pwrmgt, int type, int stype) { - DECLARE_MAC_BUF(mac); if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %s changed to use PS " + PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " "mode (type=0x%02X, stype=0x%02X)\n", - print_mac(mac, sta->addr), type >> 2, stype >> 4); + sta->addr, type >> 2, stype >> 4); } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %s changed to not use " + PDEBUG(DEBUG_PS2, "STA %pM changed to not use " "PS mode (type=0x%02X, stype=0x%02X)\n", - print_mac(mac, sta->addr), type >> 2, stype >> 4); + sta->addr, type >> 2, stype >> 4); if (type != IEEE80211_FTYPE_CTL || stype != IEEE80211_STYPE_PSPOLL) schedule_packet_send(local, sta); @@ -3029,13 +2963,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT } else { printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA " - MAC_FMT + " from non-associated STA %pM" " (type=0x%02x, subtype=0x%02x)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], + dev->name, hdr->addr2, type >> 2, stype >> 4); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -3068,13 +2998,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * after being unavailable for some time. Speed up * re-association by informing the station about it not * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc " - "frame without ToDS from not associated STA " - MAC_FMT "\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + printk(KERN_DEBUG "%s: rejected received nullfunc frame" + " without ToDS from not associated STA %pM\n", + dev->name, hdr->addr2); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ } @@ -3090,13 +3016,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * broadcast frame from an IBSS network. Drop it silently. * If BSSID is own, report the dropping of this frame. */ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { - printk(KERN_DEBUG "%s: dropped received packet from " - MAC_FMT " with no ToDS flag " + printk(KERN_DEBUG "%s: dropped received packet from %pM" + " with no ToDS flag " "(type=0x%02x, subtype=0x%02x)\n", dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], - type >> 2, stype >> 4); + hdr->addr2, type >> 2, stype >> 4); hostap_dump_rx_80211(dev->name, skb, rx_stats); } ret = AP_RX_DROP; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 3153fe9..fd7f7ce 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2335,10 +2335,6 @@ static void prism2_txexc(local_info_t *local) int show_dump, res; char *payload = NULL; struct hfa384x_tx_frame txdesc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; local->stats.tx_errors++; @@ -2404,9 +2400,9 @@ static void prism2_txexc(local_info_t *local) WLAN_FC_GET_STYPE(fc) >> 4, fc & IEEE80211_FCTL_TODS ? " ToDS" : "", fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2), - print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4)); + PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", + txdesc.addr1, txdesc.addr2, + txdesc.addr3, txdesc.addr4); } diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 7cd3fb7..99b4cf4 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -166,7 +166,6 @@ static void prism2_host_roaming(local_info_t *local) struct hfa384x_hostscan_result *selected, *entry; int i; unsigned long flags; - DECLARE_MAC_BUF(mac); if (local->last_join_time && time_before(jiffies, local->last_join_time + 10 * HZ)) { @@ -199,9 +198,8 @@ static void prism2_host_roaming(local_info_t *local) local->preferred_ap[2] || local->preferred_ap[3] || local->preferred_ap[4] || local->preferred_ap[5]) { /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " - "%s\n", - dev->name, print_mac(mac, local->preferred_ap)); + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n", + dev->name, local->preferred_ap); for (i = 0; i < local->last_scan_results_count; i++) { entry = &local->last_scan_results[i]; if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) @@ -218,9 +216,9 @@ static void prism2_host_roaming(local_info_t *local) req.channel = selected->chid; spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s" + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM" " channel=%d\n", - dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel)); + dev->name, req.bssid, le16_to_cpu(req.channel)); if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); @@ -413,7 +411,6 @@ static void handle_info_queue_linkstatus(local_info_t *local) int val = local->prev_link_status; int connected; union iwreq_data wrqu; - DECLARE_MAC_BUF(mac); connected = val == HFA384X_LINKSTATUS_CONNECTED || @@ -425,10 +422,9 @@ static void handle_info_queue_linkstatus(local_info_t *local) printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " "LinkStatus event\n", local->dev->name); } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" - "%s\n", + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n", local->dev->name, - print_mac(mac, (unsigned char *) local->bssid)); + (unsigned char *) local->bssid); if (local->wds_type & HOSTAP_WDS_AP_CLIENT) hostap_add_sta(local->ap, local->bssid); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 3f8b1d7..2318c5d 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -664,7 +664,6 @@ static int hostap_join_ap(struct net_device *dev) unsigned long flags; int i; struct hfa384x_hostscan_result *entry; - DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -686,14 +685,13 @@ static int hostap_join_ap(struct net_device *dev) if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest %s" - " failed\n", - dev->name, print_mac(mac, local->preferred_ap)); + printk(KERN_DEBUG "%s: JoinRequest %pM failed\n", + dev->name, local->preferred_ap); return -1; } - printk(KERN_DEBUG "%s: Trying to join BSSID %s\n", - dev->name, print_mac(mac, local->preferred_ap)); + printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n", + dev->name, local->preferred_ap); return 0; } @@ -3701,10 +3699,8 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%ssta: associated as client with AP " - "%s\n", - local->dev->name, print_mac(mac, param->sta_addr)); + printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n", + local->dev->name, param->sta_addr); memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); return 0; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 756ab56..4c36eb2 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -530,10 +530,6 @@ int hostap_set_auth_algs(local_info_t *local) void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) { u16 status, fc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); status = __le16_to_cpu(rx->status); @@ -552,12 +548,11 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2), - print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4)); + printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", + rx->addr1, rx->addr2, rx->addr3, rx->addr4); - printk(KERN_DEBUG " dst=%s src=%s len=%d\n", - print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr), + printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", + rx->dst_addr, rx->src_addr, __be16_to_cpu(rx->len)); } @@ -565,10 +560,6 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) { u16 fc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " "tx_control=0x%04x; jiffies=%ld\n", @@ -584,12 +575,11 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2), - print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4)); + printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", + tx->addr1, tx->addr2, tx->addr3, tx->addr4); - printk(KERN_DEBUG " dst=%s src=%s len=%d\n", - print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr), + printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", + tx->dst_addr, tx->src_addr, __be16_to_cpu(tx->len)); } diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index b035360..ae7d3ca 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -106,7 +106,6 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, local_info_t *local = (local_info_t *) data; struct list_head *ptr; struct hostap_interface *iface; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -118,9 +117,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; - p += sprintf(p, "%s\t%s\n", + p += sprintf(p, "%s\t%pM\n", iface->dev->name, - print_mac(mac, iface->u.wds.remote_addr)); + iface->u.wds.remote_addr); if ((p - page) > PROC_LIMIT) { printk(KERN_DEBUG "%s: wds proc did not fit\n", local->dev->name); @@ -148,7 +147,6 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, struct list_head *ptr; struct hostap_bss_info *bss; int i; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -160,8 +158,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, spin_lock_bh(&local->lock); list_for_each(ptr, &local->bss_list) { bss = list_entry(ptr, struct hostap_bss_info, list); - p += sprintf(p, "%s\t%lu\t%u\t0x%x\t", - print_mac(mac, bss->bssid), bss->last_update, + p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t", + bss->bssid, bss->last_update, bss->count, bss->capab_info); for (i = 0; i < bss->ssid_len; i++) { p += sprintf(p, "%c", @@ -314,7 +312,6 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, int entry, i, len, total = 0; struct hfa384x_hostscan_result *scanres; u8 *pos; - DECLARE_MAC_BUF(mac); p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " "SSID\n"); @@ -332,14 +329,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, if ((p - page) > (PAGE_SIZE - 200)) break; - p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ", + p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ", le16_to_cpu(scanres->chid), (s16) le16_to_cpu(scanres->anl), (s16) le16_to_cpu(scanres->sl), le16_to_cpu(scanres->beacon_interval), le16_to_cpu(scanres->capability), le16_to_cpu(scanres->rate), - print_mac(mac, scanres->bssid), + scanres->bssid, le16_to_cpu(scanres->atim)); pos = scanres->sup_rates; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index bca7481..6e988d2 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1914,7 +1914,6 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; - DECLARE_MAC_BUF(mac); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1975,10 +1974,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) break; } - IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" - "%s)\n", + IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", priv->net_dev->name, escape_essid(essid, essid_len), - txratename, chan, print_mac(mac, bssid)); + txratename, chan, bssid); /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { @@ -2046,12 +2044,10 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { - DECLARE_MAC_BUF(mac); - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s \n", + "disassociated: '%s' %pM \n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -4058,7 +4054,6 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, char *out = buf; int length; int ret; - DECLARE_MAC_BUF(mac); if (priv->status & STATUS_RF_KILL_MASK) return 0; @@ -4086,7 +4081,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, __LINE__); out += sprintf(out, "ESSID: %s\n", essid); - out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid)); + out += sprintf(out, "BSSID: %pM\n", bssid); out += sprintf(out, "Channel: %d\n", chan); return out - buf; @@ -4662,7 +4657,6 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) { u32 length = ETH_ALEN; u8 addr[ETH_ALEN]; - DECLARE_MAC_BUF(mac); int err; @@ -4673,8 +4667,7 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) } memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); - IPW_DEBUG_INFO("card MAC is %s\n", - print_mac(mac, priv->net_dev->dev_addr)); + IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr); return 0; } @@ -5053,10 +5046,8 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, int err; #ifdef CONFIG_IPW2100_DEBUG - DECLARE_MAC_BUF(mac); if (bssid != NULL) - IPW_DEBUG_HC("MANDATORY_BSSID: %s\n", - print_mac(mac, bssid)); + IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid); else IPW_DEBUG_HC("MANDATORY_BSSID: \n"); #endif @@ -6905,7 +6896,6 @@ static int ipw2100_wx_set_wap(struct net_device *dev, static const unsigned char off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - DECLARE_MAC_BUF(mac); // sanity checks if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) @@ -6931,8 +6921,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); - IPW_DEBUG_WX("SET BSSID -> %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data); done: mutex_unlock(&priv->action_mutex); @@ -6948,7 +6937,6 @@ static int ipw2100_wx_get_wap(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6958,8 +6946,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data); return 0; } diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index dcce3542..d0bfd86 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2265,8 +2265,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) return -1; } - IPW_DEBUG_INFO("%s: Setting MAC to %s\n", - priv->net_dev->name, print_mac(mac, mac)); + IPW_DEBUG_INFO("%s: Setting MAC to %pM\n", + priv->net_dev->name, mac); return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } @@ -3812,7 +3812,6 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) { struct ipw_station_entry entry; int i; - DECLARE_MAC_BUF(mac); for (i = 0; i < priv->num_stations; i++) { if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { @@ -3829,7 +3828,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) if (i == MAX_STATIONS) return IPW_INVALID_STATION; - IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid)); + IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid); entry.reserved = 0; entry.support_mode = 0; @@ -3856,7 +3855,6 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) { int err; - DECLARE_MAC_BUF(mac); if (priv->status & STATUS_ASSOCIATING) { IPW_DEBUG_ASSOC("Disassociating while associating.\n"); @@ -3869,9 +3867,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } - IPW_DEBUG_ASSOC("Disassocation attempt from %s " + IPW_DEBUG_ASSOC("Disassocation attempt from %pM " "on channel %d.\n", - print_mac(mac, priv->assoc_request.bssid), + priv->assoc_request.bssid, priv->assoc_request.channel); priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); @@ -4397,7 +4395,6 @@ static void handle_scan_event(struct ipw_priv *priv) static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { - DECLARE_MAC_BUF(mac); u16 size = le16_to_cpu(notif->size); notif->size = le16_to_cpu(notif->size); @@ -4411,11 +4408,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_ASSOCIATED:{ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "associated: '%s' %s" - " \n", + "associated: '%s' %pM \n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); switch (priv->ieee->iw_mode) { case IW_MODE_INFRA: @@ -4492,13 +4488,13 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' " - "%s" + "%pM" ": (0x%04X) - %s \n", escape_essid(priv-> essid, priv-> essid_len), - print_mac(mac, priv->bssid), + priv->bssid, le16_to_cpu(auth->status), ipw_get_status_code (le16_to_cpu @@ -4515,11 +4511,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "authenticated: '%s' %s" - "\n", + "authenticated: '%s' %pM\n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); break; } @@ -4544,11 +4539,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s" - " \n", + "disassociated: '%s' %pM \n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); priv->status &= ~(STATUS_DISASSOCIATING | @@ -4583,10 +4577,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, switch (auth->state) { case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "authenticated: '%s' %s \n", + "authenticated: '%s' %pM \n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); priv->status |= STATUS_AUTH; break; @@ -4602,10 +4596,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "deauthenticated: '%s' %s\n", + "deauthenticated: '%s' %pM\n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); priv->status &= ~(STATUS_ASSOCIATING | STATUS_AUTH | @@ -5429,27 +5423,25 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ if ((priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " "capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } /* If we do not have an ESSID for this AP, we can not associate with * it */ if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of hidden ESSID.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } @@ -5459,11 +5451,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } } else { @@ -5478,9 +5470,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, print_mac(mac, network->bssid), + escaped, network->bssid, escape_essid(priv->essid, priv->essid_len)); return 0; @@ -5507,10 +5499,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5518,10 +5510,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, network->channel, priv->channel); return 0; } @@ -5529,10 +5521,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, priv-> capability & CAP_PRIVACY_ON ? "on" : "off", network-> @@ -5542,41 +5534,41 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " - "because of the same BSSID match: %s" + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of the same BSSID match: %pM" ".\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), - print_mac(mac2, priv->bssid)); + network->bssid, + priv->bssid); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of no compatible rates.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } @@ -5587,9 +5579,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Set up 'new' AP to this network */ ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n", + IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 1; } @@ -5643,7 +5635,6 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5651,20 +5642,20 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_ESS)) || (priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " "capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } /* If we do not have an ESSID for this AP, we can not associate with * it */ if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of hidden ESSID.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } @@ -5674,11 +5665,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } } else { @@ -5692,9 +5683,9 @@ static int ipw_best_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, print_mac(mac, network->bssid), + escaped, network->bssid, escape_essid(priv->essid, priv->essid_len)); return 0; @@ -5708,12 +5699,12 @@ static int ipw_best_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because " - "'%s (%s)' has a stronger signal.\n", - escaped, print_mac(mac, network->bssid), + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " + "'%s (%pM)' has a stronger signal.\n", + escaped, network->bssid, escape_essid(match->network->ssid, match->network->ssid_len), - print_mac(mac, match->network->bssid)); + match->network->bssid); return 0; } @@ -5721,11 +5712,11 @@ static int ipw_best_network(struct ipw_priv *priv, * last 3 seconds, do not try and associate again... */ if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of storming (%ums since last " "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, jiffies_to_msecs(jiffies - network->last_associate)); return 0; @@ -5734,10 +5725,10 @@ static int ipw_best_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5745,10 +5736,10 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, network->channel, priv->channel); return 0; } @@ -5756,10 +5747,10 @@ static int ipw_best_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + network->bssid, priv->capability & CAP_PRIVACY_ON ? "on" : "off", network->capability & @@ -5769,48 +5760,48 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " - "because of BSSID mismatch: %s.\n", + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of BSSID mismatch: %pM.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), print_mac(mac, priv->bssid)); + network->bssid, priv->bssid); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } /* Filter out invalid channel in current GEO */ if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of no compatible rates.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 0; } @@ -5822,9 +5813,9 @@ static int ipw_best_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n", + IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + network->bssid); return 1; } @@ -6066,7 +6057,6 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { - DECLARE_MAC_BUF(mac); IPW_DEBUG_INFO("Scan completed, no valid APs matched " "[CFG 0x%08X]\n", priv->config); if (priv->config & CFG_STATIC_CHANNEL) @@ -6079,8 +6069,7 @@ static void ipw_debug_config(struct ipw_priv *priv) else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to %s\n", - print_mac(mac, priv->bssid)); + IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid); else IPW_DEBUG_INFO("BSSID unlocked.\n"); if (priv->capability & CAP_PRIVACY_ON) @@ -7295,7 +7284,6 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; - DECLARE_MAC_BUF(mac); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7463,9 +7451,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n", + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + priv->bssid); return 0; } @@ -7604,7 +7592,6 @@ static int ipw_associate(void *data) if (list_empty(&priv->ieee->network_free_list)) { struct ieee80211_network *oldest = NULL; struct ieee80211_network *target; - DECLARE_MAC_BUF(mac); list_for_each_entry(target, &priv->ieee->network_list, list) { if ((oldest == NULL) || @@ -7615,11 +7602,11 @@ static int ipw_associate(void *data) /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IPW_DEBUG_ASSOC("Expired '%s' (%s) from " + IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " "network list.\n", escape_essid(target->ssid, target->ssid_len), - print_mac(mac, target->bssid)); + target->bssid); list_add_tail(&target->list, &priv->ieee->network_free_list); } @@ -8301,9 +8288,6 @@ static void ipw_rx(struct ipw_priv *priv) u32 r, w, i; u8 network_packet; u8 fill_rx = 0; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); r = ipw_read32(priv, IPW_RX_READ_INDEX); w = ipw_read32(priv, IPW_RX_WRITE_INDEX); @@ -8433,18 +8417,12 @@ static void ipw_rx(struct ipw_priv *priv) header))) { IPW_DEBUG_DROP("Dropping: " - "%s, " - "%s, " - "%s\n", - print_mac(mac, - header-> - addr1), - print_mac(mac2, - header-> - addr2), - print_mac(mac3, - header-> - addr3)); + "%pM, " + "%pM, " + "%pM\n", + header->addr1, + header->addr2, + header->addr3); break; } @@ -8983,7 +8961,6 @@ static int ipw_wx_set_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -9014,8 +8991,8 @@ static int ipw_wx_set_wap(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting mandatory BSSID to %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n", + wrqu->ap_addr.sa_data); memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); @@ -9033,7 +9010,6 @@ static int ipw_wx_get_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -9045,8 +9021,8 @@ static int ipw_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", + wrqu->ap_addr.sa_data); mutex_unlock(&priv->mutex); return 0; } @@ -10199,10 +10175,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, id = ipw_add_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { IPW_WARNING("Attempt to send data to " - "invalid cell: " MAC_FMT "\n", - hdr->addr1[0], hdr->addr1[1], - hdr->addr1[2], hdr->addr1[3], - hdr->addr1[4], hdr->addr1[5]); + "invalid cell: %pM\n", + hdr->addr1); goto drop; } } @@ -10505,15 +10479,14 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) { struct ipw_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = p; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - printk(KERN_INFO "%s: Setting MAC to %s\n", - priv->net_dev->name, print_mac(mac, priv->mac_addr)); + printk(KERN_INFO "%s: Setting MAC to %pM\n", + priv->net_dev->name, priv->mac_addr); queue_work(priv->workqueue, &priv->adapter_restart); mutex_unlock(&priv->mutex); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 6fc5e73..bb91353 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -649,7 +649,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc, rate_mask; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; - DECLARE_MAC_BUF(mac); IWL_DEBUG_RATE("enter\n"); @@ -675,8 +674,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %pm\n", + hdr->addr1); sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7ca5627..8a00245 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -759,7 +759,6 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) int i; int ret = IWL_INVALID_STATION; unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) @@ -770,8 +769,8 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_INFO("can not find STA %s (total %d)\n", - print_mac(mac, addr), priv->num_stations); + IWL_DEBUG_INFO("can not find STA %pM (total %d)\n", + addr, priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e2a58e4..b497d40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -357,11 +357,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { - DECLARE_MAC_BUF(mac); - if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { - IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", - print_mac(mac, sta->addr), tid); + IWL_DEBUG_HT("Starting Tx agg: STA: %pM tid: %d\n", + sta->addr, tid); ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); } } @@ -2132,11 +2130,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { u8 sta_id = iwl_find_station(priv, hdr->addr1); - DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", + hdr->addr1); sta_id = iwl_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } @@ -2205,15 +2202,12 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { u8 sta_id = iwl_find_station(priv, sta->addr); - DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 24a1aeb..2af9a14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -239,7 +239,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - DECLARE_MAC_BUF(mac); int ret; bool new_assoc = !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); @@ -300,10 +299,10 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = %s\n", + "* bssid = %pM\n", (new_assoc ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); + priv->staging_rxon.bssid_addr); iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); @@ -1464,7 +1463,6 @@ void iwl_rx_handle(struct iwl_priv *priv) static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); @@ -1476,10 +1474,8 @@ static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -2466,7 +2462,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) { struct ieee80211_conf *conf = NULL; int ret = 0; - DECLARE_MAC_BUF(mac); unsigned long flags; if (priv->iw_mode == NL80211_IFTYPE_AP) { @@ -2474,9 +2469,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv) return; } - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -2722,7 +2716,6 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -2739,7 +2732,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); + IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } @@ -2948,7 +2941,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -2983,8 +2975,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); /* * very dubious code was here; the probe filtering flag is never set: @@ -2997,8 +2988,8 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %pM\n", + conf->bssid); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -3241,14 +3232,13 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, unsigned long flags; __le16 key_flags = 0; int i; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter\n"); sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return; } @@ -3285,7 +3275,6 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; u8 sta_id = IWL_INVALID_STATION; u8 is_default_wep_key = 0; @@ -3303,8 +3292,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return -EINVAL; } @@ -3405,10 +3394,9 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", - print_mac(mac, sta->addr), tid); + IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n", + sta->addr, tid); if (!(priv->cfg->sku & IWL_SKU_N)) return -EACCES; @@ -4171,7 +4159,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e struct ieee80211_hw *hw; struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; - DECLARE_MAC_BUF(mac); /************************ * 1. Allocating HW data @@ -4280,7 +4267,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); /************************ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 20db0eb..753f938 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -228,7 +228,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, ssize_t ret; /* Add 30 for initial string */ const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations); - DECLARE_MAC_BUF(mac); buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) @@ -242,7 +241,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, if (station->used) { pos += scnprintf(buf + pos, bufsz - pos, "station %d:\ngeneral data:\n", i+1); - print_mac(mac, station->sta.sta.addr); pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n", station->sta.sta.sta_id); pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 61797f3..e02c471 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -45,7 +45,6 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) int start = 0; int ret = IWL_INVALID_STATION; unsigned long flags; - DECLARE_MAC_BUF(mac); if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || (priv->iw_mode == NL80211_IFTYPE_AP)) @@ -63,8 +62,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", - print_mac(mac, addr), priv->num_stations); + IWL_DEBUG_ASSOC_LIMIT("can not find STA %pM total %d\n", + addr, priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -86,7 +85,6 @@ EXPORT_SYMBOL(iwl_get_ra_sta_id); static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); @@ -94,8 +92,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id); priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; - IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n", - print_mac(mac, priv->stations[sta_id].sta.sta.addr)); + IWL_DEBUG_ASSOC("Added STA to Ucode: %pM\n", + priv->stations[sta_id].sta.sta.addr); spin_unlock_irqrestore(&priv->sta_lock, flags); } @@ -237,7 +235,6 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -273,8 +270,8 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, station = &priv->stations[sta_id]; station->used = IWL_STA_DRIVER_ACTIVE; - IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n", - sta_id, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Add STA to driver ID %d: %pM\n", + sta_id, addr); priv->num_stations++; /* Set up the REPLY_ADD_STA command to send to device */ @@ -301,14 +298,11 @@ EXPORT_SYMBOL(iwl_add_station_flags); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - DECLARE_MAC_BUF(mac); - u8 sta_id = iwl_find_station(priv, addr); BUG_ON(sta_id == IWL_INVALID_STATION); - IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", - print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Removed STA from Ucode: %pM\n", addr); spin_lock_irqsave(&priv->sta_lock, flags); @@ -415,7 +409,6 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) int sta_id = IWL_INVALID_STATION; int i, ret = -EINVAL; unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); @@ -435,18 +428,18 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) if (unlikely(sta_id == IWL_INVALID_STATION)) goto out; - IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n", - sta_id, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Removing STA from driver:%d %pM\n", + sta_id, addr); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { - IWL_ERROR("Removing %s but non DRIVER active\n", - print_mac(mac, addr)); + IWL_ERROR("Removing %pM but non DRIVER active\n", + addr); goto out; } if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { - IWL_ERROR("Removing %s but non UCODE active\n", - print_mac(mac, addr)); + IWL_ERROR("Removing %pM but non UCODE active\n", + addr); goto out; } @@ -927,7 +920,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); - DECLARE_MAC_BUF(mac); /* If this frame is broadcast or management, use broadcast station id */ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || @@ -962,9 +954,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station %s not in station map. " + IWL_DEBUG_DROP("Station %pM not in station map. " "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); + hdr->addr1); iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 907a53e..37ebcff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -830,10 +830,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Find (or create) index into station table for destination station */ sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n", + hdr->addr1); goto drop; } @@ -1248,15 +1246,14 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) int ret; unsigned long flags; struct iwl_tid_data *tid_data; - DECLARE_MAC_BUF(mac); if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("%s on ra = %s tid = %d\n", - __func__, print_mac(mac, ra), tid); + IWL_WARNING("%s on ra = %pM tid = %d\n", + __func__, ra, tid); sta_id = iwl_find_station(priv, ra); if (sta_id == IWL_INVALID_STATION) @@ -1301,7 +1298,6 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) struct iwl_tid_data *tid_data; int ret, write_ptr, read_ptr; unsigned long flags; - DECLARE_MAC_BUF(mac); if (!ra) { IWL_ERROR("ra = NULL\n"); @@ -1467,7 +1463,6 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, int index; struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; - DECLARE_MAC_BUF(mac); /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); @@ -1489,10 +1484,10 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, /* TODO: Need to get this copy more safely - now good for debug */ - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %pM, " "sta_id = %d\n", agg->wait_for_ba, - print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32), + (u8 *) &ba_resp->sta_addr_lo32, ba_resp->sta_id); IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " "%d, scd_ssn = %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d15a2c9..d3a2966 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -446,7 +446,6 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 int index = IWL_INVALID_STATION; struct iwl3945_station_entry *station; unsigned long flags_spin; - DECLARE_MAC_BUF(mac); u8 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); @@ -480,7 +479,7 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 return index; } - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %pM\n", index, addr); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -1063,7 +1062,6 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; int rc = 0; - DECLARE_MAC_BUF(mac); if (!iwl3945_is_alive(priv)) return -1; @@ -1124,11 +1122,11 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = %s\n", + "* bssid = %pM\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); + priv->staging_rxon.bssid_addr); /* Apply the new configuration */ rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON, @@ -2482,8 +2480,6 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ case NL80211_IFTYPE_ADHOC: { - DECLARE_MAC_BUF(mac); - /* Create new station table entry */ sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) @@ -2494,9 +2490,9 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station %s not in station map. " + IWL_DEBUG_DROP("Station %pM not in station map. " "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); + hdr->addr1); iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; } @@ -2579,10 +2575,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n", + hdr->addr1); goto drop; } @@ -4019,8 +4013,6 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, #ifdef CONFIG_IWL3945_DEBUG static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) { - DECLARE_MAC_BUF(mac); - IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4031,10 +4023,8 @@ static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -6321,7 +6311,6 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) { int rc = 0; struct ieee80211_conf *conf = NULL; - DECLARE_MAC_BUF(mac); if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); @@ -6329,9 +6318,8 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) } - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6592,7 +6580,6 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, { struct iwl3945_priv *priv = hw->priv; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -6609,7 +6596,7 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set: %s\n", print_mac(mac, conf->mac_addr)); + IWL_DEBUG_MAC80211("Set: %pM\n", conf->mac_addr); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } @@ -6778,7 +6765,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct iwl3945_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -6816,8 +6802,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); /* * very dubious code was here; the probe filtering flag is never set: @@ -6830,8 +6815,8 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %pM\n", + conf->bssid); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -7072,10 +7057,8 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, sta_id = iwl3945_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return -EINVAL; } @@ -7870,7 +7853,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e struct ieee80211_hw *hw; struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); unsigned long flags; - DECLARE_MAC_BUF(mac); /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ @@ -8045,7 +8027,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e } /* MAC Address location in EEPROM same for 3945/4965 */ get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); err = iwl3945_init_channel_map(priv); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 92be604..8b88e95 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -151,7 +151,6 @@ static int lbs_adhoc_join(struct lbs_private *priv, struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; u8 preamble = RADIO_PREAMBLE_LONG; - DECLARE_MAC_BUF(mac); u16 ratesize = 0; int ret = 0; @@ -226,8 +225,8 @@ static int lbs_adhoc_join(struct lbs_private *priv, 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); + lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n", + cmd.bss.bssid, cmd.bss.ssid); /* Only v8 and below support setting these */ if (priv->fwrelease < 0x09000000) { @@ -752,17 +751,15 @@ static int assoc_helper_bssid(struct lbs_private *priv, { int ret = 0; struct bss_descriptor * bss; - DECLARE_MAC_BUF(mac); - lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s", - print_mac(mac, assoc_req->bssid)); + lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid); /* Search for index position in list for requested MAC */ bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, assoc_req->mode); if (bss == NULL) { - lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " - "cannot associate.\n", print_mac(mac, assoc_req->bssid)); + lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, " + "cannot associate.\n", assoc_req->bssid); goto out; } @@ -1208,7 +1205,6 @@ void lbs_association_worker(struct work_struct *work) struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_ASSOC); @@ -1228,13 +1224,13 @@ void lbs_association_worker(struct work_struct *work) " chann: %d\n" " band: %d\n" " mode: %d\n" - " BSSID: %s\n" + " BSSID: %pM\n" " secinfo: %s%s%s\n" " auth_mode: %d\n", assoc_req->flags, escape_essid(assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, - print_mac(mac, assoc_req->bssid), + assoc_req->bssid, assoc_req->secinfo.WPAenabled ? " WPA" : "", assoc_req->secinfo.WPA2enabled ? " WPA2" : "", assoc_req->secinfo.wep_enabled ? " WEP" : "", @@ -1357,8 +1353,8 @@ void lbs_association_worker(struct work_struct *work) } if (success) { - lbs_deb_assoc("associated to %s\n", - print_mac(mac, priv->curbssparams.bssid)); + lbs_deb_assoc("associated to %pM\n", + priv->curbssparams.bssid); lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); @@ -1478,7 +1474,6 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -1505,8 +1500,8 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv, memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bssid), pauthenticate->authtype); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", + bssid, pauthenticate->authtype); ret = 0; out: @@ -1770,7 +1765,6 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) 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); @@ -1819,9 +1813,9 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", escape_essid(bss->ssid, bss->ssid_len), - print_mac(mac, priv->curbssparams.bssid), + priv->curbssparams.bssid, priv->curbssparams.channel); done: diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 297696d..8542d85 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -87,7 +87,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) struct cmd_ds_get_hw_spec cmd; int ret = -1; u32 i; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); @@ -110,8 +109,8 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n", - print_mac(mac, cmd.permanentaddr), + lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", + cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 8 & 0xff, diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 0aa0ce3..5f6bee4 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -65,7 +65,6 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; - DECLARE_MAC_BUF(mac); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -77,10 +76,9 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); - pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %04d | %s |", + pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |", numscansdone, iter_bss->channel, iter_bss->rssi, - print_mac(mac, iter_bss->bssid)); + iter_bss->bssid); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 73dc8c7..34a47f6 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -588,7 +588,6 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, { int i = nr_addrs; struct dev_mc_list *mc_list; - DECLARE_MAC_BUF(mac); if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) return nr_addrs; @@ -596,16 +595,16 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, netif_addr_lock_bh(dev); for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { - lbs_deb_net("mcast address %s:%s skipped\n", dev->name, - print_mac(mac, mc_list->dmi_addr)); + lbs_deb_net("mcast address %s:%pM skipped\n", dev->name, + mc_list->dmi_addr); continue; } if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE) break; memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN); - lbs_deb_net("mcast address %s:%s added to filter\n", dev->name, - print_mac(mac, mc_list->dmi_addr)); + lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name, + mc_list->dmi_addr); i++; } netif_addr_unlock_bh(dev); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8f66903..fcaef38 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -359,7 +359,6 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor *iter; int i = 0; - DECLARE_MAC_BUF(mac); #endif lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); @@ -451,8 +450,8 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) mutex_lock(&priv->lock); lbs_deb_scan("scan table:\n"); list_for_each_entry(iter, &priv->network_list, list) - lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n", - i++, print_mac(mac, iter->bssid), iter->rssi, + lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", + i++, iter->bssid, iter->rssi, escape_essid(iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif @@ -512,7 +511,6 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - DECLARE_MAC_BUF(mac); struct ieeetypes_countryinfoset *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; @@ -544,7 +542,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); - lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid)); + lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid); pos += ETH_ALEN; if ((end - pos) < 12) { @@ -1151,7 +1149,6 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, struct bss_descriptor new; struct bss_descriptor *found = NULL; struct bss_descriptor *oldest = NULL; - DECLARE_MAC_BUF(mac); /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); @@ -1190,7 +1187,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, continue; } - lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid)); + lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 82c3e5a5..04f0bf2 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -2104,7 +2104,6 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, struct lbs_private *priv = dev->priv; struct assoc_request * assoc_req; int ret = 0; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_WEXT); @@ -2114,7 +2113,7 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data)); + lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data); mutex_lock(&priv->lock); diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c index fdbcf8b..3d3914c 100644 --- a/drivers/net/wireless/libertas_tf/cmd.c +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -79,7 +79,6 @@ int lbtf_update_hw_spec(struct lbtf_private *priv) struct cmd_ds_get_hw_spec cmd; int ret = -1; u32 i; - DECLARE_MAC_BUF(mac); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); @@ -96,8 +95,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv) priv->fwrelease = (priv->fwrelease << 8) | (priv->fwrelease >> 24 & 0xff); - printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n", - print_mac(mac, cmd.permanentaddr), + printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n", + cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 8 & 0xff, diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1a019e9..88c5eec 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -301,10 +301,9 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", wiphy_name(hw->wiphy), __func__, conf->type, - print_mac(mac, conf->mac_addr)); + conf->mac_addr); hwsim_set_magic(conf->vif); return 0; } @@ -313,10 +312,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, static void mac80211_hwsim_remove_interface( struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", wiphy_name(hw->wiphy), __func__, conf->type, - print_mac(mac, conf->mac_addr)); + conf->mac_addr); hwsim_check_magic(conf->vif); hwsim_clear_magic(conf->vif); } @@ -505,7 +503,6 @@ static int __init init_mac80211_hwsim(void) u8 addr[ETH_ALEN]; struct mac80211_hwsim_data *data; struct ieee80211_hw *hw; - DECLARE_MAC_BUF(mac); if (radios < 1 || radios > 100) return -EINVAL; @@ -588,9 +585,9 @@ static int __init init_mac80211_hwsim(void) goto failed_hw; } - printk(KERN_DEBUG "%s: hwaddr %s registered\n", + printk(KERN_DEBUG "%s: hwaddr %pM registered\n", wiphy_name(hw->wiphy), - print_mac(mac, hw->wiphy->perm_addr)); + hw->wiphy->perm_addr); setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index a670f36b..be80c00 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -737,7 +737,6 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; - DECLARE_MAC_BUF(mac); DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); @@ -808,12 +807,12 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, " - "id %c%c, hw_addr %s\n", + "id %c%c, hw_addr %pM\n", dev->name, dev->base_addr, dev->irq, (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), (int) readb(ramBase+NETWAVE_EREG_NI+1), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* get revision words */ printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index e0512e4..366556f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1477,12 +1477,11 @@ static void orinoco_rx(struct net_device *dev, MICHAEL_MIC_LEN)) { union iwreq_data wrqu; struct iw_michaelmicfailure wxmic; - DECLARE_MAC_BUF(mac); printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %s, " + "Invalid Michael MIC in data frame from %pM, " "using key %i\n", - dev->name, print_mac(mac, src), key_id); + dev->name, src, key_id); /* TODO: update stats */ @@ -3277,7 +3276,6 @@ static int orinoco_init(struct net_device *dev) struct hermes_idstring nickbuf; u16 reclen; int len; - DECLARE_MAC_BUF(mac); /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ @@ -3348,8 +3346,8 @@ static int orinoco_init(struct net_device *dev) goto out; } - printk(KERN_DEBUG "%s: MAC address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "%s: MAC address %pM\n", + dev->name, dev->dev_addr); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 2d022f8..72859de 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -320,7 +320,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) int err; u8 *end = (u8 *)eeprom + len; u16 synth; - DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -445,9 +444,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) SET_IEEE80211_PERM_ADDR(dev, perm_addr); } - printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n", + printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), + dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); return 0; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 1c2a02a..194237b 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -481,7 +481,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, struct ieee80211_hw *dev; unsigned long mem_addr, mem_len; int err; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 75d749b..68f1b80 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -786,7 +786,6 @@ static int __devinit p54u_probe(struct usb_interface *intf, struct p54u_priv *priv; int err; unsigned int i, recognized_pipes; - DECLARE_MAC_BUF(mac); dev = p54_init_common(sizeof(*priv)); if (!dev) { diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 16e68f4..57a150a 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2028,12 +2028,11 @@ static void format_event(islpci_private *priv, char *dest, const char *str, const struct obj_mlme *mlme, u16 *length, int error) { - DECLARE_MAC_BUF(mac); int n = snprintf(dest, IW_CUSTOM_MAX, - "%s %s %s %s (%2.2X)", + "%s %s %pM %s (%2.2X)", str, ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), - print_mac(mac, mlme->address), + mlme->address, (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") : ""), mlme->code); BUG_ON(n > IW_CUSTOM_MAX); @@ -2113,7 +2112,6 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; - DECLARE_MAC_BUF(mac); if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; @@ -2154,7 +2152,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, bss->last_update = jiffies; } else { printk(KERN_DEBUG "Failed to add BSS WPA entry for " - "%s\n", print_mac(mac, bssid)); + "%pM\n", bssid); } /* expire old entries from WPA list */ @@ -2219,7 +2217,6 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, { struct ieee80211_beacon_phdr *hdr; u8 *pos, *end; - DECLARE_MAC_BUF(mac); if (!priv->wpa) return; @@ -2230,7 +2227,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, while (pos < end) { if (pos + 2 + pos[1] > end) { printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " - "for %s\n", print_mac(mac, addr)); + "for %pM\n", addr); return; } if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && @@ -2269,7 +2266,6 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, size_t len = 0; /* u16, better? */ u8 *payload = NULL, *pos = NULL; int ret; - DECLARE_MAC_BUF(mac); /* I think all trapable objects are listed here. * Some oids have a EX version. The difference is that they are emitted @@ -2358,8 +2354,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, break; memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - printk(KERN_DEBUG "Authenticate from: address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "Authenticate from: address:\t%pM\n", + mlmeex->address); confirm->id = -1; /* or mlmeex->id ? */ confirm->state = 0; /* not used */ confirm->code = 0; @@ -2404,8 +2400,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", + mlmeex->address); kfree(confirm); break; } @@ -2441,8 +2437,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", + mlmeex->address); kfree(confirm); break; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1404a57..bf0b9299 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -414,7 +414,6 @@ static int ray_config(struct pcmcia_device *link) memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); - DECLARE_MAC_BUF(mac); DEBUG(1, "ray_config(0x%p)\n", link); @@ -485,8 +484,8 @@ static int ray_config(struct pcmcia_device *link) strcpy(local->node.dev_name, dev->name); link->dev_node = &local->node; - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n", - dev->name, dev->irq, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n", + dev->name, dev->irq, dev->dev_addr); return 0; @@ -2595,7 +2594,6 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; - DECLARE_MAC_BUF(mac); link = this_device; if (!link) @@ -2623,8 +2621,7 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) nettype[local->sparm.b5.a_network_type], c); p = local->bss_id; - seq_printf(m, "BSSID = %s\n", - print_mac(mac, p)); + seq_printf(m, "BSSID = %pM\n", p); seq_printf(m, "Country code = %d\n", local->sparm.b5.a_curr_country_code); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2b41489..bd059e3 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1276,12 +1276,11 @@ static int rndis_iw_get_bssid(struct net_device *dev, struct usbnet *usbdev = dev->priv; unsigned char bssid[ETH_ALEN]; int ret; - DECLARE_MAC_BUF(mac); ret = get_bssid(usbdev, bssid); if (ret == 0) - devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid)); + devdbg(usbdev, "SIOCGIWAP: %pM", bssid); else devdbg(usbdev, "SIOCGIWAP: "); @@ -1297,10 +1296,9 @@ static int rndis_iw_set_bssid(struct net_device *dev, { struct usbnet *usbdev = dev->priv; u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; - DECLARE_MAC_BUF(mac); int ret; - devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid)); + devdbg(usbdev, "SIOCSIWAP: %pM", bssid); ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); @@ -1660,11 +1658,10 @@ static char *rndis_translate_scan(struct net_device *dev, u32 beacon, atim; struct iw_event iwe; unsigned char sbuf[32]; - DECLARE_MAC_BUF(mac); bssid_len = le32_to_cpu(bssid->length); - devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac)); + devdbg(usbdev, "BSSID %pM", bssid->mac); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 08cb9ee..96eaf5f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1313,10 +1313,8 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index ef42cc0..8b772ab 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1451,11 +1451,8 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", - print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d3bf7bb..d19bee4 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1319,10 +1319,8 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a461620..45f69f8 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2175,10 +2175,8 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 934f8e03..336fecb 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1781,10 +1781,8 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index df7e78e..9de8f57 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -806,7 +806,6 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, const char *chip_name, *rf_name = NULL; u32 reg; u16 eeprom_val; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -1002,8 +1001,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, goto err_iounmap; } - printk(KERN_INFO "%s: hwaddr %s, %s + %s\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 431e3c7..9ceae90 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -1026,7 +1026,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, const char *chip_name; u16 txpwr, reg; int err, i; - DECLARE_MAC_BUF(mac); dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); if (!dev) { @@ -1209,8 +1208,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, } mutex_init(&priv->conf_mutex); - printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->asic_rev, priv->rf->name); return 0; diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index e939a73..6fa3d79 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -859,8 +859,6 @@ static void wv_82586_reconfig(struct net_device * dev) */ static void wv_psa_show(psa_t * p) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -872,13 +870,10 @@ static void wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %s\n", - print_mac(mac, p->psa_unused0)); + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", - print_mac(mac, p->psa_univ_mac_addr)); - printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", - print_mac(mac, p->psa_local_mac_addr)); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); @@ -1220,14 +1215,13 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ { /* Name of the function */ int i; int maxi; - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG - "%s: %s(): dest %s, length %d\n", - msg1, msg2, print_mac(mac, p), length); + "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); printk(KERN_DEBUG - "%s: %s(): src %s, type 0x%02X%02X\n", - msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); + "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1258,9 +1252,6 @@ static void wv_init_info(struct net_device * dev) short ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; psa_t psa; -#ifdef DEBUG_BASIC_SHOW - DECLARE_MAC_BUF(mac); -#endif /* Read the parameter storage area */ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1277,8 +1268,8 @@ static void wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d", - dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq); + printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d", + dev->name, ioaddr, dev->dev_addr, dev->irq); /* Print current network ID. */ if (psa.psa_nwid_select) @@ -3565,15 +3556,11 @@ static void wv_82586_config(struct net_device * dev) WAVELAN_ADDR_SIZE >> 1); #ifdef DEBUG_CONFIG_INFO - { - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for (dmi = dev->mc_list; dmi; dmi = dmi->next) - printk(KERN_DEBUG " %s\n", - print_mac(mac, dmi->dmi_addr)); - } + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); #endif } diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e124b1d..7bf4458 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1020,7 +1020,6 @@ wv_82593_reconfig(struct net_device * dev) static void wv_psa_show(psa_t * p) { - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -1034,13 +1033,10 @@ wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %s\n", - print_mac(mac, p->psa_unused0)); + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", - print_mac(mac, p->psa_univ_mac_addr)); - printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", - print_mac(mac, p->psa_local_mac_addr)); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); @@ -1238,12 +1234,11 @@ wv_packet_info(u_char * p, /* Packet to dump */ { int i; int maxi; - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n", - msg1, msg2, print_mac(mac, p), length); - printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n", - msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); + printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); + printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1274,7 +1269,6 @@ wv_init_info(struct net_device * dev) { unsigned int base = dev->base_addr; psa_t psa; - DECLARE_MAC_BUF(mac); /* Read the parameter storage area */ psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1291,10 +1285,8 @@ wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff */ - printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, " - "hw_addr %s", - dev->name, base, dev->irq, - print_mac(mac, dev->dev_addr)); + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM", + dev->name, base, dev->irq, dev->dev_addr); /* Print current network id */ if(psa.psa_nwid_select) @@ -3647,12 +3639,10 @@ wv_82593_config(struct net_device * dev) int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; #ifdef DEBUG_CONFIG_INFO - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %s\n", - print_mac(mac, dmi->dmi_addr)); + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); #endif /* Initialize adapter's ethernet multicast addresses */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 68789c6..8b96f50 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -860,10 +860,9 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { struct wl3501_card *this = netdev_priv(dev); - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n", - dev->name, print_mac(mac, this->bssid)); + printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", + dev->name, this->bssid); netif_wake_queue(dev); } @@ -1965,7 +1964,6 @@ static int wl3501_config(struct pcmcia_device *link) struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; struct wl3501_card *this; - DECLARE_MAC_BUF(mac); /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- @@ -2024,9 +2022,9 @@ static int wl3501_config(struct pcmcia_device *link) /* print probe information */ printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%s\n", + "MAC addr in flash ROM:%pM\n", dev->name, this->base_addr, (int)dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* * Initialize card parameters - added by jss */ diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index e0ac58b..f151914 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -378,7 +378,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) [0] = { .addr = CR_MAC_ADDR_P1 }, [1] = { .addr = CR_MAC_ADDR_P2 }, }; - DECLARE_MAC_BUF(mac); if (mac_addr) { reqs[0].value = (mac_addr[3] << 24) @@ -387,8 +386,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) | mac_addr[0]; reqs[1].value = (mac_addr[5] << 8) | mac_addr[4]; - dev_dbg_f(zd_chip_dev(chip), - "mac addr %s\n", print_mac(mac, mac_addr)); + dev_dbg_f(zd_chip_dev(chip), "mac addr %pM\n", mac_addr); } else { dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n"); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index fe1867b..de45509 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -852,14 +852,12 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { zd_mc_add_all(&hash); } else { - DECLARE_MAC_BUF(macbuf); - zd_mc_clear(&hash); for (i = 0; i < mc_count; i++) { if (!mclist) break; - dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", - print_mac(macbuf, mclist->dmi_addr)); + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", + mclist->dmi_addr); zd_mc_add_addr(&hash, mclist->dmi_addr); mclist = mclist->next; } -- cgit v1.1 From 7c510e4b730a92cecf94ada45c989d8be0200d47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Oct 2008 17:47:26 -0700 Subject: net: convert more to %pM A number of places still use %02x:...:%02x because it's in debug statements or for no real reason. Make a few of them use %pM. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/wireless/wavelan_cs.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 7bf4458..0a3bacc 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -2235,13 +2235,7 @@ static int wavelan_set_wap(struct net_device *dev, char *extra) { #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", - wrqu->ap_addr.sa_data[0], - wrqu->ap_addr.sa_data[1], - wrqu->ap_addr.sa_data[2], - wrqu->ap_addr.sa_data[3], - wrqu->ap_addr.sa_data[4], - wrqu->ap_addr.sa_data[5]); + printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data); #endif /* DEBUG_IOCTL_INFO */ return -EOPNOTSUPP; -- cgit v1.1 From 275f165fa970174f8a98205529750e8abb6c0a33 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 20 Oct 2008 21:42:39 -0700 Subject: pci: use pci_ioremap_bar() in drivers/net Use the newly introduced pci_ioremap_bar() function in drivers/net. pci_ioremap_bar() just takes a pci device and a bar number, with the goal of making it really hard to get wrong, while also having a central place to stick sanity checks. Signed-off-by: Arjan van de Ven Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_pci.c | 2 +- drivers/net/wireless/ipw2200.c | 2 +- drivers/net/wireless/rt2x00/rt2x00pci.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 3a874fc..8fdd41f 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -312,7 +312,7 @@ static int prism2_pci_probe(struct pci_dev *pdev, goto err_out_disable; } - mem = ioremap(phymem, pci_resource_len(pdev, 0)); + mem = pci_ioremap_bar(pdev, 0); if (mem == NULL) { printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; goto fail; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d0bfd86..13633d8 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -11621,7 +11621,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, length = pci_resource_len(pdev, 0); priv->hw_len = length; - base = ioremap_nocache(pci_resource_start(pdev, 0), length); + base = pci_ioremap_bar(pdev, 0); if (!base) { err = -ENODEV; goto out_pci_release_regions; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index adf2876..62449da 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -222,8 +222,7 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) { struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); - rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0), - pci_resource_len(pci_dev, 0)); + rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0); if (!rt2x00dev->csr.base) goto exit; -- cgit v1.1 From be5d56ed885a2897ec813eab4a8055d495816e9a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 8 Oct 2008 09:37:27 +0800 Subject: iwlwifi: make initial calibration set configurable This patch adds ability to configure initial calibration set. Not all HW supported by iwlwifi use the same calibration set, XTAL is one example. Some clean ups are also included in this patch. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 44 +++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-calib.c | 8 ++++-- drivers/net/wireless/iwlwifi/iwl-commands.h | 27 ++++++++---------- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ++- 5 files changed, 49 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index c479ee2..66ed993 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -132,6 +132,7 @@ struct iwl5000_shared { /* calibrations defined for 5000 */ /* defines the order in which results should be sent to the runtime uCode */ enum iwl5000_calib { + IWL5000_CALIB_XTAL, IWL5000_CALIB_LO, IWL5000_CALIB_TX_IQ, IWL5000_CALIB_TX_IQ_PERD, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5155b8a..c1300fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -429,20 +429,19 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, /* * Calibration */ -static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) +static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { + u8 data[sizeof(struct iwl5000_calib_hdr) + + sizeof(struct iwl_cal_xtal_freq)]; + struct iwl5000_calib_cmd *cmd = (struct iwl5000_calib_cmd *)data; + struct iwl_cal_xtal_freq *xtal = (struct iwl_cal_xtal_freq *)cmd->data; u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); - struct iwl5000_calibration cal_cmd = { - .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD, - .data = { - (u8)xtal_calib[0], - (u8)xtal_calib[1], - } - }; - - return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cal_cmd), &cal_cmd); + cmd->hdr.op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; + xtal->cap_pin1 = (u8)xtal_calib[0]; + xtal->cap_pin2 = (u8)xtal_calib[1]; + return iwl_calib_set(&priv->calib_results[IWL5000_CALIB_XTAL], + data, sizeof(data)); } static int iwl5000_send_calib_cfg(struct iwl_priv *priv) @@ -784,10 +783,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_wimax_coex(priv); - iwl5000_send_Xtal_calib(priv); - - if (priv->ucode_type == UCODE_RT) - iwl_send_calib_results(priv); + iwl5000_set_Xtal_calib(priv); + iwl_send_calib_results(priv); return 0; } @@ -844,6 +841,23 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) break; } + /* Set initial calibration set */ + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + priv->hw_params.calib_init_cfg = + BIT(IWL5000_CALIB_XTAL) | + BIT(IWL5000_CALIB_LO) | + BIT(IWL5000_CALIB_TX_IQ) | + BIT(IWL5000_CALIB_TX_IQ_PERD); + break; + case CSR_HW_REV_TYPE_5150: + priv->hw_params.calib_init_cfg = 0; + break; + } + + return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 72fbf47..25f4658 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -70,7 +70,7 @@ * INIT calibrations framework *****************************************************************************/ - int iwl_send_calib_results(struct iwl_priv *priv) +int iwl_send_calib_results(struct iwl_priv *priv) { int ret = 0; int i = 0; @@ -80,14 +80,16 @@ .meta.flags = CMD_SIZE_HUGE, }; - for (i = 0; i < IWL_CALIB_MAX; i++) - if (priv->calib_results[i].buf) { + for (i = 0; i < IWL_CALIB_MAX; i++) { + if ((BIT(i) & priv->hw_params.calib_init_cfg) && + priv->calib_results[i].buf) { hcmd.len = priv->calib_results[i].buf_len; hcmd.data = priv->calib_results[i].buf; ret = iwl_send_cmd_sync(priv, &hcmd); if (ret) goto err; } + } return 0; err: diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8d04e96..fc467c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -98,6 +98,11 @@ enum { COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_EVENT_CMD = 0x5c, + /* Calibration */ + CALIBRATION_CFG_CMD = 0x65, + CALIBRATION_RES_NOTIFICATION = 0x66, + CALIBRATION_COMPLETE_NOTIFICATION = 0x67, + /* 802.11h related */ RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ @@ -2879,25 +2884,11 @@ enum { IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, }; -enum { - CALIBRATION_CFG_CMD = 0x65, - CALIBRATION_RES_NOTIFICATION = 0x66, - CALIBRATION_COMPLETE_NOTIFICATION = 0x67 -}; - -struct iwl_cal_crystal_freq_cmd { +struct iwl_cal_xtal_freq { u8 cap_pin1; u8 cap_pin2; } __attribute__ ((packed)); -struct iwl5000_calibration { - u8 op_code; - u8 first_group; - u8 num_groups; - u8 all_data_valid; - struct iwl_cal_crystal_freq_cmd data; -} __attribute__ ((packed)); - #define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) struct iwl_calib_cfg_elmnt_s { @@ -2927,6 +2918,11 @@ struct iwl5000_calib_hdr { u8 data_valid; } __attribute__ ((packed)); +struct iwl5000_calib_cmd { + struct iwl5000_calib_hdr hdr; + u8 data[0]; +} __attribute__ ((packed)); + struct iwl5000_calibration_chain_noise_reset_cmd { u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ u8 flags; /* not used */ @@ -3039,7 +3035,6 @@ struct iwl_rx_packet { struct iwl_notif_statistics stats; struct iwl_compressed_ba_resp compressed_ba; struct iwl4965_missed_beacon_notif missed_beacon; - struct iwl5000_calibration calib; __le32 status; u8 raw[0]; } u; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c018121..2125844 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -527,6 +527,7 @@ struct iwl_sensitivity_ranges { * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses * @ct_kill_threshold: temperature threshold + * @calib_init_cfg: setup initial claibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values * @first_ampdu_q: first HW queue available for ampdu */ @@ -548,6 +549,7 @@ struct iwl_hw_params { u32 max_data_size; u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ + u32 calib_init_cfg; const struct iwl_sensitivity_ranges *sens; u8 first_ampdu_q; }; @@ -765,7 +767,7 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ -#define IWL_CALIB_MAX 3 +#define IWL_CALIB_MAX 4 struct iwl_priv { -- cgit v1.1 From 5d664a41a0a8c612f66bcb3c2a6f395e9afa6beb Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 8 Oct 2008 09:37:29 +0800 Subject: iwlwifi: take a valid antenna upon rate scale init This patch selects a valid antennae upon rate scale init. This solves a SYSASSERT complaining that the driver is setting a non valid antenna in the LQ CMD. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +++++- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.c | 9 +++++---- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c1300fb..56a3f0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -811,10 +811,14 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5100: + priv->hw_params.tx_chains_num = 1; + priv->hw_params.rx_chains_num = 2; + priv->hw_params.valid_tx_ant = ANT_B; + priv->hw_params.valid_rx_ant = ANT_AB; + break; case CSR_HW_REV_TYPE_5150: priv->hw_params.tx_chains_num = 1; priv->hw_params.rx_chains_num = 2; - /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ priv->hw_params.valid_tx_ant = ANT_A; priv->hw_params.valid_rx_ant = ANT_AB; break; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index d148d73..bac91f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -284,6 +284,16 @@ static inline u8 num_of_ant(u8 mask) !!((mask) & ANT_C); } +static inline u8 first_antenna(u8 mask) +{ + if (mask & ANT_A) + return ANT_A; + if (mask & ANT_B) + return ANT_B; + return ANT_C; +} + + static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index e02c471..a28a8de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -845,7 +845,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) struct iwl_link_quality_cmd link_cmd = { .reserved1 = 0, }; - u16 rate_flags; + u32 rate_flags; /* Set up the rate scaling to start at selected rate, fall back * all the way down to 1M in IEEE order, and then spin on 1M */ @@ -861,15 +861,16 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; - /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; link_cmd.rs_table[i].rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); r = iwl4965_get_prev_ieee_rate(r); } - link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); link_cmd.general_params.dual_stream_ant_msk = 3; link_cmd.agg_params.agg_dis_start_th = 3; link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); -- cgit v1.1 From 3195c1f3499912b207ae600968488759b16037fc Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 8 Oct 2008 09:37:30 +0800 Subject: iwlwifi: refactor rxon time command This patch refactors rxon time command. It removes the usage of union tsf in favor of u64 value and hopefully makes code more readable. There are no functional changes in this patch. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 70 +++++++++++------------------ drivers/net/wireless/iwlwifi/iwl-commands.h | 11 ++--- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 3 files changed, 29 insertions(+), 55 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fe93074..2cac094 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -636,23 +636,22 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) #define MAX_UCODE_BEACON_INTERVAL 4096 -static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) +static u16 iwl_adjust_beacon_interval(u16 beacon_val) { u16 new_val = 0; u16 beacon_factor = 0; - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; + beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) + / MAX_UCODE_BEACON_INTERVAL; new_val = beacon_val / beacon_factor; - return cpu_to_le16(new_val); + return new_val; } -static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) +static void iwl_setup_rxon_timing(struct iwl_priv *priv) { - u64 interval_tm_unit; - u64 tsf, result; + u64 tsf; + s32 interval_tm, rem; unsigned long flags; struct ieee80211_conf *conf = NULL; u16 beacon_int = 0; @@ -660,49 +659,32 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32); - priv->rxon_timing.timestamp.dw[0] = - cpu_to_le32(priv->timestamp & 0xFFFFFFFF); - + priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); - tsf = priv->timestamp; - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - + beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); priv->rxon_timing.atim_window = 0; } else { - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval(conf->beacon_int); + beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); + /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ priv->rxon_timing.atim_window = 0; } - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); + priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); - IWL_DEBUG_ASSOC - ("beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); + tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ + interval_tm = beacon_int * 1024; + rem = do_div(tsf, interval_tm); + priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); } static void iwl_set_flags_for_band(struct iwl_priv *priv, @@ -2488,8 +2470,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (ret) @@ -2879,15 +2860,14 @@ static void iwl4965_config_ap(struct iwl_priv *priv) return; /* The following should be done only at AP bring up */ - if (!(iwl_is_associated(priv))) { + if (!iwl_is_associated(priv)) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl4965_commit_rxon(priv); /* RXON Timing */ - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (ret) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index fc467c5..ba54613 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -482,11 +482,6 @@ struct iwl_alive_resp { } __attribute__ ((packed)); -union tsf { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; -}; /* * REPLY_ERROR = 0x2 (response only, not a command) @@ -497,7 +492,7 @@ struct iwl_error_resp { u8 reserved1; __le16 bad_cmd_seq_num; __le32 error_info; - union tsf timestamp; + __le64 timestamp; } __attribute__ ((packed)); /****************************************************************************** @@ -684,8 +679,8 @@ struct iwl4965_rxon_assoc_cmd { /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) */ -struct iwl4965_rxon_time_cmd { - union tsf timestamp; +struct iwl_rxon_time_cmd { + __le64 timestamp; __le16 beacon_interval; __le16 atim_window; __le32 beacon_init_val; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2125844..34306b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -275,7 +275,6 @@ struct iwl_cmd { u16 val16; u32 val32; struct iwl4965_bt_cmd bt; - struct iwl4965_rxon_time_cmd rxon_time; struct iwl_powertable_cmd powertable; struct iwl_qosparam_cmd qosparam; struct iwl_tx_cmd tx; @@ -851,7 +850,7 @@ struct iwl_priv { u8 ucode_write_complete; /* the image write is complete */ - struct iwl4965_rxon_time_cmd rxon_timing; + struct iwl_rxon_time_cmd rxon_timing; /* We declare this const so it can only be * changed via explicit cast within the -- cgit v1.1 From 5d6924eaf07bec9ce7527cad9d2537e448574738 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Wed, 8 Oct 2008 11:18:27 +0200 Subject: mac80211: use HWSIM_STA_MAGIC in hwsim_check_sta_magic() and hwsim_set_sta_magic(). This patch fixes a typo in mac80211_hwsim.c: use HWSIM_STA_MAGIC in hwsim_check_sta_magic() and hwsim_set_sta_magic() instead of HWSIM_VIF_MAGIC. Signed-off-by: Rami Rosen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 88c5eec..e23d9a5 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -63,13 +63,13 @@ struct hwsim_sta_priv { static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; - WARN_ON(sp->magic != HWSIM_VIF_MAGIC); + WARN_ON(sp->magic != HWSIM_STA_MAGIC); } static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; - sp->magic = HWSIM_VIF_MAGIC; + sp->magic = HWSIM_STA_MAGIC; } static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) -- cgit v1.1 From 40333e4fb476014cdd939d27e20eb54573172b32 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 8 Oct 2008 20:52:22 +0200 Subject: p54: honour bss_info_changed's short slot time settings This patch was made on behalf of Johannes request. "mac80211 and IEEE80211_CONF_SHORT_SLOT_TIME" Of course, bss_info_changed provides some more useful data. e.g.: basic_rates, dtim_period, beacon_int and maybe even more. Everything can be hooked up if it's necessary. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1d0704f..8da4d30 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -81,6 +81,7 @@ struct p54_common { unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; unsigned int filter_flags; + bool use_short_slot; u16 rxhw; u8 version; u8 rx_antenna; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6370c44..b1dc10c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -901,12 +901,10 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, memset(filter->bssid, ~0, ETH_ALEN); else memcpy(filter->bssid, bssid, ETH_ALEN); - filter->rx_antenna = priv->rx_antenna; - if (priv->fw_var < 0x500) { data_len = P54_TX_CONTROL_FILTER_V1_LEN; - filter->v1.basic_rate_mask = cpu_to_le32(0x15F); + filter->v1.basic_rate_mask = cpu_to_le32(0x15f); filter->v1.rx_addr = cpu_to_le32(priv->rx_end); filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); filter->v1.rxhw = cpu_to_le16(priv->rxhw); @@ -918,7 +916,6 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter->v2.rxhw = cpu_to_le16(priv->rxhw); filter->v2.timer = cpu_to_le16(1000); } - hdr->len = cpu_to_le16(data_len); p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); @@ -1088,7 +1085,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) vdcf = (struct p54_tx_control_vdcf *) hdr->data; - if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + if (priv->use_short_slot) { vdcf->slottime = 9; vdcf->magic1 = 0x10; vdcf->magic2 = 0x00; @@ -1135,7 +1132,6 @@ static int p54_start(struct ieee80211_hw *dev) priv->mode = NL80211_IFTYPE_MONITOR; p54_init_vdcf(dev); - mod_timer(&priv->stats_timer, jiffies + HZ); return err; } @@ -1351,6 +1347,19 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, return 0; } +static void p54_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct p54_common *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT) { + priv->use_short_slot = info->use_short_slot; + p54_set_vdcf(dev); + } +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, @@ -1359,6 +1368,7 @@ static const struct ieee80211_ops p54_ops = { .remove_interface = p54_remove_interface, .config = p54_config, .config_interface = p54_config_interface, + .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -1385,7 +1395,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ - priv->tx_stats[0].limit = 1; priv->tx_stats[1].limit = 1; priv->tx_stats[2].limit = 1; -- cgit v1.1 From d9fe60dea7779d412b34679f1177c5ca1940ea8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Oct 2008 12:13:49 +0200 Subject: 802.11: clean up/fix HT support This patch cleans up a number of things: * the unusable definition of the HT capabilities/HT information information elements * variable names that are hard to understand * mac80211: move ieee80211_handle_ht to ht.c and remove the unused enable_ht parameter * mac80211: fix bug with MCS rate 32 in ieee80211_handle_ht * mac80211: fix bug with casting the result of ieee80211_bss_get_ie to an information element _contents_ rather than the whole element, add size checking (another out-of-bounds access bug fixed!) * mac80211: remove some unused return values in favour of BUG_ON checking * a few minor other things Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 57 ++++++++++++------------- drivers/net/wireless/ath9k/rc.c | 10 ++--- drivers/net/wireless/ath9k/rc.h | 1 - drivers/net/wireless/ath9k/recv.c | 2 +- drivers/net/wireless/ath9k/xmit.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 18 ++++---- drivers/net/wireless/iwlwifi/iwl-agn.c | 20 ++++----- drivers/net/wireless/iwlwifi/iwl-core.c | 71 ++++++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 12 +++--- drivers/net/wireless/iwlwifi/iwl-sta.c | 6 +-- drivers/net/wireless/mac80211_hwsim.c | 19 ++++----- 13 files changed, 110 insertions(+), 114 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 186d75a..5e087c9 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -61,24 +61,24 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, switch (chan->band) { case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && (tx_chan_width == ATH9K_HT_MACMODE_20)) chanmode = CHANNEL_G_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_G_HT40MINUS; break; case IEEE80211_BAND_5GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && (tx_chan_width == ATH9K_HT_MACMODE_20)) chanmode = CHANNEL_A_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && + if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_A_HT40MINUS; break; @@ -215,24 +215,24 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) ath_key_reset(sc, key->keyidx, freeslot); } -static void setup_ht_cap(struct ieee80211_ht_info *ht_info) +static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) { #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 - |(u16)IEEE80211_HT_CAP_SM_PS - |(u16)IEEE80211_HT_CAP_SGI_40 - |(u16)IEEE80211_HT_CAP_DSSSCCK40; + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; 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; - ht_info->supp_mcs_set[1] = 0xff; - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.rx_mask[1] = 0xff; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } static int ath_rate2idx(struct ath_softc *sc, int rate) @@ -328,31 +328,28 @@ static u8 parse_mpdudensity(u8 mpdudensity) static void ath9k_ht_conf(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { -#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) struct ath_ht_info *ht_info = &sc->sc_ht_info; if (bss_conf->assoc_ht) { ht_info->ext_chan_offset = bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_SEC_OFFSET; + IEEE80211_HT_PARAM_CHA_SEC_OFFSET; - if (!(bss_conf->ht_conf->cap & + if (!(bss_conf->ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_WIDTH)) + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; else ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - bss_conf->ht_conf->ampdu_factor); + bss_conf->ht_cap->ampdu_factor); ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_conf->ampdu_density); + parse_mpdudensity(bss_conf->ht_cap->ampdu_density); } - -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT } static void ath9k_bss_assoc_info(struct ath_softc *sc, @@ -411,7 +408,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, return; } - if (hw->conf.ht_conf.ht_supported) + if (hw->conf.ht_cap.ht_supported) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); else @@ -534,7 +531,7 @@ int _ath_rx_indicate(struct ath_softc *sc, if (an) { ath_rx_input(sc, an, - hw->conf.ht_conf.ht_supported, + hw->conf.ht_cap.ht_supported, skb, status, &st); } if (!an || (st != ATH_RX_CONSUMED)) @@ -943,7 +940,7 @@ static int ath_attach(u16 devid, if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) /* Setup HT capabilities for 2.4Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); + setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; @@ -958,7 +955,7 @@ static int ath_attach(u16 devid, if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) /* Setup HT capabilities for 5Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); + setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; @@ -1254,7 +1251,7 @@ static int ath9k_config(struct ieee80211_hw *hw, (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) + if (sc->sc_curaid && hw->conf.ht_cap.ht_supported) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index b1e535b..ee2dbce 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1838,7 +1838,7 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) struct ath_softc *sc = hw->priv; u32 capflag = 0; - if (hw->conf.ht_conf.ht_supported) { + if (hw->conf.ht_cap.ht_supported) { capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) capflag |= ATH_RC_CW40_FLAG; @@ -1910,7 +1910,7 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, */ si = container_of(sta, struct sta_info, sta); buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ + sband->ht_cap.ampdu_factor; /* FIXME */ state = si->ampdu_mlme.tid_state_tx[tidno]; if (state & HT_ADDBA_RECEIVED_MSK) { @@ -1979,7 +1979,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, /* Check if aggregation has to be enabled for this tid */ - if (hw->conf.ht_conf.ht_supported) { + if (hw->conf.ht_cap.ht_supported) { if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; @@ -2027,8 +2027,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, ath_setup_rates(sc, sband, sta, ath_rc_priv); if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - for (i = 0; i < MCS_SET_SIZE; i++) { - if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) + for (i = 0; i < 77; i++) { + if (sc->hw->conf.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index b95b415..6671097 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -59,7 +59,6 @@ struct ath_softc; #define FALSE 0 #define ATH_RATE_MAX 30 -#define MCS_SET_SIZE 128 enum ieee80211_fixed_rate_mode { IEEE80211_FIXED_RATE_NONE = 0, diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 4983402..010fcdf 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -1119,7 +1119,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, sband = hw->wiphy->bands[hw->conf.channel->band]; buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ + sband->ht_cap.ampdu_factor; /* FIXME */ rxtid = &an->an_aggr.rx.tid[tid]; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 1386604..3770fbe 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -300,7 +300,7 @@ static int ath_tx_prepare(struct ath_softc *sc, if (ieee80211_is_data(fc) && !txctl->use_minrate) { /* Enable HT only for DATA frames and not for EAPOL */ - txctl->ht = (hw->conf.ht_conf.ht_supported && + txctl->ht = (hw->conf.ht_cap.ht_supported && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); if (is_multicast_ether_addr(hdr->addr1)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index b497d40..cd1bff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1134,10 +1134,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s8 is_green = lq_sta->is_green; if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + !sta->ht_cap.ht_supported) return -1; - if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == WLAN_HT_CAP_SM_PS_STATIC) return -1; @@ -1202,7 +1202,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, s32 rate; if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + !sta->ht_cap.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); @@ -2238,19 +2238,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; - lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; + lq_sta->active_siso_rate = conf->ht_cap.mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= conf->ht_cap.mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; - lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; + lq_sta->active_mimo2_rate = conf->ht_cap.mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= conf->ht_cap.mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; - lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; + lq_sta->active_mimo3_rate = conf->ht_cap.mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= conf->ht_cap.mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2cac094..e6695e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -552,7 +552,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) static void iwl4965_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; + struct ieee80211_sta_ht_cap *ht_conf = bss_conf->ht_cap; struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; struct iwl_ht_info *iwl_conf = &priv->current_ht_config; @@ -573,27 +573,27 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { - iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; + if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; iwl_conf->supported_chan_width = 0; } iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); + memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); iwl_conf->control_channel = ht_bss_conf->primary_channel; iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + !!(ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY); iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); + !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); IWL_DEBUG_MAC80211("leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4c312c55..4678da4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -382,10 +382,10 @@ void iwl_reset_qos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_reset_qos); -#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */ -#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */ +#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ +#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, + struct ieee80211_sta_ht_cap *ht_info, enum ieee80211_band band) { u16 max_bit_rate = 0; @@ -393,45 +393,46 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, u8 tx_chains_num = priv->hw_params.tx_chains_num; ht_info->cap = 0; - memset(ht_info->supp_mcs_set, 0, 16); + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - ht_info->ht_supported = 1; + ht_info->ht_supported = true; - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS & + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.fat_channel & BIT(band)) { - ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; - ht_info->supp_mcs_set[4] = 0x01; + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + ht_info->mcs.rx_mask[4] = 0x01; max_bit_rate = MAX_BIT_RATE_40_MHZ; } if (priv->cfg->mod_params->amsdu_size_8K) - ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - ht_info->supp_mcs_set[0] = 0xFF; + ht_info->mcs.rx_mask[0] = 0xFF; if (rx_chains_num >= 2) - ht_info->supp_mcs_set[1] = 0xFF; + ht_info->mcs.rx_mask[1] = 0xFF; if (rx_chains_num >= 3) - ht_info->supp_mcs_set[2] = 0xFF; + ht_info->mcs.rx_mask[2] = 0xFF; /* Highest supported Rx data rate */ max_bit_rate *= rx_chains_num; - ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); - ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); + WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); + ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); /* Tx MCS capabilities */ - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; if (tx_chains_num != rx_chains_num) { - ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; - ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_chains_num - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } } @@ -495,7 +496,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & IWL_SKU_N) - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_5GHZ); sband = &priv->bands[IEEE80211_BAND_2GHZ]; @@ -505,7 +506,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT; if (priv->cfg->sku & IWL_SKU_N) - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; @@ -595,8 +596,8 @@ static void iwlcore_free_geos(struct iwl_priv *priv) static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || - ((priv->current_ht_config.supp_mcs_set[1] == 0) && - (priv->current_ht_config.supp_mcs_set[2] == 0)); + ((priv->current_ht_config.mcs.rx_mask[1] == 0) && + (priv->current_ht_config.mcs.rx_mask[2] == 0)); } static u8 iwl_is_channel_extension(struct iwl_priv *priv, @@ -609,10 +610,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return 0; - if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) + if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) return !(ch_info->fat_extension_channel & IEEE80211_CHAN_NO_FAT_ABOVE); - else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) + else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) return !(ch_info->fat_extension_channel & IEEE80211_CHAN_NO_FAT_BELOW); @@ -620,18 +621,18 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, } u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; if ((!iwl_ht_conf->is_ht) || (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE)) + (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) return 0; if (sta_ht_inf) { if ((!sta_ht_inf->ht_supported) || - (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))) + (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) return 0; } @@ -671,13 +672,13 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) /* Note: control channel is opposite of extension channel */ switch (ht_info->extension_chan_offset) { - case IEEE80211_HT_IE_CHA_SEC_ABOVE: + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); break; - case IEEE80211_HT_IE_CHA_SEC_BELOW: + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; - case IEEE80211_HT_IE_CHA_SEC_NONE: + case IEEE80211_HT_PARAM_CHA_SEC_NONE: default: rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; break; @@ -693,9 +694,9 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x " "control chan %d\n", - ht_info->supp_mcs_set[0], - ht_info->supp_mcs_set[1], - ht_info->supp_mcs_set[2], + ht_info->mcs.rx_mask[0], + ht_info->mcs.rx_mask[1], + ht_info->mcs.rx_mask[2], le32_to_cpu(rxon->flags), ht_info->ht_protection, ht_info->extension_chan_offset, ht_info->control_channel); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 288b6a8..1a3ad8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -190,7 +190,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf); + struct ieee80211_sta_ht_cap *sta_ht_inf); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 34306b6..572250e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -411,7 +411,7 @@ struct iwl_ht_info { u8 max_amsdu_size; u8 ampdu_factor; u8 mpdu_density; - u8 supp_mcs_set[16]; + struct ieee80211_mcs_info mcs; /* BSS related data */ u8 control_channel; u8 extension_chan_offset; @@ -585,7 +585,7 @@ struct iwl_addsta_cmd; extern int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); + int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); extern void iwl4965_update_chain_flags(struct iwl_priv *priv); extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); extern const u8 iwl_bcast_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 3b0bee3..78d16bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -550,7 +550,7 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, { struct ieee80211_ht_cap *ht_cap; - if (!sband || !sband->ht_info.ht_supported) + if (!sband || !sband->ht_cap.ht_supported) return; if (*left < sizeof(struct ieee80211_ht_cap)) @@ -559,12 +559,12 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (struct ieee80211_ht_cap *) pos; - ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); - memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); + ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); + memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); ht_cap->ampdu_params_info = - (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | - ((sband->ht_info.ampdu_density << 2) & - IEEE80211_HT_CAP_AMPDU_DENSITY); + (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((sband->ht_cap.ampdu_density << 2) & + IEEE80211_HT_AMPDU_PARM_DENSITY); *left -= sizeof(struct ieee80211_ht_cap); } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index a28a8de..b9b8554 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -181,7 +181,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, EXPORT_SYMBOL(iwl_send_add_sta); static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { __le32 sta_flags; u8 mimo_ps_mode; @@ -229,7 +229,7 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, * iwl_add_station_flags - Add station to tables in driver and device */ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_ht_info *ht_info) + u8 flags, struct ieee80211_sta_ht_cap *ht_info) { int i; int sta_id = IWL_INVALID_STATION; @@ -894,7 +894,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) /* Add station to device's station table */ struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; + struct ieee80211_sta_ht_cap *cur_ht_config = &conf->ht_cap; if ((is_ap) && (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e23d9a5..3f236b5 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -563,19 +563,18 @@ 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 | + data->band.ht_cap.ht_supported = true; + data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 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; + data->band.ht_cap.ampdu_factor = 0x3; + data->band.ht_cap.ampdu_density = 0x6; + memset(&data->band.ht_cap.mcs, 0, + sizeof(data->band.ht_cap.mcs)); + data->band.ht_cap.mcs.rx_mask[0] = 0xff; + data->band.ht_cap.mcs.rx_mask[1] = 0xff; + data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; err = ieee80211_register_hw(hw); -- cgit v1.1 From 0f4ac38b5999c3d51adad52d61c56c1b99c247ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Oct 2008 12:18:04 +0200 Subject: mac80211: kill hw.conf.antenna_sel_{rx,tx} Never actually used. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 25 +++---------------------- drivers/net/wireless/b43legacy/main.c | 18 ++---------------- drivers/net/wireless/p54/p54common.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00config.c | 20 ++++---------------- drivers/net/wireless/rt2x00/rt2x00dev.c | 6 ++---- 5 files changed, 12 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6e77301..6b85428 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1339,25 +1339,6 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, return antenna_nr; } -static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) -{ - antenna = b43_ieee80211_antenna_sanitize(dev, antenna); - switch (antenna) { - case 0: /* default/diversity */ - return B43_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43_ANTENNA0; - case 2: /* Antenna 1 */ - return B43_ANTENNA1; - case 3: /* Antenna 2 */ - return B43_ANTENNA2; - case 4: /* Antenna 3 */ - return B43_ANTENNA3; - default: - return B43_ANTENNA_DEFAULT; - } -} - /* Convert a b43 antenna number value to the PHY TX control value. */ static u16 b43_antenna_to_phyctl(int antenna) { @@ -1399,7 +1380,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -3399,9 +3380,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } /* Antennas for RX and management frame TX. */ - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; b43_mgmtframe_txantenna(dev, antenna); - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); + antenna = B43_ANTENNA_DEFAULT; if (phy->ops->set_rx_antenna) phy->ops->set_rx_antenna(dev, antenna); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c66d575..867f01c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2556,20 +2556,6 @@ init_failure: return err; } -static int b43legacy_antenna_from_ieee80211(u8 antenna) -{ - switch (antenna) { - case 0: /* default/diversity */ - return B43legacy_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43legacy_ANTENNA0; - case 2: /* Antenna 1 */ - return B43legacy_ANTENNA1; - default: - return B43legacy_ANTENNA_DEFAULT; - } -} - static int b43legacy_op_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { @@ -2583,8 +2569,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int err = 0; u32 savedirqs; - antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx); - antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); + antenna_tx = B43legacy_ANTENNA_DEFAULT; + antenna_rx = B43legacy_ANTENNA_DEFAULT; mutex_lock(&wl->mutex); dev = wl->current_dev; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b1dc10c..b3e75eb 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1198,8 +1198,7 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - priv->rx_antenna = (conf->antenna_sel_rx == 0) ? - 2 : conf->antenna_sel_tx - 1; + priv->rx_antenna = 2; /* automatic */ priv->output_power = conf->power_level << 2; ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 4d5e87b..7910147 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -199,23 +199,15 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, * to work with untill the link tuner decides that an antenna * switch should be performed. */ - if (!conf->antenna_sel_rx && - default_ant->rx != ANTENNA_SW_DIVERSITY && + if (default_ant->rx != ANTENNA_SW_DIVERSITY && default_ant->rx != active_ant->rx) flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_rx && - conf->antenna_sel_rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; else if (active_ant->rx == ANTENNA_SW_DIVERSITY) flags |= CONFIG_UPDATE_ANTENNA; - if (!conf->antenna_sel_tx && - default_ant->tx != ANTENNA_SW_DIVERSITY && + if (default_ant->tx != ANTENNA_SW_DIVERSITY && default_ant->tx != active_ant->tx) flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_tx && - conf->antenna_sel_tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; else if (active_ant->tx == ANTENNA_SW_DIVERSITY) flags |= CONFIG_UPDATE_ANTENNA; @@ -252,18 +244,14 @@ config: } if (flags & CONFIG_UPDATE_ANTENNA) { - if (conf->antenna_sel_rx) - libconf.ant.rx = conf->antenna_sel_rx; - else if (default_ant->rx != ANTENNA_SW_DIVERSITY) + if (default_ant->rx != ANTENNA_SW_DIVERSITY) libconf.ant.rx = default_ant->rx; else if (active_ant->rx == ANTENNA_SW_DIVERSITY) libconf.ant.rx = ANTENNA_B; else libconf.ant.rx = active_ant->rx; - if (conf->antenna_sel_tx) - libconf.ant.tx = conf->antenna_sel_tx; - else if (default_ant->tx != ANTENNA_SW_DIVERSITY) + if (default_ant->tx != ANTENNA_SW_DIVERSITY) libconf.ant.tx = default_ant->tx; else if (active_ant->tx == ANTENNA_SW_DIVERSITY) libconf.ant.tx = ANTENNA_B; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 86840e3..9e0472b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -249,11 +249,9 @@ static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY; rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_rx == 0 && - rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_tx == 0 && - rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY; if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) && -- cgit v1.1 From e8975581f63870be42ff4662b293d1b0c8c21350 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Oct 2008 12:18:51 +0200 Subject: mac80211: introduce hw config change flags This makes mac80211 notify the driver which configuration actually changed, e.g. channel etc. No driver changes, this is just plumbing, driver authors are expected to act on this if they want to. Also remove the HW CONFIG debug printk, it's incorrect, often we configure something else. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 3 ++- drivers/net/wireless/ath5k/base.c | 7 +++---- drivers/net/wireless/ath9k/main.c | 4 ++-- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43legacy/main.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ++++--- drivers/net/wireless/libertas_tf/main.c | 4 +++- drivers/net/wireless/mac80211_hwsim.c | 4 ++-- drivers/net/wireless/p54/p54common.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 ++- drivers/net/wireless/rtl8180_dev.c | 3 ++- drivers/net/wireless/rtl8187_dev.c | 3 ++- drivers/net/wireless/zd1211rw/zd_mac.c | 4 +++- 16 files changed, 35 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 6e18c9d..9a1e0c5 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1314,9 +1314,10 @@ static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) return 0; } -static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int adm8211_config(struct ieee80211_hw *dev, u32 changed) { struct adm8211_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); if (channel != priv->channel) { diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 9e47d72..fcd6887 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -219,8 +219,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -static int ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static int ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); @@ -2780,10 +2779,10 @@ end: * TODO: Phy disable/diversity etc */ static int -ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +ath5k_config(struct ieee80211_hw *hw, u32 changed) { struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; sc->bintval = conf->beacon_int; sc->power_level = conf->power_level; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 5e087c9..f499107 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1230,11 +1230,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, __func__, error); } -static int ath9k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; struct ieee80211_channel *curchan = hw->conf.channel; + struct ieee80211_conf *conf = &hw->conf; int pos; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6b85428..2e81af1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3320,11 +3320,12 @@ init_failure: return err; } -static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int b43_op_config(struct ieee80211_hw *hw, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int antenna; int err = 0; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 867f01c..793cc39 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2557,11 +2557,12 @@ init_failure: } static int b43legacy_op_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) + u32 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; struct b43legacy_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; unsigned int new_phymode = 0xFFFF; int antenna_tx; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e6695e8..79a2441 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2734,10 +2734,11 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; u16 channel; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d3a2966..b1464c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6415,7 +6415,7 @@ static void iwl3945_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); static void iwl3945_bg_scan_completed(struct work_struct *work) { @@ -6428,7 +6428,7 @@ static void iwl3945_bg_scan_completed(struct work_struct *work) return; if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + iwl3945_mac_config(priv->hw, 0); ieee80211_scan_completed(priv->hw); @@ -6616,10 +6616,11 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl3945_priv *priv = hw->priv; const struct iwl3945_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index feff945..241ddcf 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -354,9 +354,11 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) { struct lbtf_private *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + if (conf->channel->center_freq != priv->cur_freq) { priv->cur_freq = conf->channel->center_freq; lbtf_set_channel(priv, conf->channel->hw_value); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 3f236b5..e2aeef8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -359,10 +359,10 @@ static void mac80211_hwsim_beacon(unsigned long arg) } -static int mac80211_hwsim_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_conf *conf = &hw->conf; printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", wiphy_name(hw->wiphy), __func__, diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b3e75eb..b3c297e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1192,10 +1192,11 @@ static void p54_remove_interface(struct ieee80211_hw *dev, p54_set_filter(dev, 0, NULL); } -static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int p54_config(struct ieee80211_hw *dev, u32 changed) { int ret; struct p54_common *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; mutex_lock(&priv->conf_mutex); priv->rx_antenna = 2; /* automatic */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1359a37..8ec8f7e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -997,7 +997,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9e0472b..697806cf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1245,7 +1245,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + retval = rt2x00mac_config(rt2x00dev->hw, ~0); if (retval) goto exit; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2c6cc5c..da7b49a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -335,9 +335,10 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_conf *conf = &hw->conf; int radio_on; int status; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 9de8f57..e8d2239 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -692,9 +692,10 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, priv->vif = NULL; } -static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8180_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; priv->rf->set_chan(dev, conf); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 9ceae90..2c69ab3 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -873,9 +873,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, mutex_unlock(&priv->conf_mutex); } -static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8187_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; u32 reg; mutex_lock(&priv->conf_mutex); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index de45509..6c3e218 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -743,9 +743,11 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, zd_write_mac_addr(&mac->chip, NULL); } -static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int zd_op_config(struct ieee80211_hw *hw, u32 changed) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_conf *conf = &hw->conf; + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } -- cgit v1.1 From 2e20cc3986cbee410fbe8e3e116bdcb12d70fcce Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 9 Oct 2008 17:38:52 -0700 Subject: p54: Move rx_mtu to struct bootrec_desc The patch entitled "[PATCH] p54: Fix sparse warnings" added the __le16 variable rx_mtu to struct bootrec, but it could equally well be placed in the struct bootrec_desc, which overlays the 'data' section of bootrec. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 2 +- drivers/net/wireless/p54/p54common.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b3c297e..f8cdd88 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -183,7 +183,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; if (le32_to_cpu(bootrec->len) == 11) - priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu); + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else priv->rx_mtu = (size_t) 0x620 - priv->tx_hdr_len; diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 2fa994c..22af41c 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -19,7 +19,6 @@ struct bootrec { __le32 code; __le32 len; u32 data[10]; - __le16 rx_mtu; } __attribute__((packed)); struct bootrec_exp_if { @@ -39,6 +38,8 @@ struct bootrec_desc { u8 tailroom; u8 unimportant[6]; u8 rates[16]; + u8 padding2[4]; + __le16 rx_mtu; } __attribute__((packed)); #define BR_CODE_MIN 0x80000000 -- cgit v1.1 From 94778280fabdb6bc76db5509bd95859f1141385b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Oct 2008 13:21:59 +0200 Subject: mac80211: provide sequence numbers I've come to think that not providing sequence numbers for the normal STA mode case was a mistake, at least two drivers now had to implement code they wouldn't otherwise need, and I believe at76_usb and adm8211 might be broken. This patch makes mac80211 assign a sequence number to all those frames that need one except beacons. That means that if a driver only implements modes that do not do beaconing it need not worry about the sequence number. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 - drivers/net/wireless/p54/p54common.c | 18 +++++------------- drivers/net/wireless/rtl8187.h | 1 - drivers/net/wireless/rtl8187_dev.c | 18 ++++-------------- 4 files changed, 9 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 8da4d30..1da96fe 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -67,7 +67,6 @@ struct p54_common { int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u16 seqno; u16 rx_mtu; u8 headroom; u8 tailroom; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index f8cdd88..7c37d3f 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -856,19 +856,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (padding) txhdr->align[0] = padding; - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } /* modifies skb->cb and with it info, so must be last! */ p54_assign_address(dev, skb, hdr, skb->len); @@ -1392,6 +1379,11 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + /* + * XXX: when this driver gets support for any mode that + * requires beacons (AP, MESH, IBSS) then it must + * implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index e82bb4d..33725d0 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -100,7 +100,6 @@ struct rtl8187_priv { struct usb_device *udev; u32 rx_conf; u16 txpwr_base; - u16 seqno; u8 asic_rev; u8 is_rtl8187b; enum { diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 2c69ab3..16f2fe2 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -241,20 +241,6 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } - info->driver_data[0] = dev; info->driver_data[1] = urb; @@ -1187,6 +1173,10 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->max_signal = 65; } + /* + * XXX: Once this driver supports anything that requires + * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) -- cgit v1.1 From 525181891fb5ed323b6ba0f141c422f1395acfb9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 11 Oct 2008 01:46:25 +0200 Subject: iwl3945: fix station stuff in RC algorithm Probably bugs I added. Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index bb91353..c25daec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -826,13 +826,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); - psta = (void *) sta->drv_priv; - if (!sta || !psta) { - IWL_DEBUG_RATE("leave - no private rate data!\n"); + if (!sta) { rcu_read_unlock(); return; } + psta = (void *) sta->drv_priv; rs_sta = psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); @@ -856,7 +855,6 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) break; } - rcu_read_unlock(); spin_unlock_irqrestore(&rs_sta->lock, flags); rssi = priv->last_rx_rssi; @@ -870,6 +868,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) IWL_DEBUG_RATE("leave: rssi %d assign rate index: " "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, iwl3945_rates[rs_sta->start_rate].plcp); + rcu_read_unlock(); } int iwl3945_rate_control_register(void) -- cgit v1.1 From 9124b07740c51cbc6e358dd0c4abc6ee8ded084d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Oct 2008 19:17:54 +0200 Subject: mac80211: make retry limits part of hw config Instead of having a separate callback, use the HW config callback with a new flag to change retry limits. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 1 - drivers/net/wireless/b43/main.c | 60 +++++++++++++-------------------- drivers/net/wireless/b43legacy/main.c | 59 ++++++++++++-------------------- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 3 ++ drivers/net/wireless/rt2x00/rt2x00mac.c | 9 +++++ drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 9 files changed, 61 insertions(+), 79 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f499107..41cd114 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1659,7 +1659,6 @@ static struct ieee80211_ops ath9k_ops = { .get_tkip_seq = NULL, .set_rts_threshold = NULL, .set_frag_threshold = NULL, - .set_retry_limit = NULL, .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, .tx_last_beacon = NULL, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2e81af1..9aeeb65 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3320,6 +3320,22 @@ init_failure: return err; } +/* Write the short and long frame retry limit values. */ +static void b43_set_retry_limits(struct b43_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, + short_retry); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, + long_retry); +} + static int b43_op_config(struct ieee80211_hw *hw, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); @@ -3340,6 +3356,13 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) dev = wl->current_dev; phy = &dev->phy; + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + b43_set_retry_limits(dev, conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + goto out_unlock_mutex; + /* Disable IRQs while reconfiguring the device. * This makes it possible to drop the spinlock throughout * the reconfiguration process. */ @@ -3859,22 +3882,6 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } -/* Write the short and long frame retry limit values. */ -static void b43_set_retry_limits(struct b43_wldev *dev, - unsigned int short_retry, - unsigned int long_retry) -{ - /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. */ - short_retry = min(short_retry, (unsigned int)0xF); - long_retry = min(long_retry, (unsigned int)0xF); - - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, - short_retry); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, - long_retry); -} - static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) { u16 pu_delay; @@ -4195,26 +4202,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&(wl->txpower_adjust_work)); } -static int b43_op_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry_limit, u32 long_retry_limit) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; - int err = 0; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) { - err = -ENODEV; - goto out_unlock; - } - b43_set_retry_limits(dev, short_retry_limit, long_retry_limit); -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { @@ -4251,7 +4238,6 @@ static const struct ieee80211_ops b43_hw_ops = { .get_tx_stats = b43_op_get_tx_stats, .start = b43_op_start, .stop = b43_op_stop, - .set_retry_limit = b43_op_set_retry_limit, .set_tim = b43_op_beacon_set_tim, .sta_notify = b43_op_sta_notify, }; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 793cc39..78e4636 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2556,6 +2556,20 @@ init_failure: return err; } +/* Write the short and long frame retry limit values. */ +static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); +} + static int b43legacy_op_dev_config(struct ieee80211_hw *hw, u32 changed) { @@ -2577,6 +2591,14 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, dev = wl->current_dev; phy = &dev->phy; + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + b43legacy_set_retry_limits(dev, + conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + goto out_unlock_mutex; + /* Switch the PHY mode (if necessary). */ switch (conf->channel->band) { case IEEE80211_BAND_2GHZ: @@ -2989,20 +3011,6 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } -/* Write the short and long frame retry limit values. */ -static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, - unsigned int short_retry, - unsigned int long_retry) -{ - /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. */ - short_retry = min(short_retry, (unsigned int)0xF); - long_retry = min(long_retry, (unsigned int)0xF); - - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); -} - static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; @@ -3367,28 +3375,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } -static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry_limit, - u32 long_retry_limit) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev; - int err = 0; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (unlikely(!dev || - (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) { - err = -ENODEV; - goto out_unlock; - } - b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit); -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { @@ -3414,7 +3400,6 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .get_tx_stats = b43legacy_op_get_tx_stats, .start = b43legacy_op_start, .stop = b43legacy_op_stop, - .set_retry_limit = b43legacy_op_set_retry_limit, .set_tim = b43legacy_op_beacon_set_tim, }; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 96eaf5f..1adca7a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1574,7 +1574,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt2400pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1603,6 +1602,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .config_intf = rt2400pci_config_intf, .config_erp = rt2400pci_config_erp, .config = rt2400pci_config, + .set_retry_limit = rt2400pci_set_retry_limit, }; static const struct data_queue_desc rt2400pci_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 8b772ab..85b0387 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1874,7 +1874,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt2500pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1903,6 +1902,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .config_intf = rt2500pci_config_intf, .config_erp = rt2500pci_config_erp, .config = rt2500pci_config, + .set_retry_limit = rt2500pci_set_retry_limit, }; static const struct data_queue_desc rt2500pci_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8ec8f7e..0887e89 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -599,6 +599,9 @@ struct rt2x00lib_ops { #define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 ) #define CONFIG_UPDATE_BEACON_INT ( 1 << 6 ) #define CONFIG_UPDATE_ALL 0xffff + + int (*set_retry_limit) (struct ieee80211_hw *hw, + u32 short_limit, u32 long_limit); }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index da7b49a..9311833 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -349,6 +349,15 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + rt2x00dev->ops->lib->set_retry_limit(hw, + conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + } + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + return 0; + /* * Only change device state when the radio is enabled. It does not * matter what parameters we have configured when the radio is disabled diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 45f69f8..08eb896 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2724,7 +2724,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -2757,6 +2756,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .config_intf = rt61pci_config_intf, .config_erp = rt61pci_config_erp, .config = rt61pci_config, + .set_retry_limit = rt61pci_set_retry_limit, }; static const struct data_queue_desc rt61pci_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 336fecb..7f89782 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2315,7 +2315,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -2347,6 +2346,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, .config = rt73usb_config, + .set_retry_limit = rt73usb_set_retry_limit, }; static const struct data_queue_desc rt73usb_queue_rx = { -- cgit v1.1 From ae5eb02641233a4e9d1b92d22090f1b1afa14466 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Oct 2008 16:58:37 +0200 Subject: mac80211: rewrite HT handling The HT handling has the following deficiencies, which I've (partially) fixed: * it always uses the AP info even if there is no AP, hence has no chance of working as an AP * it pretends to be HW config, but really is per-BSS * channel sanity checking is left to the drivers * it generally lets the driver control too much HT enabling is still wrong with this patch if you have more than one virtual STA mode interface, but that never happens currently. Once WDS, IBSS or AP/VLAN gets HT capabilities, it will also be wrong, see the comment in ieee80211_enable_ht(). Additionally, this fixes a number of bugs: * mac80211: ieee80211_set_disassoc doesn't notify the driver any more since the refactoring * iwl-agn-rs: always uses the HT capabilities from the wrong stuff mac80211 gives it rather than the actual peer STA * ath9k: a number of bugs resulting from the broken HT API I'm not entirely happy with putting the HT capabilities into struct ieee80211_sta as restricted to our own HT TX capabilities, but I see no cleaner solution for now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 6 ++--- drivers/net/wireless/ath9k/main.c | 41 +++++++++++++++---------------- drivers/net/wireless/ath9k/rc.c | 8 +++--- drivers/net/wireless/ath9k/recv.c | 3 +-- drivers/net/wireless/ath9k/xmit.c | 17 +++++++------ drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 23 ++++++++--------- drivers/net/wireless/iwlwifi/iwl-agn.c | 39 +++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.c | 17 +++---------- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-sta.c | 33 ++++++++++++++++--------- 10 files changed, 100 insertions(+), 88 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index cb3e61e..59d835b 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -380,7 +380,6 @@ void ath_rx_cleanup(struct ath_softc *sc); int ath_rx_tasklet(struct ath_softc *sc, int flush); int ath_rx_input(struct ath_softc *sc, struct ath_node *node, - int is_ampdu, struct sk_buff *skb, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status); @@ -650,6 +649,9 @@ struct ath_node { u8 an_smmode; /* SM Power save mode */ u8 an_flags; u8 an_addr[ETH_ALEN]; + + u16 maxampdu; + u8 mpdudensity; }; void ath_tx_resume_tid(struct ath_softc *sc, @@ -919,8 +921,6 @@ enum RATE_TYPE { struct ath_ht_info { enum ath9k_ht_macmode tx_chan_width; - u16 maxampdu; - u8 mpdudensity; u8 ext_chan_offset; }; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 41cd114..7555c34 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -330,25 +330,15 @@ static void ath9k_ht_conf(struct ath_softc *sc, { struct ath_ht_info *ht_info = &sc->sc_ht_info; - if (bss_conf->assoc_ht) { - ht_info->ext_chan_offset = - bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_PARAM_CHA_SEC_OFFSET; - - if (!(bss_conf->ht_cap->cap & - IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) + if (sc->hw->conf.ht.enabled) { + ht_info->ext_chan_offset = bss_conf->ht.secondary_channel_offset; + + if (bss_conf->ht.width_40_ok) ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; else ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); - ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - bss_conf->ht_cap->ampdu_factor); - ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_cap->ampdu_density); - } } @@ -390,7 +380,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; /* Update chainmask */ - ath_update_chainmask(sc, bss_conf->assoc_ht); + ath_update_chainmask(sc, hw->conf.ht.enabled); DPRINTF(sc, ATH_DBG_CONFIG, "%s: bssid %pM aid 0x%x\n", @@ -408,7 +398,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, return; } - if (hw->conf.ht_cap.ht_supported) + if (hw->conf.ht.enabled) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); else @@ -531,7 +521,6 @@ int _ath_rx_indicate(struct ath_softc *sc, if (an) { ath_rx_input(sc, an, - hw->conf.ht_cap.ht_supported, skb, status, &st); } if (!an || (st != ATH_RX_CONSUMED)) @@ -1241,6 +1230,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) __func__, curchan->center_freq); + /* Update chainmask */ + ath_update_chainmask(sc, conf->ht.enabled); + pos = ath_get_channel(sc, curchan); if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); @@ -1251,7 +1243,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - if (sc->sc_curaid && hw->conf.ht_cap.ht_supported) + if (sc->sc_curaid && hw->conf.ht.enabled) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); @@ -1434,6 +1426,14 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } else { ath_node_get(sc, sta->addr); } + + /* XXX: Is this right? Can the capabilities change? */ + an = ath_node_find(sc, sta->addr); + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = + parse_mpdudensity(sta->ht_cap.ampdu_density); + spin_unlock_irqrestore(&sc->node_lock, flags); break; case STA_NOTIFY_REMOVE: @@ -1552,9 +1552,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n", - __func__, - bss_conf->assoc_ht); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT\n", + __func__); ath9k_ht_conf(sc, bss_conf); } diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index ee2dbce..9b25260 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1838,7 +1838,7 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) struct ath_softc *sc = hw->priv; u32 capflag = 0; - if (hw->conf.ht_cap.ht_supported) { + if (hw->conf.ht.enabled) { capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) capflag |= ATH_RC_CW40_FLAG; @@ -1979,7 +1979,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, /* Check if aggregation has to be enabled for this tid */ - if (hw->conf.ht_cap.ht_supported) { + if (hw->conf.ht.enabled) { if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; @@ -2026,9 +2026,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); ath_setup_rates(sc, sband, sta, ath_rc_priv); - if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + if (sc->hw->conf.ht.enabled) { for (i = 0; i < 77; i++) { - if (sc->hw->conf.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) + if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 010fcdf..8283228 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -720,12 +720,11 @@ void ath_flushrecv(struct ath_softc *sc) int ath_rx_input(struct ath_softc *sc, struct ath_node *an, - int is_ampdu, struct sk_buff *skb, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status) { - if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { + if (sc->sc_flags & SC_OP_RXAGGR) { *status = ATH_RX_CONSUMED; return ath_ampdu_input(sc, an, skb, rx_status); } else { diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3770fbe..ba818cc 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -300,7 +300,8 @@ static int ath_tx_prepare(struct ath_softc *sc, if (ieee80211_is_data(fc) && !txctl->use_minrate) { /* Enable HT only for DATA frames and not for EAPOL */ - txctl->ht = (hw->conf.ht_cap.ht_supported && + /* XXX why AMPDU only?? */ + txctl->ht = (hw->conf.ht.enabled && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); if (is_multicast_ether_addr(hdr->addr1)) { @@ -1450,7 +1451,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, */ static u32 ath_lookup_rate(struct ath_softc *sc, - struct ath_buf *bf) + struct ath_buf *bf, + struct ath_atx_tid *tid) { const struct ath9k_rate_table *rt = sc->sc_currates; struct sk_buff *skb; @@ -1504,7 +1506,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, * The IE, however can hold upto 65536, which shows up here * as zero. Ignore 65536 since we are constrained by hw. */ - maxampdu = sc->sc_ht_info.maxampdu; + maxampdu = tid->an->maxampdu; if (maxampdu) aggr_limit = min(aggr_limit, maxampdu); @@ -1518,6 +1520,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, */ static int ath_compute_num_delims(struct ath_softc *sc, + struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) { @@ -1545,7 +1548,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, * required minimum length for subframe. Take into account * whether high rate is 20 or 40Mhz and half or full GI. */ - mpdudensity = sc->sc_ht_info.mpdudensity; + mpdudensity = tid->an->mpdudensity; /* * If there is no mpdu density restriction, no further calculation @@ -1619,7 +1622,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } if (!rl) { - aggr_limit = ath_lookup_rate(sc, bf); + aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; /* * Is rate dual stream @@ -1657,7 +1660,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * Get the delimiters needed to meet the MPDU * density for this node. */ - ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen); + ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); bpad = PADBYTES(al_delta) + (ndelim << 2); @@ -2629,7 +2632,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) struct ath_atx_ac *ac; int tidno, acno; - sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT; + an->maxampdu = ATH_AMPDU_LIMIT_DEFAULT; /* * Init per tid tx state diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index cd1bff5..e10e0ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1133,8 +1133,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s32 rate; s8 is_green = lq_sta->is_green; - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_cap.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) @@ -1201,8 +1200,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, u8 is_green = lq_sta->is_green; s32 rate; - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_cap.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); @@ -2001,9 +1999,8 @@ lq_update: * stay with best antenna legacy modulation for a while * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(tbl1->lq_type) && - (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && - (lq_sta->action_counter >= 1)) { + if (is_legacy(tbl1->lq_type) && !conf->ht.enabled && + lq_sta->action_counter >= 1) { lq_sta->action_counter = 0; IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); rs_set_stay_in_table(priv, 1, lq_sta); @@ -2238,19 +2235,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = conf->ht_cap.mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= conf->ht_cap.mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = conf->ht_cap.mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= conf->ht_cap.mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = conf->ht_cap.mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= conf->ht_cap.mcs.rx_mask[2] & 0x1; + lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 79a2441..7c3eb3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -552,17 +552,30 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) static void iwl4965_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_sta_ht_cap *ht_conf = bss_conf->ht_cap; - struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct ieee80211_sta_ht_cap *ht_conf; struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct ieee80211_sta *sta; IWL_DEBUG_MAC80211("enter: \n"); - iwl_conf->is_ht = bss_conf->assoc_ht; - if (!iwl_conf->is_ht) return; + + /* + * It is totally wrong to base global information on something + * that is valid only when associated, alas, this driver works + * that way and I don't know how to fix it. + */ + + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + ht_conf = &sta->ht_cap; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) iwl_conf->sgf |= HT_SHORT_GI_20MHZ; if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) @@ -574,8 +587,8 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, iwl_conf->supported_chan_width = !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; + + iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset; /* If no above or below channel supplied disable FAT channel */ if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { @@ -587,15 +600,14 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY); + iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok; iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_PROTECTION; + bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + rcu_read_unlock(); - IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); IWL_DEBUG_MAC80211("leave\n"); } @@ -2746,6 +2758,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); + priv->current_ht_config.is_ht = conf->ht.enabled; + if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); goto out; @@ -3104,7 +3118,6 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_HT) { - IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); iwl4965_ht_conf(priv, bss_conf); iwl_set_rxon_chain(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4678da4..10f5a0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -637,8 +637,8 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, } return iwl_is_channel_extension(priv, priv->band, - iwl_ht_conf->control_channel, - iwl_ht_conf->extension_chan_offset); + le16_to_cpu(priv->staging_rxon.channel), + iwl_ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); @@ -663,13 +663,6 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); - if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { - IWL_DEBUG_ASSOC("control diff than current %d %d\n", - le16_to_cpu(rxon->channel), - ht_info->control_channel); - return; - } - /* Note: control channel is opposite of extension channel */ switch (ht_info->extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: @@ -692,14 +685,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " - "extension channel offset 0x%x " - "control chan %d\n", + "extension channel offset 0x%x\n", ht_info->mcs.rx_mask[0], ht_info->mcs.rx_mask[1], ht_info->mcs.rx_mask[2], le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset, - ht_info->control_channel); + ht_info->extension_chan_offset); return; } EXPORT_SYMBOL(iwl_set_rxon_ht); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 572250e..2e95149 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -413,7 +413,6 @@ struct iwl_ht_info { u8 mpdu_density; struct ieee80211_mcs_info mcs; /* BSS related data */ - u8 control_channel; u8 extension_chan_offset; u8 tx_chan_width; u8 ht_protection; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b9b8554..218483d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -890,20 +890,31 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) */ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { + struct ieee80211_sta *sta; + struct ieee80211_sta_ht_cap ht_config; + struct ieee80211_sta_ht_cap *cur_ht_config = NULL; u8 sta_id; /* Add station to device's station table */ - struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_sta_ht_cap *cur_ht_config = &conf->ht_cap; - - if ((is_ap) && - (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == NL80211_IFTYPE_STATION)) - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); - else - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, NULL); + + /* + * XXX: This check is definitely not correct, if we're an AP + * it'll always be false which is not what we want, but + * it doesn't look like iwlagn is prepared to be an HT + * AP anyway. + */ + if (priv->current_ht_config.is_ht) { + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, addr); + if (sta) { + memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); + cur_ht_config = &ht_config; + } + rcu_read_unlock(); + } + + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); /* Set up default rate scaling table in device's station table */ iwl_sta_init_lq(priv, addr, is_ap); -- cgit v1.1 From 7eb27af766e4a1db3dbc02a5b3d175885bf2ce93 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 12 Oct 2008 00:39:55 +0200 Subject: p54/rtl8187: fix up the seqno patch Sorry about that, for some reason I didn't notice that I'd left some unused variables in there. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 1 - drivers/net/wireless/rtl8187_dev.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7c37d3f..81a9756 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -802,7 +802,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct p54_tx_control_allocdata *txhdr; size_t padding, len; u8 rate; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 16f2fe2..b211a51 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -175,7 +175,6 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; unsigned int ep; void *buf; struct urb *urb; -- cgit v1.1 From da966bcae70e4012b7d999820b728dd6502047e0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 12 Oct 2008 22:54:10 +0200 Subject: Ath5k: add AP mode Add support for AP mode. This involves: - enablement in ath5k_beacon_config -- initialize beacon timer - add AP to the supported modes in ath5k_add_interface - handle beacon change even for AP in ath5k_config_interface - remove useless test for IBSS in ath5k_beacon_update Note that it doesn't enable the AP mode for the driver. It must be enabled by NL80211_IFTYPE_AP bit added to interface_modes. v2: Fixed opmode constant (IEEE80211_ to NL80211_) Signed-off-by: Jiri Slaby Cc: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 42 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index fcd6887..c983808 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -237,8 +237,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb); +static int ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb); static struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -2137,8 +2136,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) * * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA * interrupts to detect TSF updates only. - * - * AP mode is missing. */ static void ath5k_beacon_config(struct ath5k_softc *sc) @@ -2151,7 +2148,8 @@ ath5k_beacon_config(struct ath5k_softc *sc) if (sc->opmode == NL80211_IFTYPE_STATION) { sc->imask |= AR5K_INT_BMISS; - } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_AP) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2163,13 +2161,15 @@ ath5k_beacon_config(struct ath5k_softc *sc) sc->imask |= AR5K_INT_SWBA; - if (ath5k_hw_hasveol(ah)) { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + if (ath5k_hw_hasveol(ah)) { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } + } else + ath5k_beacon_update_timers(sc, -1); } - /* TODO else AP */ ath5k_hw_set_imr(ah, sc->imask); } @@ -2740,6 +2740,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->vif = conf->vif; switch (conf->type) { + case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MONITOR: @@ -2803,7 +2804,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ret = -EIO; goto unlock; } - if (conf->bssid) { + if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { /* Cache for later use during resets */ memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); /* XXX: assoc id is set to 0 for now, mac80211 doesn't have @@ -2811,18 +2812,16 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath5k_hw_set_associd(ah, ah->ah_bssid, 0); mmiowb(); } - if (conf->changed & IEEE80211_IFCC_BEACON && - vif->type == NL80211_IFTYPE_ADHOC) { + (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_AP)) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) { ret = -ENOMEM; goto unlock; } - /* call old handler for now */ - ath5k_beacon_update(hw, beacon); + ath5k_beacon_update(sc, beacon); } - mutex_unlock(&sc->lock); return ath5k_reset_wake(sc); @@ -3052,19 +3051,13 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) { - struct ath5k_softc *sc = hw->priv; unsigned long flags; int ret; ath5k_debug_dump_skb(sc, skb, "BC ", 1); - if (sc->opmode != NL80211_IFTYPE_ADHOC) { - ret = -EIO; - goto end; - } - spin_lock_irqsave(&sc->block, flags); ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; @@ -3077,7 +3070,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) mmiowb(); } -end: return ret; } -- cgit v1.1 From 64761077f815660276f69b497edb9842d880df9a Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 13 Oct 2008 18:10:59 +0000 Subject: rtl8187: adapt for deprecated IEEE80211_CONF_SHORT_SLOT_TIME flag This updates 8187L handling for short slot after "mac80211: fix short slot handling". For 8187B, there was no handling done for short slot timing so nothing done, support for it will come in a following patch. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index b211a51..991d65c 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -877,22 +877,6 @@ static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) msleep(10); rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - if (!priv->is_rtl8187b) { - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } - } - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); @@ -927,6 +911,35 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, return 0; } +static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot) +{ + if (!priv->is_rtl8187b) { + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + if (use_short_slot) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } + } +} + +static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT) + rtl8187_conf_erp(priv, info->use_short_slot); +} + static void rtl8187_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -967,6 +980,7 @@ static const struct ieee80211_ops rtl8187_ops = { .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .config_interface = rtl8187_config_interface, + .bss_info_changed = rtl8187_bss_info_changed, .configure_filter = rtl8187_configure_filter, }; -- cgit v1.1 From f8288317b5076fde0bb4e91cd4754379c850be7a Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 13 Oct 2008 18:11:00 +0000 Subject: rtl8187: add short slot handling for 8187B This change adds short slot handling for 8187B variant of rtl8187 chips. Some things to note about changes done: * Values used are chosen to met 802.11-2007 spec. This raised a question about SIFS value used with 8187L: 0x22 (34) doesn't match any spec value. For now just don't change 8187L, but is something to be looked at. * On 8187B, the location of EIFS register is at the same place as BRSR+1 of struct rtl818x_csr. Unfortunately there is no clean way to accomodate 8187B differences currently, just use address of BRSR+1 and comment about it. The same thing happens for Ack timeout register, that is on CARRIER_SENSE_COUNTER location of 8187L. The eifs and ack timeout values are in units of 4us. All these registers information was gathered from references being the vendor gpl driver and 8180 datasheet, unfortunately there is no information about this on 8187B datasheet. Also the ack timeout value was inspired by the same calculation as done on rt2x00. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 45 +++++++++++++++++++++++++++++++--- drivers/net/wireless/rtl8187_rtl8225.c | 8 ------ 2 files changed, 41 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 991d65c..cd839bc 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -911,9 +911,45 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, return 0; } -static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot) +static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, + bool use_short_preamble) { - if (!priv->is_rtl8187b) { + if (priv->is_rtl8187b) { + u8 difs, eifs, slot_time; + u16 ack_timeout; + + if (use_short_slot) { + slot_time = 0x9; + difs = 0x1c; + eifs = 0x53; + } else { + slot_time = 0x14; + difs = 0x32; + eifs = 0x5b; + } + rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); + rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); + rtl818x_iowrite8(priv, &priv->map->DIFS, difs); + + /* + * BRSR+1 on 8187B is in fact EIFS register + * Value in units of 4 us + */ + rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); + + /* + * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout + * register. In units of 4 us like eifs register + * ack_timeout = ack duration + plcp + difs + preamble + */ + ack_timeout = 112 + 48 + difs; + if (use_short_preamble) + ack_timeout += 72; + else + ack_timeout += 144; + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, + DIV_ROUND_UP(ack_timeout, 4)); + } else { rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); if (use_short_slot) { rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); @@ -936,8 +972,9 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, { struct rtl8187_priv *priv = dev->priv; - if (changed & BSS_CHANGED_ERP_SLOT) - rtl8187_conf_erp(priv, info->use_short_slot); + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) + rtl8187_conf_erp(priv, info->use_short_slot, + info->use_short_preamble); } static void rtl8187_configure_filter(struct ieee80211_hw *dev, diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 1bae899..b999f87 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -885,14 +885,6 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->SLOT, 9); - rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28); - rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B); - rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B); rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); -- cgit v1.1 From c49d154a800c55b8948e6d34563e593b500b31b9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 13 Oct 2008 14:08:09 -0700 Subject: ath9k: correct signal quality report This adjusts ath9k's signal quality reporting taking into consideration received beacons at an RSSI of 45 should indicate you can use of MCS 15 rate (144 Mbps) reliably on dual stream card. Keep in mind mac80211 does not yet have aggregation fixed but this should still provide more accurate results. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7555c34..32acaf7 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -279,8 +279,15 @@ static void ath9k_rx_prepare(struct ath_softc *sc, rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); rx_status->antenna = status->antenna; - /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */ - rx_status->qual = status->rssi * 100 / 64; + /* at 45 you will be able to use MCS 15 reliably. A more elaborate + * scheme can be used here but it requires tables of SNR/throughput for + * each possible mode used. */ + rx_status->qual = status->rssi * 100 / 45; + + /* rssi can be more than 45 though, anything above that + * should be considered at 100% */ + if (rx_status->qual > 100) + rx_status->qual = 100; if (status->flags & ATH_RX_MIC_ERROR) rx_status->flag |= RX_FLAG_MMIC_ERROR; -- cgit v1.1 From 6e0e0bf80c963d83f511e1cda652630cf31ebf85 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 13 Oct 2008 14:08:10 -0700 Subject: ath5k: correct ath5k signal quality This adjusts ath5k's signal quality reporting taking into consideration received beacons at an RSSI of 35 should indicate you can use of 54 Mbps on a single stream card (all ath5k cards) reliably. Signed-off-by: Luis R. Rodriguez Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c983808..b1e9a47 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1778,7 +1778,17 @@ accept: rxs.noise = sc->ah->ah_noise_floor; rxs.signal = rxs.noise + rs.rs_rssi; - rxs.qual = rs.rs_rssi * 100 / 64; + + /* An rssi of 35 indicates you should be able use + * 54 Mbps reliably. A more elaborate scheme can be used + * here but it requires a map of SNR/throughput for each + * possible mode used */ + rxs.qual = rs.rs_rssi * 100 / 35; + + /* rssi can be more than 35 though, anything above that + * should be considered at 100% */ + if (rxs.qual > 100) + rxs.qual = 100; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); -- cgit v1.1 From b706e65b40417e03c2451bb3f92488f3736843fa Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Mon, 13 Oct 2008 18:23:07 -0700 Subject: ath5k: fix mesh point operation This patch fixes mesh point operation (thanks to YanBo for pointing out the problem): make mesh point interfaces start beaconing when they come up and configure the RX filter in mesh mode so that mesh beacons and action frames are received. Add mesh point to the check in ath5k_add_interface. Tested with multiple AR5211 cards. Signed-off-by: Andrey Yurovsky Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index b1e9a47..44401f6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2159,6 +2159,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) if (sc->opmode == NL80211_IFTYPE_STATION) { sc->imask |= AR5K_INT_BMISS; } else if (sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_MESH_POINT || sc->opmode == NL80211_IFTYPE_AP) { /* * In IBSS mode we use a self-linked tx descriptor and let the @@ -2753,6 +2754,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: sc->opmode = conf->type; break; @@ -2824,6 +2826,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (conf->changed & IEEE80211_IFCC_BEACON && (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_AP)) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) { @@ -2952,6 +2955,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, rfilt |= AR5K_RX_FILTER_PROM; if (sc->opmode == NL80211_IFTYPE_ADHOC) rfilt |= AR5K_RX_FILTER_BEACON; + if (sc->opmode == NL80211_IFTYPE_MESH_POINT) + rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; /* Set filters */ ath5k_hw_set_rx_filter(ah,rfilt); -- cgit v1.1 From faf3994a9f65fd95a68bbcc03c318a427cd1e7d3 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Tue, 14 Oct 2008 13:30:33 +0800 Subject: airo: Kill directly reference of netdev->priv We have some reasons to kill netdev->priv: 1. netdev->priv is equal to netdev_priv(). 2. netdev_priv() wraps the calculation of netdev->priv's offset, obviously netdev_priv() is more flexible than netdev->priv. But we cann't kill netdev->priv, because so many drivers reference to it directly. OK, becasue Dave S. Miller said, "every direct netdev->priv usage is a bug", and I want to kill netdev->priv later, I decided to convert all the direct reference of netdev->priv first. In this driver, I don't simply use netdev_priv() to replace netdev->priv. The reason is: Pointer netdev->priv was changed in this driver, but it shouldn't. Because the memory was allocated when alloc_netdev() and netdev->priv should always point to that memory. So I use netdev->ml_priv to replace netdev->priv. After replacing, both ai and ai->wifidev->ml_priv point to the same memory. Signed-off-by: Wang Chen Cc: John W. Linville Cc: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 171 ++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 85 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 7c99f5a..d7388d2 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1270,6 +1270,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev); #define airo_print_err(name, fmt, args...) \ airo_print(KERN_ERR, name, fmt, ##args) +#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) /*********************************************************************** * MIC ROUTINES * @@ -1865,7 +1866,7 @@ static void try_auto_wep(struct airo_info *ai) } static int airo_open(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int rc = 0; if (test_bit(FLAG_FLASHING, &ai->flags)) @@ -1912,7 +1913,7 @@ static int airo_open(struct net_device *dev) { static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { int npacks, pending; unsigned long flags; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (!skb) { airo_print_err(dev->name, "%s: skb == NULL!",__func__); @@ -1956,7 +1957,7 @@ static int mpi_send_packet (struct net_device *dev) unsigned char *buffer; s16 len; __le16 *payloadLen; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; u8 *sendbuf; /* get a packet to send */ @@ -2085,7 +2086,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid) static void airo_end_xmit(struct net_device *dev) { u16 status; int i; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; struct sk_buff *skb = priv->xmit.skb; int fid = priv->xmit.fid; u32 *fids = priv->fids; @@ -2111,7 +2112,7 @@ static void airo_end_xmit(struct net_device *dev) { static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; u32 *fids = priv->fids; if ( skb == NULL ) { @@ -2150,7 +2151,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { static void airo_end_xmit11(struct net_device *dev) { u16 status; int i; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; struct sk_buff *skb = priv->xmit11.skb; int fid = priv->xmit11.fid; u32 *fids = priv->fids; @@ -2176,7 +2177,7 @@ static void airo_end_xmit11(struct net_device *dev) { static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; u32 *fids = priv->fids; if (test_bit(FLAG_MPI, &priv->flags)) { @@ -2220,7 +2221,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { static void airo_read_stats(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; StatsRid stats_rid; __le32 *vals = stats_rid.vals; @@ -2254,7 +2255,7 @@ static void airo_read_stats(struct net_device *dev) static struct net_device_stats *airo_get_stats(struct net_device *dev) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit(JOB_STATS, &local->jobs)) { /* Get stats out of the card if available */ @@ -2281,7 +2282,7 @@ static void airo_set_promisc(struct airo_info *ai) { } static void airo_set_multicast_list(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if ((dev->flags ^ ai->flags) & IFF_PROMISC) { change_bit(FLAG_PROMISC, &ai->flags); @@ -2299,7 +2300,7 @@ static void airo_set_multicast_list(struct net_device *dev) { static int airo_set_mac_address(struct net_device *dev, void *p) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; struct sockaddr *addr = p; readConfigRid(ai, 1); @@ -2339,7 +2340,7 @@ static void del_airo_dev(struct airo_info *ai) } static int airo_close(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; netif_stop_queue(dev); @@ -2365,7 +2366,7 @@ static int airo_close(struct net_device *dev) { void stop_airo_card( struct net_device *dev, int freeres ) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; set_bit(FLAG_RADIO_DOWN, &ai->flags); disable_MAC(ai, 1); @@ -2665,7 +2666,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup); if (!dev) return NULL; - dev->priv = ethdev->priv; + dev->ml_priv = ethdev->ml_priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; dev->wireless_data = ethdev->wireless_data; @@ -2680,7 +2681,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, } static int reset_card( struct net_device *dev , int lock) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (lock && down_interruptible(&ai->sem)) return -1; @@ -2765,7 +2766,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, return NULL; } - ai = dev->priv; + ai = dev->ml_priv = netdev_priv(dev); ai->wifidev = NULL; ai->flags = 1 << FLAG_RADIO_DOWN; ai->jobs = 0; @@ -2866,7 +2867,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, for( i = 0; i < MAX_FIDS; i++ ) ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); - if (setup_proc_entry(dev, dev->priv) < 0) + if (setup_proc_entry(dev, dev->ml_priv) < 0) goto err_out_wifi; return dev; @@ -2915,7 +2916,7 @@ static int waitbusy (struct airo_info *ai) { int reset_airo_card( struct net_device *dev ) { int i; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (reset_card (dev, 1)) return -1; @@ -2938,7 +2939,7 @@ int reset_airo_card( struct net_device *dev ) EXPORT_SYMBOL(reset_airo_card); static void airo_send_event(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; union iwreq_data wrqu; StatusRid status_rid; @@ -3015,7 +3016,7 @@ out: static int airo_thread(void *data) { struct net_device *dev = data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int locked; set_freezable(); @@ -3130,7 +3131,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; u16 status; u16 fid; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; u16 savedInterrupts = 0; int handled = 0; @@ -4600,7 +4601,7 @@ static int proc_status_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; CapabilityRid cap_rid; StatusRid status_rid; u16 mode; @@ -4683,7 +4684,7 @@ static int proc_stats_rid_open( struct inode *inode, struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; StatsRid stats; int i, j; __le32 *vals = stats.vals; @@ -4746,7 +4747,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file) struct proc_data *data = file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *line; if ( !data->writelen ) return; @@ -4958,7 +4959,7 @@ static int proc_config_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; __le16 mode; @@ -5049,7 +5050,7 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file) struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; SsidRid SSID_rid; int i; char *p = data->wbuffer; @@ -5092,7 +5093,7 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) { struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; APListRid APList_rid; int i; @@ -5187,7 +5188,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char key[16]; u16 index = 0; @@ -5229,7 +5230,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *ptr; WepKeyRid wkr; __le16 lastindex; @@ -5278,7 +5279,7 @@ static int proc_SSID_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char *ptr; SsidRid SSID_rid; @@ -5322,7 +5323,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char *ptr; APListRid APList_rid; @@ -5362,7 +5363,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *ptr; BSSListRid BSSList_rid; int rc; @@ -5440,7 +5441,7 @@ static int proc_close( struct inode *inode, struct file *file ) associated we will check every minute to see if anything has changed. */ static void timer_func( struct net_device *dev ) { - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; /* We don't have a link so try changing the authtype */ readConfigRid(apriv, 0); @@ -5511,7 +5512,7 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev) static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; @@ -5543,7 +5544,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int airo_pci_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; pci_power_t prev_state = pdev->current_state; pci_set_power_state(pdev, PCI_D0); @@ -5722,7 +5723,7 @@ static int airo_set_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rc = -EINPROGRESS; /* Call commit handler */ /* If setting by frequency, convert to a channel */ @@ -5767,7 +5768,7 @@ static int airo_get_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ int ch; @@ -5798,7 +5799,7 @@ static int airo_set_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; SsidRid SSID_rid; /* SSIDs */ /* Reload the list of current SSID */ @@ -5844,7 +5845,7 @@ static int airo_get_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -5872,7 +5873,7 @@ static int airo_set_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; Cmd cmd; Resp rsp; APListRid APList_rid; @@ -5909,7 +5910,7 @@ static int airo_get_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -5930,7 +5931,7 @@ static int airo_set_nick(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; /* Check the size of the string */ if(dwrq->length > 16) { @@ -5953,7 +5954,7 @@ static int airo_get_nick(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); strncpy(extra, local->config.nodeName, 16); @@ -5972,7 +5973,7 @@ static int airo_set_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ u8 brate = 0; int i; @@ -6042,7 +6043,7 @@ static int airo_get_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -6064,7 +6065,7 @@ static int airo_set_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rthr = vwrq->value; if(vwrq->disabled) @@ -6088,7 +6089,7 @@ static int airo_get_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.rtsThres); @@ -6107,7 +6108,7 @@ static int airo_set_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int fthr = vwrq->value; if(vwrq->disabled) @@ -6132,7 +6133,7 @@ static int airo_get_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.fragThresh); @@ -6151,7 +6152,7 @@ static int airo_set_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int reset = 0; readConfigRid(local, 1); @@ -6214,7 +6215,7 @@ static int airo_get_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); /* If not managed, assume it's ad-hoc */ @@ -6251,7 +6252,7 @@ static int airo_set_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 ); __le16 currentAuthType = local->config.authType; @@ -6338,7 +6339,7 @@ static int airo_get_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; CapabilityRid cap_rid; /* Card capability info */ @@ -6386,7 +6387,7 @@ static int airo_set_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ @@ -6472,7 +6473,7 @@ static int airo_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ @@ -6535,7 +6536,7 @@ static int airo_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_param *param = &wrqu->param; __le16 currentAuthType = local->config.authType; @@ -6603,7 +6604,7 @@ static int airo_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_param *param = &wrqu->param; __le16 currentAuthType = local->config.authType; @@ -6652,7 +6653,7 @@ static int airo_set_txpow(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ int i; int rc = -EINVAL; @@ -6689,7 +6690,7 @@ static int airo_get_txpow(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.txPower); @@ -6709,7 +6710,7 @@ static int airo_set_retry(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rc = -EINVAL; if(vwrq->disabled) { @@ -6747,7 +6748,7 @@ static int airo_get_retry(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; vwrq->disabled = 0; /* Can't be disabled */ @@ -6778,7 +6779,7 @@ static int airo_get_range(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_range *range = (struct iw_range *) extra; CapabilityRid cap_rid; /* Card capability info */ int i; @@ -6903,7 +6904,7 @@ static int airo_set_power(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); if (vwrq->disabled) { @@ -6960,7 +6961,7 @@ static int airo_get_power(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; __le16 mode; readConfigRid(local, 1); @@ -6991,7 +6992,7 @@ static int airo_set_sens(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); local->config.rssiThreshold = @@ -7010,7 +7011,7 @@ static int airo_get_sens(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.rssiThreshold); @@ -7030,7 +7031,7 @@ static int airo_get_aplist(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct sockaddr *address = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; BSSListRid BSSList; @@ -7103,7 +7104,7 @@ static int airo_set_scan(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; int wake = 0; @@ -7149,7 +7150,7 @@ static inline char *airo_translate_scan(struct net_device *dev, char *end_buf, BSSListRid *bss) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; struct iw_event iwe; /* Temporary buffer */ __le16 capabilities; char * current_val; /* For rates */ @@ -7331,7 +7332,7 @@ static int airo_get_scan(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; BSSListElement *net; int err = 0; char *current_ev = extra; @@ -7375,7 +7376,7 @@ static int airo_config_commit(struct net_device *dev, void *zwrq, /* NULL */ char *extra) /* NULL */ { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit (FLAG_COMMIT, &local->flags)) return 0; @@ -7520,7 +7521,7 @@ static const struct iw_handler_def airo_handler_def = static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int rc = 0; - struct airo_info *ai = (struct airo_info *)dev->priv; + struct airo_info *ai = dev->ml_priv; if (ai->power.event) return 0; @@ -7648,7 +7649,7 @@ static void airo_read_wireless_stats(struct airo_info *local) static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit(JOB_WSTATS, &local->jobs)) { /* Get stats out of the card if available */ @@ -7673,7 +7674,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { unsigned short ridcode; unsigned char *iobuf; int len; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (test_bit(FLAG_FLASHING, &ai->flags)) return -EIO; @@ -7739,7 +7740,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { */ static int writerids(struct net_device *dev, aironet_ioctl *comp) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int ridcode; int enabled; static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); @@ -7862,41 +7863,41 @@ static int flashcard(struct net_device *dev, aironet_ioctl *comp) { switch(comp->command) { case AIROFLSHRST: - return cmdreset((struct airo_info *)dev->priv); + return cmdreset((struct airo_info *)dev->ml_priv); case AIROFLSHSTFL: - if (!((struct airo_info *)dev->priv)->flash && - (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL) + if (!AIRO_FLASH(dev) && + (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL) return -ENOMEM; - return setflashmode((struct airo_info *)dev->priv); + return setflashmode((struct airo_info *)dev->ml_priv); case AIROFLSHGCHR: /* Get char from aux */ if(comp->len != sizeof(int)) return -EINVAL; if (copy_from_user(&z,comp->data,comp->len)) return -EFAULT; - return flashgchar((struct airo_info *)dev->priv,z,8000); + return flashgchar((struct airo_info *)dev->ml_priv, z, 8000); case AIROFLSHPCHR: /* Send char to card. */ if(comp->len != sizeof(int)) return -EINVAL; if (copy_from_user(&z,comp->data,comp->len)) return -EFAULT; - return flashpchar((struct airo_info *)dev->priv,z,8000); + return flashpchar((struct airo_info *)dev->ml_priv, z, 8000); case AIROFLPUTBUF: /* Send 32k to card */ - if (!((struct airo_info *)dev->priv)->flash) + if (!AIRO_FLASH(dev)) return -ENOMEM; if(comp->len > FLASHSIZE) return -EINVAL; - if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len)) + if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len)) return -EFAULT; - flashputbuf((struct airo_info *)dev->priv); + flashputbuf((struct airo_info *)dev->ml_priv); return 0; case AIRORESTART: - if(flashrestart((struct airo_info *)dev->priv,dev)) + if (flashrestart((struct airo_info *)dev->ml_priv, dev)) return -EIO; return 0; } -- cgit v1.1 From e6a9854b05c1a6af1308fe2b8c68f35abf28a3ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Oct 2008 12:40:02 +0200 Subject: mac80211/drivers: rewrite the rate control API So after the previous changes we were still unhappy with how convoluted the API is and decided to make things simpler for everybody. This completely changes the rate control API, now taking into account 802.11n with MCS rates and more control, most drivers don't support that though. Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 21 +++++----- drivers/net/wireless/ath5k/base.c | 34 +++++++-------- drivers/net/wireless/ath9k/main.c | 18 ++++---- drivers/net/wireless/ath9k/rc.c | 40 +++++++++--------- drivers/net/wireless/ath9k/xmit.c | 28 +++++++++---- drivers/net/wireless/b43/dma.c | 4 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/pio.c | 3 +- drivers/net/wireless/b43/xmit.c | 60 +++++++++++++++++++++----- drivers/net/wireless/b43/xmit.h | 5 ++- drivers/net/wireless/b43legacy/dma.c | 46 +++++++++++++------- drivers/net/wireless/b43legacy/main.c | 2 +- drivers/net/wireless/b43legacy/pio.c | 31 +++++++++++++- drivers/net/wireless/b43legacy/xmit.c | 26 ++++++++---- drivers/net/wireless/b43legacy/xmit.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 57 ++++++++----------------- drivers/net/wireless/iwlwifi/iwl-3945.c | 65 ++++++++++++++++++++++++++--- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 + drivers/net/wireless/iwlwifi/iwl-4965.c | 8 ++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++-- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 37 ++++++++-------- drivers/net/wireless/iwlwifi/iwl-core.c | 19 +++++---- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ++- drivers/net/wireless/libertas_tf/main.c | 4 +- drivers/net/wireless/mac80211_hwsim.c | 12 ++---- drivers/net/wireless/p54/p54common.c | 26 ++++++------ drivers/net/wireless/rt2x00/rt2x00dev.c | 14 +++++-- drivers/net/wireless/rt2x00/rt2x00mac.c | 14 +++---- drivers/net/wireless/rt2x00/rt2x00queue.c | 22 ++++++++-- drivers/net/wireless/rt2x00/rt2x00queue.h | 9 +++- drivers/net/wireless/rtl8180_dev.c | 28 ++++++------- drivers/net/wireless/rtl8187_dev.c | 18 ++++---- drivers/net/wireless/zd1211rw/zd_mac.c | 32 +++++++------- drivers/net/wireless/zd1211rw/zd_usb.c | 2 +- 34 files changed, 427 insertions(+), 277 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 9a1e0c5..b96ebfe 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&txi->status, 0, sizeof(txi->status)); + ieee80211_tx_info_clear_status(txi); + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (status & TDES0_STATUS_ES) - txi->status.excessive_retries = 1; - else - txi->flags |= IEEE80211_TX_STAT_ACK; - } + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && + !(status & TDES0_STATUS_ES)) + txi->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; @@ -1691,8 +1690,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); + u8 rc_flags; - short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); + rc_flags = info->control.rates[0].flags; + short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; @@ -1724,10 +1725,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); - txhdr->retry_limit = info->control.retry_limit; + txhdr->retry_limit = info->control.rates[0].count; adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 44401f6..3773d98 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -541,8 +541,8 @@ ath5k_pci_probe(struct pci_dev *pdev, /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_altrates = 3; - hw->max_altrate_tries = 11; + hw->max_rates = 4; + hw->max_rate_tries = 11; } /* Finish private driver data initialization */ @@ -1181,7 +1181,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), ieee80211_get_tx_rate(sc->hw, info)->hw_value, - info->control.retry_limit, keyidx, 0, flags, 0, 0); + info->control.rates[0].count, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1193,7 +1193,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) break; mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.retries[i].limit; + mrr_tries[i] = info->control.rates[i + 1].count; } ah->ah_setup_mrr_tx_desc(ah, ds, @@ -1849,30 +1849,26 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - memset(&info->status, 0, sizeof(info->status)); - info->tx_rate_idx = ath5k_hw_to_driver_rix(sc, - ts.ts_rate[ts.ts_final_idx]); - info->status.retry_count = ts.ts_longretry; - + ieee80211_tx_info_clear_status(info); for (i = 0; i < 4; i++) { - struct ieee80211_tx_altrate *r = - &info->status.retries[i]; + struct ieee80211_tx_rate *r = + &info->status.rates[i]; if (ts.ts_rate[i]) { - r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); - r->limit = ts.ts_retry[i]; + r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); + r->count = ts.ts_retry[i]; } else { - r->rate_idx = -1; - r->limit = 0; + r->idx = -1; + r->count = 0; } } - info->status.excessive_retries = 0; + /* count the successful attempt as well */ + info->status.rates[ts.ts_final_idx].count++; + if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; - if (ts.ts_status & AR5K_TXERR_XRETRY) - info->status.excessive_retries = 1; - else if (ts.ts_status & AR5K_TXERR_FILT) + if (ts.ts_status & AR5K_TXERR_FILT) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { info->flags |= IEEE80211_TX_STAT_ACK; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 32acaf7..a7656a3 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -457,12 +457,13 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, DPRINTF(sc, ATH_DBG_XMIT, "%s: TX complete: skb: %p\n", __func__, skb); + ieee80211_tx_info_clear_status(tx_info); if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info */ - if (tx_info->driver_data[0] != NULL) - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; + /* free driver's private data area of tx_info, XXX: HACK! */ + if (tx_info->control.vif != NULL) + kfree(tx_info->control.vif); + tx_info->control.vif = NULL; } if (tx_status->flags & ATH_TX_BAR) { @@ -470,17 +471,12 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_status->flags &= ~ATH_TX_BAR; } - 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 { + if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { /* Frame was ACKed */ tx_info->flags |= IEEE80211_TX_STAT_ACK; } - tx_info->status.retry_count = tx_status->retries; + tx_info->status.rates[0].count = tx_status->retries + 1; ieee80211_tx_status(hw, skb); if (an) diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 9b25260..6afafed 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1864,24 +1864,21 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* XXX: UGLY HACK!! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; spin_lock_bh(&sc->node_lock); an = ath_node_find(sc, hdr->addr1); spin_unlock_bh(&sc->node_lock); - if (!an || !priv_sta || !ieee80211_is_data(fc)) { - if (tx_info->driver_data[0] != NULL) { - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } + if (tx_info_priv == NULL) return; - } - if (tx_info->driver_data[0] != NULL) { + + if (an && priv_sta && ieee80211_is_data(fc)) ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } + + kfree(tx_info_priv); + tx_info->control.vif = NULL; } static void ath_tx_aggr_resp(struct ath_softc *sc, @@ -1927,10 +1924,11 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, } } -static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; @@ -1945,17 +1943,17 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - /* allocate driver private area of tx_info */ - tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - ASSERT(tx_info->driver_data[0] != NULL); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* allocate driver private area of tx_info, XXX: UGLY HACK! */ + tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; + ASSERT(tx_info_priv != NULL); lowest_idx = rate_lowest_index(sband, sta); 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) { - sel->rate_idx = lowest_idx; + tx_info->control.rates[0].idx = lowest_idx; return; } @@ -1966,8 +1964,10 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, tx_info_priv->rcs, &is_probe, false); +#if 0 if (is_probe) sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; +#endif /* Ratecontrol sometimes returns invalid rate index */ if (tx_info_priv->rcs[0].rix != 0xff) @@ -1975,7 +1975,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, else tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix; - sel->rate_idx = tx_info_priv->rcs[0].rix; + tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix; /* Check if aggregation has to be enabled for this tid */ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index ba818cc..9fa3954 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -168,7 +168,9 @@ static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl) hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { txctl->use_minrate = 1; @@ -288,13 +290,16 @@ static int ath_tx_prepare(struct ath_softc *sc, if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) txctl->flags |= ATH9K_TXDESC_NOACK; - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) txctl->flags |= ATH9K_TXDESC_RTSENA; /* * Setup for rate calculations. */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; rcs = tx_info_priv->rcs; if (ieee80211_is_data(fc) && !txctl->use_minrate) { @@ -855,7 +860,9 @@ static int ath_tx_send_normal(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); /* update starting sequence number for subsequent ADDBA request */ @@ -1249,8 +1256,9 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; + + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif; if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && @@ -1431,7 +1439,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); /* Add sub-frame to BAW */ @@ -1466,7 +1475,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; + tx_info->control.vif; /* XXX: HACK! */ memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); @@ -1927,7 +1936,8 @@ static int ath_tx_start_dma(struct ath_softc *sc, bf->bf_flags = txctl->flags; bf->bf_keytype = txctl->keytype; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + /* XXX: HACK! */ + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; rcs = tx_info_priv->rcs; bf->bf_rcs[0] = rcs[0]; bf->bf_rcs[1] = rcs[1]; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 098f886..6d65a02 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,13 +1387,11 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, info = IEEE80211_SKB_CB(meta->skb); - memset(&info->status, 0, sizeof(info->status)); - /* * Call back to inform the ieee80211 subsystem about * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report(info, status); + frame_succeed = b43_fill_txstatus_report(dev, info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9aeeb65..2a599fb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4555,7 +4555,7 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_ADHOC); hw->queues = b43_modparam_qos ? 4 : 1; - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 40159126..1036bef 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -587,9 +587,8 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ info = IEEE80211_SKB_CB(pack->skb); - memset(&info->status, 0, sizeof(info->status)); - b43_fill_txstatus_report(info, status); + b43_fill_txstatus_report(dev, info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 2fabcf8..adba89b 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -185,7 +185,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; @@ -202,6 +202,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u16 phy_ctl = 0; u8 extra_ft = 0; struct ieee80211_rate *txrate; + struct ieee80211_tx_rate *rates; memset(txhdr, 0, sizeof(*txhdr)); @@ -291,7 +292,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { @@ -314,6 +315,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, B43_WARN_ON(1); } + rates = info->control.rates; /* MAC control */ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; @@ -324,12 +326,22 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43_TXH_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; @@ -344,7 +356,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; + int retry_limit; + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = report->status.rates[0].count; + ieee80211_tx_info_clear_status(report); if (status->acked) { /* The frame was ACKed. */ @@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->status.retry_count = 0; - } else - report->status.retry_count = status->frame_count - 1; + report->status.rates[0].count = 0; + } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + report->status.rates[0].count = 0; + report->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + report->status.rates[0].count = retry_limit; + report->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + report->status.rates[0].count = status->frame_count; + report->status.rates[1].idx = -1; + } + } return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 0215faf..4fb2a19 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *txctl, u16 cookie); + struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index fb6819e..308c264 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_dmaring *ring; struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; + int retry_limit; int slot; ring = parse_cookie(dev, status->cookie, &slot); @@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct ieee80211_tx_info *info; BUG_ON(!meta->skb); info = IEEE80211_SKB_CB(meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). - */ - memset(&info->status, 0, sizeof(info->status)); + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); - if (status->acked) { + if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; } else { - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->status.excessive_retries = 1; + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - info->status.retry_count = 0; - } else - info->status.retry_count = status->frame_count - - 1; + + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 78e4636..9edbdf9 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3682,7 +3682,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index a86c764..746d536 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; struct ieee80211_tx_info *info; + int retry_limit; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, sizeof(struct b43legacy_txhdr_fw3)); info = IEEE80211_SKB_CB(packet->skb); - memset(&info->status, 0, sizeof(info->status)); + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; - info->status.retry_count = status->frame_count - 1; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } + } ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 65e8337..12fca99 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; @@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; struct ieee80211_rate *tx_rate; + struct ieee80211_tx_rate *rates; wlhdr = (const struct ieee80211_hdr *)fragment_data; @@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) phy_ctl |= B43legacy_TX4_PHY_OFDM; - if (dev->short_preamble) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (info->antenna_sel_tx) { case 0: @@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ + rates = info->control.rates; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) @@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, @@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index e56777e0f..62e09d0 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index c25daec..f440ed0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -422,34 +422,6 @@ static void rs_free_sta(void *priv, struct ieee80211_sta *sta, } -/* - * get ieee prev rate from rate scale table. - * for A and B mode we need to overright prev - * value - */ -static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) -{ - int next_rate = iwl3945_get_prev_ieee_rate(rate); - - switch (priv->band) { - case IEEE80211_BAND_5GHZ: - if (rate == IWL_RATE_12M_INDEX) - next_rate = IWL_RATE_9M_INDEX; - else if (rate == IWL_RATE_6M_INDEX) - next_rate = IWL_RATE_6M_INDEX; - break; -/* XXX cannot be invoked in current mac80211 so not a regression - case MODE_IEEE80211B: - if (rate == IWL_RATE_11M_INDEX_TABLE) - next_rate = IWL_RATE_5M_INDEX_TABLE; - break; - */ - default: - break; - } - - return next_rate; -} /** * rs_tx_status - Update rate control values based on Tx results * @@ -460,17 +432,21 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - u8 retries, current_count; + u8 retries = 0, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct iwl3945_rs_sta *rs_sta = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int i; IWL_DEBUG_RATE("enter\n"); - retries = info->status.retry_count; - first_index = sband->bitrates[info->tx_rate_idx].hw_value; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) + retries += info->status.rates[i].count; + retries--; + + first_index = sband->bitrates[info->status.rates[0].idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -502,7 +478,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband last_index = scale_rate_index; } else { current_count = priv->retry_rate; - last_index = rs_adjust_next_rate(priv, + last_index = iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -518,7 +494,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband if (retries) scale_rate_index = - rs_adjust_next_rate(priv, scale_rate_index); + iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -630,10 +606,11 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * rate table and must reference the driver allocated rate table * */ -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, + void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; @@ -649,6 +626,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc, rate_mask; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); @@ -659,7 +637,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, is_multicast_ether_addr(hdr->addr1) || !sta || !priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -792,9 +770,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + info->control.rates[0].idx = rs_sta->last_txrate_idx - + IWL_FIRST_OFDM_RATE; else - sel->rate_idx = rs_sta->last_txrate_idx; + info->control.rates[0].idx = rs_sta->last_txrate_idx; IWL_DEBUG_RATE("leave: %d\n", index); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8a00245..7afafb6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -261,6 +261,35 @@ static inline const char *iwl3945_get_tx_fail_reason(u32 status) } #endif +/* + * get ieee prev rate from rate scale table. + * for A and B mode we need to overright prev + * value + */ +int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate) +{ + int next_rate = iwl3945_get_prev_ieee_rate(rate); + + switch (priv->band) { + case IEEE80211_BAND_5GHZ: + if (rate == IWL_RATE_12M_INDEX) + next_rate = IWL_RATE_9M_INDEX; + else if (rate == IWL_RATE_6M_INDEX) + next_rate = IWL_RATE_6M_INDEX; + break; +/* XXX cannot be invoked in current mac80211 so not a regression + case MODE_IEEE80211B: + if (rate == IWL_RATE_11M_INDEX_TABLE) + next_rate = IWL_RATE_5M_INDEX_TABLE; + break; + */ + default: + break; + } + + return next_rate; +} + /** * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd @@ -308,6 +337,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; + int fail, i; if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -318,9 +348,36 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, } info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); + + /* Fill the MRR chain with some info about on-chip retransmissions */ + rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + + fail = tx_resp->failure_frame; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + int next = iwl3945_rs_next_rate(priv, rate_idx); + + info->status.rates[i].idx = rate_idx; + + /* + * Put remaining into the last count as best approximation + * of saying exactly what the hardware would have done... + */ + if ((rate_idx == next) || (i == IEEE80211_TX_MAX_RATES - 1)) { + info->status.rates[i].count = fail; + break; + } + + info->status.rates[i].count = priv->retry_rate; + fail -= priv->retry_rate; + rate_idx = next; + if (fail <= 0) + break; + } + info->status.rates[i].count++; /* add final attempt */ - info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? IEEE80211_TX_STAT_ACK : 0; @@ -329,10 +386,6 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); - rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - if (info->band == IEEE80211_BAND_5GHZ) - rate_idx -= IWL_FIRST_OFDM_RATE; - info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index bdd3247..592c595 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -954,6 +954,8 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) extern const struct iwl3945_channel_info *iwl3945_get_channel_info( const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); +extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate); + /* Requires full declaration of iwl3945_priv before including */ #include "iwl-3945-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9838de5..222c2baa9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -619,10 +619,10 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { *tx_flags |= TX_CMD_FLG_RTS_MSK; *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { *tx_flags &= ~TX_CMD_FLG_RTS_MSK; *tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2070,7 +2070,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; info->flags |= iwl_is_tx_success(status)? IEEE80211_TX_STAT_ACK : 0; @@ -2227,7 +2227,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 56a3f0c..d5282fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -390,8 +390,8 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv) static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; else *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; @@ -1154,7 +1154,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; info->flags |= iwl_is_tx_success(status)? IEEE80211_TX_STAT_ACK : 0; @@ -1307,7 +1307,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags = iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e10e0ca..f685e5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -798,7 +798,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = info->status.retry_count; + retries = info->status.rates[0].count - 1; if (retries > 15) retries = 15; @@ -830,20 +830,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((info->tx_rate_idx < 0) || - (tbl_type.is_SGI ^ - !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || - (tbl_type.is_fat ^ - !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || - (tbl_type.is_dup ^ - !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || - (tbl_type.ant_type ^ info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || - (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || + if ((info->status.rates[0].idx < 0) || + (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + (tbl_type.ant_type != info->antenna_sel_tx) || + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { + hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); goto out; } @@ -2098,15 +2093,17 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; } -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { int i; + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); __le16 fc; struct iwl_lq_sta *lq_sta; @@ -2117,7 +2114,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, fc = hdr->frame_control; if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !priv_sta) { - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -2143,13 +2140,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } if (sband->band == IEEE80211_BAND_5GHZ) i -= IWL_FIRST_OFDM_RATE; - sel->rate_idx = i; + info->control.rates[0].idx = i; } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 10f5a0a..2c4162e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates); * translate ucode response to mac80211 tx status control values */ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_info *control) + struct ieee80211_tx_info *info) { int rate_index; + struct ieee80211_tx_rate *r = &info->control.rates[0]; - control->antenna_sel_tx = + info->antenna_sel_tx = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TX_CTL_OFDM_HT; + r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; + r->flags |= IEEE80211_TX_RC_GREEN_FIELD; if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; + r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TX_CTL_DUP_DATA; + r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TX_CTL_SHORT_GI; + r->flags |= IEEE80211_TX_RC_SHORT_GI; rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (control->band == IEEE80211_BAND_5GHZ) + if (info->band == IEEE80211_BAND_5GHZ) rate_index -= IWL_FIRST_OFDM_RATE; - control->tx_rate_idx = rate_index; + r->idx = rate_index; } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index b1464c7..2cd33b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2395,6 +2395,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, { __le16 fc = hdr->frame_control; __le32 tx_flags = cmd->cmd.tx.tx_flags; + u8 rc_flags = info->control.rates[0].flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { @@ -2421,10 +2422,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 241ddcf..d1fc305 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -592,14 +592,14 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card); void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); - memset(&info->status, 0, sizeof(info->status)); + + ieee80211_tx_info_clear_status(info); /* * Commented out, otherwise we never go beyond 1Mbit/s using mac80211 * default pid rc algorithm. * * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt; */ - info->status.excessive_retries = fail ? 1 : 0; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) info->flags |= IEEE80211_TX_STAT_ACK; skb_pull(priv->tx_skb, sizeof(struct txpd)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e2aeef8..c576523 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -209,7 +209,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* TODO: set mactime */ rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; - rx_status.rate_idx = info->tx_rate_idx; + rx_status.rate_idx = info->control.rates[0].idx; /* TODO: simulate signal strength (and optional packet drop) */ /* Copy skb to all enabled radios that are on the current frequency */ @@ -269,13 +269,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (txi->control.sta) hwsim_check_sta_magic(txi->control.sta); - memset(&txi->status, 0, sizeof(txi->status)); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (ack) - txi->flags |= IEEE80211_TX_STAT_ACK; - else - txi->status.excessive_retries = 1; - } + ieee80211_tx_info_clear_status(txi); + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) + txi->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 81a9756..65be5ec 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -548,7 +548,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) 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; + range = (void *)info->rate_driver_data; if (range->start_addr == addr) { struct p54_control_hdr *entry_hdr; struct p54_tx_control_allocdata *entry_data; @@ -559,7 +559,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct memrecord *mr; ni = IEEE80211_SKB_CB(entry->next); - mr = (struct memrecord *)ni->driver_data; + mr = (struct memrecord *)ni->rate_driver_data; freed = mr->start_addr - last_addr; } else freed = priv->rx_end - last_addr; @@ -568,7 +568,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -578,10 +578,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; } - info->status.retry_count = payload->retries - 1; + info->status.rates[0].count = payload->retries; info->status.ack_signal = p54_rssi_to_dbm(dev, le16_to_cpu(payload->ack_rssi)); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); @@ -699,7 +697,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, while (left--) { u32 hole_size; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->driver_data; + struct memrecord *range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -715,7 +713,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); - struct memrecord *range = (void *)info->driver_data; + struct memrecord *range = (void *)info->rate_driver_data; target_addr = range->end_addr; } } else @@ -723,7 +721,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct memrecord *range = (void *)info->driver_data; + struct memrecord *range = (void *)info->rate_driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; __skb_queue_after(&priv->tx_queue, target_skb, skb); @@ -806,6 +804,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len; u8 rate; u8 cts_rate = 0x20; + u8 rc_flags; current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) @@ -828,18 +827,19 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = info->control.retry_limit; + hdr->retry1 = hdr->retry2 = info->control.rates[0].count; /* TODO: add support for alternate retry TX rates */ rate = ieee80211_get_tx_rate(dev, info)->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) { + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { rate |= 0x10; cts_rate |= 0x10; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { rate |= 0x40; cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { rate |= 0x20; cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 697806cf..e1feab8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -498,7 +498,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + u8 rate_idx, rate_flags; /* * Unmap the skb. @@ -528,14 +530,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); + rate_idx = skbdesc->tx_rate_idx; + rate_flags = skbdesc->tx_rate_flags; + /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.excessive_retries = - test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); - tx_info->status.retry_count = txdesc->retry; + tx_info->status.rates[0].idx = rate_idx; + tx_info->status.rates[0].flags = rate_flags; + tx_info->status.rates[0].count = txdesc->retry + 1; + tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) @@ -544,7 +550,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 9311833..b32d59e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, unsigned int data_length; int retval = 0; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) data_length = sizeof(struct ieee80211_cts); else data_length = sizeof(struct ieee80211_rts); @@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; - rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; @@ -84,7 +84,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, data_length += rt2x00crypto_tx_overhead(tx_info); #endif /* CONFIG_RT2X00_LIB_CRYPTO */ - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); @@ -146,8 +146,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * inside the hardware. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); - if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | - IEEE80211_TX_CTL_USE_CTS_PROTECT)) && + if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | + IEEE80211_TX_RC_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) goto exit_fail; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 451d410..070786e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -230,8 +230,15 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Determine retry information. */ - txdesc->retry_limit = tx_info->control.retry_limit; - if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + txdesc->retry_limit = tx_info->control.rates[0].count - 1; + /* + * XXX: If at this point we knew whether the HW is going to use + * the RETRY_MODE bit or the retry_limit (currently all + * use the RETRY_MODE bit) we could do something like b43 + * does, set the RETRY_MODE bit when the RC algorithm is + * requesting more than the long retry limit. + */ + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -371,10 +378,12 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) { + struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; unsigned int iv_len = 0; + u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) return -EINVAL; @@ -399,13 +408,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; /* - * All information is retreived from the skb->cb array, + * All information is retrieved from the skb->cb array, * now we should claim ownership of the driver part of that - * array. + * array, preserving the bitrate index and flags. */ + tx_info = IEEE80211_SKB_CB(skb); + rate_idx = tx_info->control.rates[0].idx; + rate_flags = tx_info->control.rates[0].flags; skbdesc = get_skb_frame_desc(entry->skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; + skbdesc->tx_rate_idx = rate_idx; + skbdesc->tx_rate_flags = rate_flags; /* * When hardware encryption is supported, and this frame diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 9dbf04f..4d3c724 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -104,6 +104,8 @@ enum skb_frame_desc_flags { * * @flags: Frame flags, see &enum skb_frame_desc_flags. * @desc_len: Length of the frame descriptor. + * @tx_rate_idx: the index of the TX rate, used for TX status reporting + * @tx_rate_flags: the TX rate flags, used for TX status reporting * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. @@ -113,9 +115,12 @@ enum skb_frame_desc_flags { * @entry: The entry to which this sk buffer belongs. */ struct skb_frame_desc { - unsigned int flags; + u8 flags; + + u8 desc_len; + u8 tx_rate_idx; + u8 tx_rate_flags; - unsigned int desc_len; void *desc; __le32 iv; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index e8d2239..6c226c0 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) skb->len, PCI_DMA_TODEVICE); info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (flags & RTL818X_TX_DESC_FLAG_TX_OK) - info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = flags & 0xFF; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) @@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) unsigned int idx, prio; dma_addr_t mapping; u32 tx_flags; + u8 rc_flags; u16 plcp_len = 0; __le16 rts_duration = 0; @@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) tx_flags |= RTL818X_TX_DESC_FLAG_DMA | RTL818X_TX_DESC_FLAG_NO_ENC; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= RTL818X_TX_DESC_FLAG_RTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags |= RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, info); @@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = info->control.retries[0].rate_idx >= 0 ? + entry->flags2 = info->control.rates[1].idx >= 0 ? ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.retry_limit; + entry->retry_limit = info->control.rates[0].count; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) @@ -855,7 +855,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; - dev->max_altrates = 1; + dev->max_rates = 2; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index cd839bc..6260ed8 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -160,13 +160,13 @@ static void rtl8187_tx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *)urb->context; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; struct rtl8187_priv *priv = hw->priv; - usb_free_urb(info->driver_data[1]); + usb_free_urb(info->rate_driver_data[1]); skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); info->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); } @@ -194,12 +194,12 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, info); - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { flags |= RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -210,7 +210,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); buf = hdr; ep = 2; @@ -228,7 +228,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(hdr, 0, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, skb->len, txrate); @@ -240,8 +240,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } - info->driver_data[0] = dev; - info->driver_data[1] = urb; + info->rate_driver_data[0] = dev; + info->rate_driver_data[1] = urb; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), buf, skb->len, rtl8187_tx_cb, skb); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6c3e218..2f0802b 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_hw *hw) * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - u32 flags, int ackssi, bool success) + int ackssi, bool success) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!success) - info->status.excessive_retries = 1; - info->flags |= flags; + if (success) + info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ackssi; ieee80211_tx_status_irqsafe(hw, skb); } @@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) if (skb == NULL) return; - tx_status(hw, skb, 0, 0, 0); + tx_status(hw, skb, 0, 0); } /** @@ -342,12 +341,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error || (info->flags & IEEE80211_TX_CTL_NO_ACK))) { - tx_status(hw, skb, 0, 0, !error); + tx_status(hw, skb, 0, !error); } else { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; @@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr *header, u32 flags) + struct ieee80211_hdr *header, + struct ieee80211_tx_info *info) { /* * CONTROL TODO: @@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (ieee80211_is_pspoll(header->frame_control)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ @@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *mac, txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, info->flags); + cs_set_control(mac, cs, hdr, info); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -577,7 +577,7 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (r) return r; - info->driver_data[0] = hw; + info->rate_driver_data[0] = hw; r = zd_usb_tx(&mac->chip.usb, skb); if (r) @@ -618,7 +618,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { __skb_unlink(skb, q); - tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); + tx_status(hw, skb, stats->signal, 1); goto out; } } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a60ae86..d7a2f52 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -907,7 +907,7 @@ free_urb: * it might be freed by zd_mac_tx_to_dev or mac80211) */ info = IEEE80211_SKB_CB(skb); - usb = &zd_hw_mac(info->driver_data[0])->chip.usb; + usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); -- cgit v1.1 From c12abae333ac550acacf9d324ed54b7d17ead0c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Oct 2008 16:56:51 +0200 Subject: p54: implement MRR This implements multi-rate retry in p54. With lots of help and testing from Christian and the limiting idea from nbd. Signed-off-by: Johannes Berg Cc: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 130 +++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 65be5ec..2370901 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1,9 +1,9 @@ - /* * Common code for mac80211 Prism54 drivers * * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter + * Copyright 2008, Johannes Berg * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note , et al. @@ -544,6 +544,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) u32 freed = 0; u32 last_addr = priv->rx_start; unsigned long flags; + int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { @@ -568,18 +569,39 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - ieee80211_tx_info_clear_status(info); + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - 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; + /* walk through the rates array and adjust the counts */ + count = payload->retries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; + } } - info->status.rates[0].count = payload->retries; + + priv->tx_stats[entry_data->hw_queue].len--; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + !(payload->status & 0x01)) + info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = p54_rssi_to_dbm(dev, le16_to_cpu(payload->ack_rssi)); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); @@ -802,9 +824,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_control_hdr *hdr; struct p54_tx_control_allocdata *txhdr; size_t padding, len; + int i, j, ridx; u8 rate; u8 cts_rate = 0x20; u8 rc_flags; + u8 calculated_tries[4]; + u8 nrates = 0, nremaining = 8; current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) @@ -827,23 +852,74 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->magic1 = cpu_to_le16(0x0010); hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = info->control.rates[0].count; - - /* TODO: add support for alternate retry TX rates */ - rate = ieee80211_get_tx_rate(dev, info)->hw_value; - rc_flags = info->control.rates[0].flags; - if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { - rate |= 0x10; - cts_rate |= 0x10; + hdr->retry1 = info->control.rates[0].count; + + /* + * we register the rates in perfect order, and + * RTS/CTS won't happen on 5 GHz + */ + cts_rate = info->control.rts_cts_rate_idx; + + memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); + + /* see how many rates got used */ + for (i = 0; i < 4; i++) { + if (info->control.rates[i].idx < 0) + break; + nrates++; + } + + /* limit tries to 8/nrates per rate */ + for (i = 0; i < nrates; i++) { + /* + * The magic expression here is equivalent to 8/nrates for + * all values that matter, but avoids division and jumps. + * Note that nrates can only take the values 1 through 4. + */ + calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, + info->control.rates[i].count); + nremaining -= calculated_tries[i]; } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - rate |= 0x40; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; - } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - rate |= 0x20; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; + + /* if there are tries left, distribute from back to front */ + for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { + int tmp = info->control.rates[i].count - calculated_tries[i]; + + if (tmp <= 0) + continue; + /* RC requested more tries at this rate */ + + tmp = min_t(int, tmp, nremaining); + calculated_tries[i] += tmp; + nremaining -= tmp; } - memset(txhdr->rateset, rate, 8); + + ridx = 0; + for (i = 0; i < nrates && ridx < 8; i++) { + /* we register the rates in perfect order */ + rate = info->control.rates[i].idx; + if (info->band == IEEE80211_BAND_5GHZ) + rate += 4; + + /* store the count we actually calculated for TX status */ + info->control.rates[i].count = calculated_tries[i]; + + rc_flags = info->control.rates[i].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { + rate |= 0x10; + cts_rate |= 0x10; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) + rate |= 0x40; + else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + rate |= 0x20; + for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { + txhdr->rateset[ridx] = rate; + ridx++; + } + } + hdr->retry2 = ridx; + txhdr->key_type = 0; txhdr->key_len = 0; txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; @@ -1393,6 +1469,16 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv->tx_stats[4].limit = 5; dev->queues = 1; priv->noise = -94; + /* + * We support at most 8 tries no matter which rate they're at, + * we cannot support max_rates * max_rate_tries as we set it + * here, but setting it correctly to 4/2 or so would limit us + * artificially if the RC algorithm wants just two rates, so + * let's say 4/7, we'll redistribute it at TX time, see the + * comments there. + */ + dev->max_rates = 4; + dev->max_rate_tries = 7; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + sizeof(struct p54_tx_control_allocdata); -- cgit v1.1 From 5c7f9b7363bfd10e40cf1a28dfc9048417df7028 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Tue, 14 Oct 2008 10:38:03 -0600 Subject: ipw2x00: change default policy for auto-associate Do not attempt association until directed to do so by a user space application. In particular, this avoids race conditions with NetworkManager association state. Signed-off-by: Tim Gardner Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 4 ++-- drivers/net/wireless/ipw2200.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 6e988d2..079dbd0 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -185,7 +185,7 @@ MODULE_LICENSE("GPL"); static int debug = 0; static int mode = 0; static int channel = 0; -static int associate = 1; +static int associate = 0; static int disable = 0; #ifdef CONFIG_PM static struct ipw2100_fw ipw2100_firmware; @@ -201,7 +201,7 @@ module_param(disable, int, 0444); MODULE_PARM_DESC(debug, "debug level"); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); MODULE_PARM_DESC(channel, "channel"); -MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); static u32 ipw2100_debug_level = IPW_DL_NONE; diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 13633d8..6ec6de2 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -87,7 +87,7 @@ static int channel = 0; static int mode = 0; static u32 ipw_debug_level; -static int associate = 1; +static int associate; static int auto_create = 1; static int led = 0; static int disable = 0; @@ -11913,7 +11913,7 @@ module_param(disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param(associate, int, 0444); -MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); -- cgit v1.1 From 4e062f99af771173b601742b0c1c98eb4d52ea08 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Tue, 14 Oct 2008 12:32:41 -0700 Subject: iwlwifi: define firmware file name once string repeated for definition of ucode firmware file and in preparation for multiple firmware files need to consolidate location for their definition. Signed-off-by: Jay Sternberg Acked-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d5282fa..0fc6757 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -46,6 +46,8 @@ #define IWL5000_UCODE_API "-1" +#define IWL5000_MODULE_FIRMWARE "iwlwifi-5000" IWL5000_UCODE_API ".ucode" + static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC3, IWL_TX_FIFO_AC2, @@ -1544,7 +1546,7 @@ static struct iwl_mod_params iwl50_mod_params = { struct iwl_cfg iwl5300_agn_cfg = { .name = "5300AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name = IWL5000_MODULE_FIRMWARE, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1553,7 +1555,7 @@ struct iwl_cfg iwl5300_agn_cfg = { struct iwl_cfg iwl5100_bg_cfg = { .name = "5100BG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name = IWL5000_MODULE_FIRMWARE, .sku = IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1562,7 +1564,7 @@ struct iwl_cfg iwl5100_bg_cfg = { struct iwl_cfg iwl5100_abg_cfg = { .name = "5100ABG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name = IWL5000_MODULE_FIRMWARE, .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1571,7 +1573,7 @@ struct iwl_cfg iwl5100_abg_cfg = { struct iwl_cfg iwl5100_agn_cfg = { .name = "5100AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name = IWL5000_MODULE_FIRMWARE, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1580,14 +1582,14 @@ struct iwl_cfg iwl5100_agn_cfg = { struct iwl_cfg iwl5350_agn_cfg = { .name = "5350AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name = IWL5000_MODULE_FIRMWARE, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .mod_params = &iwl50_mod_params, }; -MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE); module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, -- cgit v1.1 From 56e1261596334e60210fb8ecd9eb6a3db53aba94 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Tue, 14 Oct 2008 12:32:42 -0700 Subject: iwlwifi: expand error lookup and align output change desc_lookup from hard coded switch to a simple lookup table and expand list to include all errors. Also corrected output using this string so info is aligned and easier to read when debugging issues. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 57 +++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2c4162e..59dd608 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1162,24 +1162,47 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); + +static const char *desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT" + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", + "UNKNOWN" +}; + static const char *desc_lookup(int i) { - switch (i) { - case 1: - return "FAIL"; - case 2: - return "BAD_PARAM"; - case 3: - return "BAD_CHECKSUM"; - case 4: - return "NMI_INTERRUPT"; - case 5: - return "SYSASSERT"; - case 6: - return "FATAL_ERROR"; - } + int max = ARRAY_SIZE(desc_lookup_text) - 1; + + if (i < 0 || i > max) + i = max; - return "UNKNOWN"; + return desc_lookup_text[i]; } #define ERROR_START_OFFSET (1 * sizeof(u32)) @@ -1225,9 +1248,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - IWL_ERROR("Desc Time " + IWL_ERROR("Desc Time " "data1 data2 line\n"); - IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + IWL_ERROR("%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", desc_lookup(desc), desc, time, data1, data2, line); IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, -- cgit v1.1 From 3257e5d4eb418e4656542207720aef5f0f547701 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 14 Oct 2008 12:32:43 -0700 Subject: iwlwifi: remove host commands structures from iwl_cmd This patch removes host commands structures from iwl_cmd to make more HW oblivious tx cmd was left it needs special treatment. Signed-off-by: Tomas Winkler Reviewed-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 9 +-------- drivers/net/wireless/iwlwifi/iwl-sta.c | 8 ++++++-- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2e95149..c73315f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -268,23 +268,16 @@ struct iwl_cmd { struct iwl_cmd_meta meta; /* driver data */ struct iwl_cmd_header hdr; /* uCode API */ union { - struct iwl_addsta_cmd addsta; - struct iwl_led_cmd led; u32 flags; u8 val8; u16 val16; u32 val32; - struct iwl4965_bt_cmd bt; - struct iwl_powertable_cmd powertable; - struct iwl_qosparam_cmd qosparam; struct iwl_tx_cmd tx; - struct iwl4965_rxon_assoc_cmd rxon_assoc; - struct iwl_rem_sta_cmd rm_sta; - u8 *indirect; u8 payload[IWL_CMD_MAX_PAYLOAD]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); + struct iwl_host_cmd { u8 id; u16 len; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 218483d..dde0850 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -102,7 +102,9 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; - u8 sta_id = cmd->cmd.addsta.sta.sta_id; + struct iwl_addsta_cmd *addsta = + (struct iwl_addsta_cmd *)cmd->cmd.payload; + u8 sta_id = addsta->sta.sta_id; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); @@ -320,7 +322,9 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; - const char *addr = cmd->cmd.rm_sta.addr; + struct iwl_rem_sta_cmd *rm_sta = + (struct iwl_rem_sta_cmd *)cmd->cmd.payload; + const char *addr = rm_sta->addr; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n"); -- cgit v1.1 From 961ba60abe02517d0c8252f9befb1478f4e008a4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 14 Oct 2008 12:32:44 -0700 Subject: iwlwifi: add iwl_cmd_queue_free for readability This patch adds iwl_cmd_queue_free function and separate cmd queue freeing from regular tx queue freeing. This improves readability and adds one more step in restructuring of cmd queue handling Signed-off-by: Tomas Winkler Reviewed-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 53 ++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 37ebcff..87c955e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -72,10 +72,6 @@ static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) int counter = 0; int index, is_odd; - /* Host command buffers stay mapped in memory, nothing to clean */ - if (txq->q.id == IWL_CMD_QUEUE_NUM) - return 0; - /* Sanity check on number of chunks */ counter = IWL_GET_BITS(*bd, num_tbs); if (counter > MAX_NUM_OF_TBS) { @@ -210,7 +206,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, slots_num, len; + int i, len; if (q->n_bd == 0) return; @@ -221,16 +217,10 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) iwl_hw_txq_free_tfd(priv, txq); len = sizeof(struct iwl_cmd) * q->n_window; - if (q->id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; /* De-alloc array of command/tx buffers */ - slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - for (i = 0; i < slots_num; i++) + for (i = 0; i < TFD_TX_CMD_SLOTS; i++) kfree(txq->cmd[i]); - if (txq_id == IWL_CMD_QUEUE_NUM) - kfree(txq->cmd[slots_num]); /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) @@ -245,6 +235,40 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) memset(txq, 0, sizeof(*txq)); } + +/** + * iwl_cmd_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_cmd_queue_free(struct iwl_priv *priv) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int i, len; + + if (q->n_bd == 0) + return; + + len = sizeof(struct iwl_cmd) * q->n_window; + len += IWL_MAX_SCAN_SIZE; + + /* De-alloc array of command/tx buffers */ + for (i = 0; i <= TFD_CMD_SLOTS; i++) + kfree(txq->cmd[i]); + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -468,7 +492,10 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) /* Tx queues */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, txq_id); + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); /* Keep-warm buffer */ iwl_kw_free(priv); -- cgit v1.1 From 76eff18bdc5feaa53f1be33709b67df02f1d55e9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 14 Oct 2008 12:32:45 -0700 Subject: iwlwifi: unify tx antenna toggling TX antenna toggling is requested for management frames in tx and scanning. I addition toggling in scanning was incorrect; Signed-off-by: Tomas Winkler Reviewed-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 14 ++++--- drivers/net/wireless/iwlwifi/iwl-core.c | 13 ++++++- drivers/net/wireless/iwlwifi/iwl-core.h | 9 ++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 +-- drivers/net/wireless/iwlwifi/iwl-scan.c | 57 +++++++++-------------------- drivers/net/wireless/iwlwifi/iwl-tx.c | 14 ++----- 6 files changed, 51 insertions(+), 62 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ba54613..67680a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -283,18 +283,20 @@ struct iwl_cmd_header { #define RATE_MCS_SGI_MSK 0x2000 /** - * rate_n_flags Tx antenna masks (4965 has 2 transmitters): - * bit14:15 01 B inactive, A active - * 10 B active, A inactive - * 11 Both active + * rate_n_flags Tx antenna masks + * 4965 has 2 transmitters + * 5100 has 1 transmitter B + * 5150 has 1 transmitter A + * 5300 has 3 transmitters + * 5350 has 3 transmitters + * bit14:16 */ #define RATE_MCS_ANT_POS 14 #define RATE_MCS_ANT_A_MSK 0x04000 #define RATE_MCS_ANT_B_MSK 0x08000 #define RATE_MCS_ANT_C_MSK 0x10000 #define RATE_MCS_ANT_ABC_MSK 0x1C000 - -#define RATE_MCS_ANT_INIT_IND 1 +#define RATE_ANT_NUM 3 #define POWER_TABLE_NUM_ENTRIES 33 #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 59dd608..20c7ff3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -141,7 +141,17 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) } EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); - +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) +{ + int i; + u8 ind = ant; + for (i = 0; i < RATE_ANT_NUM - 1; i++) { + ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0; + if (priv->hw_params.valid_tx_ant & BIT(ind)) + return ind; + } + return ant; +} const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; EXPORT_SYMBOL(iwl_bcast_addr); @@ -938,7 +948,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; - priv->use_ant_b_for_management_frame = 1; /* start with ant B */ priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 1a3ad8b..a2d8afe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -237,7 +237,6 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); - /***************************************************** * TX power ****************************************************/ @@ -259,6 +258,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx); + +static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) +{ + return BIT(ant_idx) << RATE_MCS_ANT_POS; +} + static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; @@ -313,6 +319,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); + /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c73315f..0f57bf4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -810,12 +810,13 @@ struct iwl_priv { unsigned long scan_start; unsigned long scan_pass_start; unsigned long scan_start_tsf; + struct iwl_scan_cmd *scan; int scan_bands; int one_direct_scan; u8 direct_ssid_len; u8 direct_ssid[IW_ESSID_MAX_SIZE]; - struct iwl_scan_cmd *scan; - u32 scan_tx_ant[IEEE80211_NUM_BANDS]; + u8 scan_tx_ant[IEEE80211_NUM_BANDS]; + u8 mgmt_tx_ant; /* spinlock */ spinlock_t lock; /* protect general shared data */ @@ -874,7 +875,6 @@ struct iwl_priv { u16 active_rate_basic; u8 assoc_station_added; - u8 use_ant_b_for_management_frame; /* Tx antenna selection */ u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 78d16bd..86b7457 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -64,12 +64,6 @@ #define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) -static int scan_tx_ant[3] = { - RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK -}; - - - static int iwl_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ @@ -455,10 +449,11 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, void iwl_init_scan_params(struct iwl_priv *priv) { + u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) - priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND; + priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) - priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND; + priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } int iwl_scan_initiate(struct iwl_priv *priv) @@ -670,23 +665,6 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, return (u16)len; } -static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band) -{ - int i, ind; - - ind = priv->scan_tx_ant[band]; - for (i = 0; i < priv->hw_params.tx_chains_num; i++) { - ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1; - if (priv->hw_params.valid_tx_ant & (1 << ind)) { - priv->scan_tx_ant[band] = ind; - break; - } - } - IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind); - return scan_tx_ant[ind]; -} - - static void iwl_bg_request_scan(struct work_struct *data) { struct iwl_priv *priv = @@ -699,11 +677,12 @@ static void iwl_bg_request_scan(struct work_struct *data) struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; int ret = 0; - u32 tx_ant; + u32 rate_flags = 0; u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; u8 rx_chain = priv->hw_params.valid_rx_ant; + u8 rate; conf = ieee80211_get_hw_conf(priv->hw); @@ -822,23 +801,16 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - tx_ant = iwl_scan_tx_ant(priv, band); - if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - tx_ant); - else - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, - tx_ant | - RATE_MCS_CCK_MSK); + if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { + rate = IWL_RATE_6M_PLCP; + } else { + rate = IWL_RATE_1M_PLCP; + rate_flags = RATE_MCS_CCK_MSK; + } scan->good_CRC_th = 0; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; - tx_ant = iwl_scan_tx_ant(priv, band); - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - tx_ant); + rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; /* Force use of chains B and C (0x6) for scan Rx for 4965 @@ -851,6 +823,11 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } + priv->scan_tx_ant[band] = + iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]); + rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); + scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); + /* MIMO is not used here, but value is required */ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 87c955e..b047fd1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -674,11 +674,11 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, __le16 fc, int sta_id, int is_hcca) { + u32 rate_flags = 0; + int rate_idx; u8 rts_retry_limit = 0; u8 data_retry_limit = 0; u8 rate_plcp; - u16 rate_flags = 0; - int rate_idx; rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, IWL_RATE_COUNT - 1); @@ -721,14 +721,8 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, break; } - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags |= RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags |= RATE_MCS_ANT_A_MSK; - } + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); } tx_cmd->rts_retry_limit = rts_retry_limit; -- cgit v1.1 From 499b1883038a7db2dcf8b64229f8533ce2c8f0fc Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 14 Oct 2008 12:32:48 -0700 Subject: iwlwifi: fix TX cmd dma unmapping This patch: 1. fixes command DMA unmapping, this might be visible only on platforms where DMA unmapping is no noop such as PPC64 (not tested) 2. attaches correctly high memory part of the host command buffer 3. changes structure of TFD TB instead of describing transmit buffer (TB) tuple it describes single TB and makes code more readable on price of one unaligned access 4. eliminates using of IWL_GET/SET_BITs for TFD handling 5. renames TFD structures to mach the HW spec 6. reduces iwl_tx_info size by reserving first TB to the host command This patch should not have any visible effect on x86 32 This patch is rework of iwlwifi: fix DMA code and bugs from Johannes Berg Signed-off-by: Tomas Winkler Cc: Johannes Berg Reviewed-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 100 +++++-------- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 9 +- drivers/net/wireless/iwlwifi/iwl-helpers.h | 5 - drivers/net/wireless/iwlwifi/iwl-tx.c | 231 ++++++++++++++++------------- 5 files changed, 163 insertions(+), 184 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index f4793a6..b66dd09 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -822,94 +822,62 @@ enum { #define IWL49_NUM_QUEUES 16 #define IWL49_NUM_AMPDU_QUEUES 8 +#define IWL_TX_DMA_MASK (DMA_BIT_MASK(36) & ~0x3) +#define IWL_NUM_OF_TBS 20 + +static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) +{ + return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF; +} /** - * struct iwl_tfd_frame_data + * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor * - * Describes up to 2 buffers containing (contiguous) portions of a Tx frame. - * Each buffer must be on dword boundary. - * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers, - * may be filled within a TFD (iwl_tfd_frame). + * This structure contains dma address and length of transmission address * - * Bit fields in tb1_addr: - * 31- 0: Tx buffer 1 address bits [31:0] - * - * Bit fields in val1: - * 31-16: Tx buffer 2 address bits [15:0] - * 15- 4: Tx buffer 1 length (bytes) - * 3- 0: Tx buffer 1 address bits [32:32] - * - * Bit fields in val2: - * 31-20: Tx buffer 2 length (bytes) - * 19- 0: Tx buffer 2 address bits [35:16] + * @lo: low [31:0] portion of the dma address of TX buffer + * every even is unaligned on 16 bit boundary + * @hi_n_len 0-3 [35:32] portion of dma + * 4-16 length of the tx buffer */ -struct iwl_tfd_frame_data { - __le32 tb1_addr; - - __le32 val1; - /* __le32 ptb1_32_35:4; */ -#define IWL_tb1_addr_hi_POS 0 -#define IWL_tb1_addr_hi_LEN 4 -#define IWL_tb1_addr_hi_SYM val1 - /* __le32 tb_len1:12; */ -#define IWL_tb1_len_POS 4 -#define IWL_tb1_len_LEN 12 -#define IWL_tb1_len_SYM val1 - /* __le32 ptb2_0_15:16; */ -#define IWL_tb2_addr_lo16_POS 16 -#define IWL_tb2_addr_lo16_LEN 16 -#define IWL_tb2_addr_lo16_SYM val1 - - __le32 val2; - /* __le32 ptb2_16_35:20; */ -#define IWL_tb2_addr_hi20_POS 0 -#define IWL_tb2_addr_hi20_LEN 20 -#define IWL_tb2_addr_hi20_SYM val2 - /* __le32 tb_len2:12; */ -#define IWL_tb2_len_POS 20 -#define IWL_tb2_len_LEN 12 -#define IWL_tb2_len_SYM val2 -} __attribute__ ((packed)); - +struct iwl_tfd_tb { + __le32 lo; + __le16 hi_n_len; +} __attribute__((packed)); /** - * struct iwl_tfd_frame + * struct iwl_tfd * * Transmit Frame Descriptor (TFD) * - * 4965 supports up to 16 Tx queues resident in host DRAM. + * @ __reserved1[3] reserved + * @ num_tbs 0-5 number of active tbs + * 6-7 padding (not used) + * @ tbs[20] transmit frame buffer descriptors + * @ __pad padding + * * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be - * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965. + * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes * * Driver must indicate the physical address of the base of each - * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers. + * circular buffer via the FH_MEM_CBBC_QUEUE registers. * * Each TFD contains pointer/size information for up to 20 data buffers * in host DRAM. These buffers collectively contain the (one) frame described * by the TFD. Each buffer must be a single contiguous block of memory within * itself, but buffers may be scattered in host DRAM. Each buffer has max size - * of (4K - 4). The 4965 concatenates all of a TFD's buffers into a single + * of (4K - 4). The concatenates all of a TFD's buffers into a single * Tx frame, up to 8 KBytes in size. * - * Bit fields in the control dword (val0): - * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound - * 29: reserved - * 28-24: # Transmit Buffer Descriptors in TFD - * 23- 0: reserved - * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. + * + * Bit fields in the control dword (val0): */ -struct iwl_tfd_frame { - __le32 val0; - /* __le32 rsvd1:24; */ - /* __le32 num_tbs:5; */ -#define IWL_num_tbs_POS 24 -#define IWL_num_tbs_LEN 5 -#define IWL_num_tbs_SYM val0 - /* __le32 rsvd2:1; */ - /* __le32 padding:2; */ - struct iwl_tfd_frame_data pa[10]; - __le32 reserved; +struct iwl_tfd { + u8 __reserved1[3]; + u8 num_tbs; + struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS]; + __le32 __pad; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0fc6757..ad566ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -536,7 +536,7 @@ static int iwl5000_load_section(struct iwl_priv *priv, iwl_write_direct32(priv, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), - (iwl_get_dma_hi_address(phy_addr) + (iwl_get_dma_hi_addr(phy_addr) << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); iwl_write_direct32(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0f57bf4..1f42e90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -112,11 +112,9 @@ struct iwl_queue { * space less than this */ } __attribute__ ((packed)); -#define MAX_NUM_OF_TBS (20) - /* One for each TFD */ struct iwl_tx_info { - struct sk_buff *skb[MAX_NUM_OF_TBS]; + struct sk_buff *skb[IWL_NUM_OF_TBS - 1]; }; /** @@ -134,7 +132,7 @@ struct iwl_tx_info { */ struct iwl_tx_queue { struct iwl_queue q; - struct iwl_tfd_frame *bd; + struct iwl_tfd *tfds; struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; struct iwl_tx_info *txb; int need_update; @@ -252,7 +250,8 @@ struct iwl_cmd_meta { /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ u32 flags; - + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(len) } __attribute__ ((packed)); #define IWL_CMD_MAX_PAYLOAD 320 diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 41eed67..029d19c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -159,11 +159,6 @@ static inline unsigned long elapsed_jiffies(unsigned long start, return end + (MAX_JIFFY_OFFSET - start) + 1; } -static inline u8 iwl_get_dma_hi_address(dma_addr_t addr) -{ - return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; -} - /** * iwl_queue_inc_wrap - increment queue index, wrap back to beginning * @index -- current index diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b047fd1..c3656c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -56,92 +56,112 @@ static const u16 default_tid_to_tx_fifo[] = { IWL_TX_FIFO_AC3 }; +static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + dma_addr_t addr = get_unaligned_le32(&tb->lo); + if (sizeof(dma_addr_t) > sizeof(u32)) + addr |= + ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16; + + return addr; +} + +static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + return le16_to_cpu(tb->hi_n_len) >> 4; +} + +static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, + dma_addr_t addr, u16 len) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + u16 hi_n_len = len << 4; + + put_unaligned_le32(addr, &tb->lo); + if (sizeof(dma_addr_t) > sizeof(u32)) + hi_n_len |= ((addr >> 16) >> 16) & 0xF; + + tb->hi_n_len = cpu_to_le16(hi_n_len); + + tfd->num_tbs = idx + 1; +} + +static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) +{ + return tfd->num_tbs & 0x1f; +} /** * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] + * @priv - driver private data + * @txq - tx queue * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; - struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; + struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0]; + struct iwl_tfd *tfd; struct pci_dev *dev = priv->pci_dev; + int index = txq->q.read_ptr; int i; - int counter = 0; - int index, is_odd; + int num_tbs; + + tfd = &tfd_tmp[index]; /* Sanity check on number of chunks */ - counter = IWL_GET_BITS(*bd, num_tbs); - if (counter > MAX_NUM_OF_TBS) { - IWL_ERROR("Too many chunks: %i\n", counter); + num_tbs = iwl_tfd_get_num_tbs(tfd); + + if (num_tbs >= IWL_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", num_tbs); /* @todo issue fatal error, it is quite serious situation */ - return 0; + return; } - /* Unmap chunks, if any. - * TFD info for odd chunks is different format than for even chunks. */ - for (i = 0; i < counter; i++) { - index = i / 2; - is_odd = i & 0x1; - - if (is_odd) - pci_unmap_single( - dev, - IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16), - IWL_GET_BITS(bd->pa[index], tb2_len), + /* Unmap tx_cmd */ + if (num_tbs) + pci_unmap_single(dev, + pci_unmap_addr(&txq->cmd[index]->meta, mapping), + pci_unmap_len(&txq->cmd[index]->meta, len), PCI_DMA_TODEVICE); - else if (i > 0) - pci_unmap_single(dev, - le32_to_cpu(bd->pa[index].tb1_addr), - IWL_GET_BITS(bd->pa[index], tb1_len), - PCI_DMA_TODEVICE); - - /* Free SKB, if any, for this chunk */ - if (txq->txb[txq->q.read_ptr].skb[i]) { - struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; + /* Unmap chunks, if any. */ + for (i = 1; i < num_tbs; i++) { + pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), + iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - txq->txb[txq->q.read_ptr].skb[i] = NULL; + if (txq->txb) { + dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]); + txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; } } - return 0; } -static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, - dma_addr_t addr, u16 len) +static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, + struct iwl_tfd *tfd, + dma_addr_t addr, u16 len) { - int index, is_odd; - struct iwl_tfd_frame *tfd = ptr; - u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + u32 num_tbs = iwl_tfd_get_num_tbs(tfd); /* Each TFD can point to a maximum 20 Tx buffers */ - if (num_tbs >= MAX_NUM_OF_TBS) { + if (num_tbs >= IWL_NUM_OF_TBS) { IWL_ERROR("Error can not send more than %d chunks\n", - MAX_NUM_OF_TBS); + IWL_NUM_OF_TBS); return -EINVAL; } - index = num_tbs / 2; - is_odd = num_tbs & 0x1; - - if (!is_odd) { - tfd->pa[index].tb1_addr = cpu_to_le32(addr); - IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl_get_dma_hi_address(addr)); - IWL_SET_BITS(tfd->pa[index], tb1_len, len); - } else { - IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, - (u32) (addr & 0xffff)); - IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); - IWL_SET_BITS(tfd->pa[index], tb2_len, len); - } + BUG_ON(addr & ~DMA_BIT_MASK(36)); + if (unlikely(addr & ~IWL_TX_DMA_MASK)) + IWL_ERROR("Unaligned address = %llx\n", + (unsigned long long)addr); - IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + iwl_tfd_set_tb(tfd, num_tbs, addr, len); return 0; } @@ -224,8 +244,8 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); + pci_free_consistent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* De-alloc array of per-TFD driver data */ kfree(txq->txb); @@ -263,8 +283,8 @@ static void iwl_cmd_queue_free(struct iwl_priv *priv) /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); + pci_free_consistent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); @@ -364,13 +384,13 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ - txq->bd = pci_alloc_consistent(dev, - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + txq->tfds = pci_alloc_consistent(dev, + sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX, &txq->q.dma_addr); - if (!txq->bd) { + if (!txq->tfds) { IWL_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX); goto error; } txq->q.id = id; @@ -394,15 +414,15 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, static int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int rc; + int ret; unsigned long flags; int txq_id = txq->q.id; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Circular buffer (TFD queue in DRAM) physical base address */ @@ -410,10 +430,10 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, txq->q.dma_addr >> 8); /* Enable DMA channel, using same id as for TFD queue */ - iwl_write_direct32( - priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -788,7 +808,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_tfd_frame *tfd; + struct iwl_tfd *tfd; struct iwl_tx_queue *txq; struct iwl_queue *q; struct iwl_cmd *out_cmd; @@ -882,7 +902,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); /* Set up first empty TFD within this queue's circular TFD buffer */ - tfd = &txq->bd[q->write_ptr]; + tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); idx = get_cmd_index(q, q->write_ptr, 0); @@ -931,12 +951,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = pci_map_single(priv->pci_dev, out_cmd, - sizeof(struct iwl_cmd), PCI_DMA_TODEVICE); - txcmd_phys += offsetof(struct iwl_cmd, hdr); - + txcmd_phys = pci_map_single(priv->pci_dev, + out_cmd, sizeof(struct iwl_cmd), + PCI_DMA_TODEVICE); + pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); + pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd)); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ + txcmd_phys += offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (info->control.hw_key) @@ -969,7 +991,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -1030,7 +1052,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; + struct iwl_tfd *tfd; struct iwl_cmd *out_cmd; dma_addr_t phys_addr; unsigned long flags; @@ -1059,7 +1081,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) spin_lock_irqsave(&priv->hcmd_lock, flags); - tfd = &txq->bd[q->write_ptr]; + tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); @@ -1080,9 +1102,13 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; len = (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); - phys_addr = pci_map_single(priv->pci_dev, out_cmd, len, - PCI_DMA_TODEVICE); + + phys_addr = pci_map_single(priv->pci_dev, out_cmd, + len, PCI_DMA_TODEVICE); + pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); + pci_unmap_len_set(&out_cmd->meta, len, len); phys_addr += offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); #ifdef CONFIG_IWLWIFI_DEBUG @@ -1132,8 +1158,9 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) return 0; } - for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + for (index = iwl_queue_inc_wrap(index, q->n_bd); + q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); @@ -1157,44 +1184,34 @@ EXPORT_SYMBOL(iwl_tx_queue_reclaim); * need to be reclaimed. As result, some free space forms. If there is * enough free space (> low mark), wake the stack that feeds us. */ -static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, + int idx, int cmd_idx) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *bd = &txq->bd[index]; - dma_addr_t dma_addr; - int is_odd, buf_len; int nfreed = 0; - if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) { IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); + idx, q->n_bd, q->write_ptr, q->read_ptr); return; } - for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + pci_unmap_single(priv->pci_dev, + pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), + pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), + PCI_DMA_TODEVICE); + + for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (nfreed > 1) { - IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + if (nfreed++ > 0) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); queue_work(priv->workqueue, &priv->restart); } - is_odd = (index/2) & 0x1; - if (is_odd) { - dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16); - buf_len = IWL_GET_BITS(bd->pa[index], tb2_len); - } else { - dma_addr = le32_to_cpu(bd->pa[index].tb1_addr); - buf_len = IWL_GET_BITS(bd->pa[index], tb1_len); - } - pci_unmap_single(priv->pci_dev, dma_addr, buf_len, - PCI_DMA_TODEVICE); - nfreed++; } } @@ -1234,7 +1251,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl_hcmd_queue_reclaim(priv, txq_id, index); + iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); -- cgit v1.1 From b88b15dfbddc8837569c6dea49348791357de4aa Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 14 Oct 2008 12:32:49 -0700 Subject: iwlwifi: tx command must run on same tfd as packet This patch makes clear that tx command is attached to the same tfd as the tx packet Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c3656c4..6cf4a7c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -817,7 +817,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - u16 len, idx, len_org; + u16 len, len_org; u16 seq_number = 0; __le16 fc; u8 hdr_len, unicast; @@ -904,14 +904,13 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up first empty TFD within this queue's circular TFD buffer */ tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); - idx = get_cmd_index(q, q->write_ptr, 0); /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = txq->cmd[idx]; + out_cmd = txq->cmd[q->write_ptr]; tx_cmd = &out_cmd->cmd.tx; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); -- cgit v1.1 From 0fdd7c5d2defe8c6873eb8a40a880eb0dc59573d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 03:55:37 +0200 Subject: p54: broken out edcf changes This patch series hopefully increases p54's "longterm" stability. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 9 +++- drivers/net/wireless/p54/p54common.c | 99 ++++++++++++++---------------------- drivers/net/wireless/p54/p54common.h | 28 +++++----- 3 files changed, 58 insertions(+), 78 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1da96fe..1dace10 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -49,6 +49,13 @@ struct p54_control_hdr { u8 data[0]; } __attribute__ ((packed)); +struct p54_edcf_queue_param { + __le16 aifs; + __le16 cwmin; + __le16 cwmax; + __le16 txop; +} __attribute__ ((packed)); + #define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -85,13 +92,13 @@ struct p54_common { u8 version; u8 rx_antenna; unsigned int tx_hdr_len; - void *cached_vdcf; unsigned int fw_var; unsigned int fw_interface; unsigned int output_power; u32 tsf_low32; u32 tsf_high32; struct ieee80211_tx_queue_stats tx_stats[8]; + struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; struct timer_list stats_timer; struct completion stats_comp; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 2370901..7ddb93b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1114,53 +1114,41 @@ do { \ queue.txop = cpu_to_le16(_txop); \ } while(0) -static void p54_init_vdcf(struct ieee80211_hw *dev) +static int p54_set_edcf(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; + struct p54_edcf *edcf; - /* all USB V1 adapters need a extra headroom */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + hdr = kzalloc(priv->tx_hdr_len + sizeof(*hdr) + sizeof(*edcf), + GFP_ATOMIC); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*vdcf)); + hdr->len = cpu_to_le16(sizeof(*edcf)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); - hdr->req_id = cpu_to_le32(priv->rx_start); - - vdcf = (struct p54_tx_control_vdcf *) hdr->data; - - P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47); - P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94); - P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0); - P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0); -} - -static void p54_set_vdcf(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; - - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); - - vdcf = (struct p54_tx_control_vdcf *) hdr->data; - + hdr->retry1 = hdr->retry2 = 0; + edcf = (struct p54_edcf *)hdr->data; if (priv->use_short_slot) { - vdcf->slottime = 9; - vdcf->magic1 = 0x10; - vdcf->magic2 = 0x00; + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; } else { - vdcf->slottime = 20; - vdcf->magic1 = 0x0a; - vdcf->magic2 = 0x06; + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; } - /* (see prism54/isl_oid.h for further details) */ - vdcf->frameburst = cpu_to_le16(0); + edcf->frameburst = cpu_to_le16(0); + edcf->round_trip_delay = cpu_to_le16(0); + memset(edcf->mapping, 0, sizeof(edcf->mapping)); + memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*edcf)); + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*edcf), 1); + return 0; } static int p54_start(struct ieee80211_hw *dev) @@ -1168,33 +1156,26 @@ static int p54_start(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int err; - if (!priv->cached_vdcf) { - priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+ - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); - - if (!priv->cached_vdcf) - return -ENOMEM; - } - if (!priv->cached_stats) { priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL); - if (!priv->cached_stats) { - kfree(priv->cached_vdcf); - priv->cached_vdcf = NULL; + if (!priv->cached_stats) return -ENOMEM; - } } err = priv->open(dev); if (!err) priv->mode = NL80211_IFTYPE_MONITOR; + P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); + err = p54_set_edcf(dev); + if (!err) + mod_timer(&priv->stats_timer, jiffies + HZ); - p54_init_vdcf(dev); - mod_timer(&priv->stats_timer, jiffies + HZ); return err; } @@ -1264,7 +1245,8 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) priv->rx_antenna = 2; /* automatic */ priv->output_power = conf->power_level << 2; ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); - p54_set_vdcf(dev); + if (!ret) + ret = p54_set_edcf(dev); mutex_unlock(&priv->conf_mutex); return ret; } @@ -1319,20 +1301,14 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; - struct p54_tx_control_vdcf *vdcf; - - vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) - ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); if ((params) && !(queue > 4)) { - P54_SET_QUEUE(vdcf->queue[queue], params->aifs, + P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else return -EINVAL; - p54_set_vdcf(dev); - - return 0; + return p54_set_edcf(dev); } static int p54_init_xbow_synth(struct ieee80211_hw *dev) @@ -1418,7 +1394,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, if (changed & BSS_CHANGED_ERP_SLOT) { priv->use_short_slot = info->use_short_slot; - p54_set_vdcf(dev); + p54_set_edcf(dev); } } @@ -1499,7 +1475,6 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); - kfree(priv->cached_vdcf); } EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 22af41c..2cb3885 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -7,8 +7,12 @@ * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -286,21 +290,15 @@ struct p54_tx_control_led { __le16 duration; } __attribute__ ((packed)); -struct p54_tx_vdcf_queues { - __le16 aifs; - __le16 cwmin; - __le16 cwmax; - __le16 txop; -} __attribute__ ((packed)); - -struct p54_tx_control_vdcf { - u8 padding; +struct p54_edcf { + u8 flags; u8 slottime; - u8 magic1; - u8 magic2; - struct p54_tx_vdcf_queues queue[8]; - u8 pad2[4]; + u8 sifs; + u8 eofpad; + struct p54_edcf_queue_param queue[8]; + u8 mapping[4]; __le16 frameburst; + __le16 round_trip_delay; } __attribute__ ((packed)); struct p54_statistics { -- cgit v1.1 From 0f1be978910092bed5d8dac0774e5cf85d4b4e12 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 03:56:20 +0200 Subject: p54: refactor statistic timer code Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7ddb93b..fcde424 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1151,19 +1151,32 @@ static int p54_set_edcf(struct ieee80211_hw *dev) return 0; } -static int p54_start(struct ieee80211_hw *dev) +static int p54_init_stats(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - int err; + struct p54_control_hdr *hdr; + struct p54_statistics *stats; - if (!priv->cached_stats) { - priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + priv->cached_stats = kzalloc(priv->tx_hdr_len + + sizeof(*hdr) + sizeof(*stats), GFP_KERNEL); - if (!priv->cached_stats) + if (!priv->cached_stats) return -ENOMEM; - } + + hdr = (void *) priv->cached_stats + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8000); + hdr->len = cpu_to_le16(sizeof(*stats)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); + hdr->retry1 = hdr->retry2 = 0; + + mod_timer(&priv->stats_timer, jiffies + HZ); + return 0; +} + +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; err = priv->open(dev); if (!err) @@ -1174,7 +1187,7 @@ static int p54_start(struct ieee80211_hw *dev) P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); err = p54_set_edcf(dev); if (!err) - mod_timer(&priv->stats_timer, jiffies + HZ); + err = p54_init_stats(dev); return err; } @@ -1185,6 +1198,8 @@ static void p54_stop(struct ieee80211_hw *dev) struct sk_buff *skb; del_timer(&priv->stats_timer); + kfree(priv->cached_stats); + priv->cached_stats = NULL; while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); priv->stop(dev); @@ -1346,11 +1361,7 @@ static void p54_statistics_timer(unsigned long data) struct p54_statistics *stats; BUG_ON(!priv->cached_stats); - - hdr = (void *)priv->cached_stats + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*stats)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); + hdr = (void *) priv->cached_stats + priv->tx_hdr_len; p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); -- cgit v1.1 From 9de5776ff33a006b864341a6ec8d31f1a3c628cf Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 04:05:51 +0200 Subject: p54: p54: refactor p54_rx_frame_sent the long names and the nesting in p54_rx_frame_sent really became a "line longer than 80 characters" problem. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 118 ++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 57 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index fcde424..68ae8c0 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -549,73 +549,77 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) 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); + struct p54_control_hdr *entry_hdr; + struct p54_tx_control_allocdata *entry_data; + int pad = 0; + range = (void *)info->rate_driver_data; - if (range->start_addr == addr) { - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; - int pad = 0; + if (range->start_addr != addr) { + last_addr = range->end_addr; + entry = entry->next; + continue; + } - if (entry->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct memrecord *mr; + if (entry->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; - ni = IEEE80211_SKB_CB(entry->next); - mr = (struct memrecord *)ni->rate_driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + ni = IEEE80211_SKB_CB(entry->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; + } else + freed = priv->rx_end - last_addr; - last_addr = range->end_addr; - __skb_unlink(entry, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - - /* - * Clear manually, ieee80211_tx_info_clear_status would - * clear the counts too and we need them. - */ - memset(&info->status.ampdu_ack_len, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); - BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, - status.ampdu_ack_len) != 23); - - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) - pad = entry_data->align[0]; - - /* walk through the rates array and adjust the counts */ - count = payload->retries; - for (idx = 0; idx < 4; idx++) { - if (count >= info->status.rates[idx].count) { - count -= info->status.rates[idx].count; - } else if (count > 0) { - info->status.rates[idx].count = count; - count = 0; - } else { - info->status.rates[idx].idx = -1; - info->status.rates[idx].count = 0; - } + last_addr = range->end_addr; + __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + + entry_hdr = (struct p54_control_hdr *) entry->data; + entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; + if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) + pad = entry_data->align[0]; + + /* walk through the rates array and adjust the counts */ + count = payload->retries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; } + } - priv->tx_stats[entry_data->hw_queue].len--; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - !(payload->status & 0x01)) - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = p54_rssi_to_dbm(dev, - le16_to_cpu(payload->ack_rssi)); - skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry); - goto out; - } else - last_addr = range->end_addr; - entry = entry->next; + priv->tx_stats[entry_data->hw_queue].len--; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + if (payload->status & 0x02) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.ack_signal = p54_rssi_to_dbm(dev, + le16_to_cpu(payload->ack_rssi)); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(dev, entry); + goto out; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + - sizeof(struct p54_control_hdr)) + if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } -- cgit v1.1 From b92f30d65aeb0502e2ed8beb80c8465578b40002 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 04:07:16 +0200 Subject: p54: fix memory management We have to be careful if multiple "control frames" are passed in a very short intervals to the device's firmware. As p54_assign_address always put them into same memory location. To guarantee that this won't happen anymore, we have to treat control frames like normal data frames in the devices own memory management. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 7 +- drivers/net/wireless/p54/p54common.c | 288 ++++++++++++++++++++--------------- drivers/net/wireless/p54/p54pci.c | 23 +-- drivers/net/wireless/p54/p54usb.c | 74 ++++++--- 4 files changed, 229 insertions(+), 163 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1dace10..e9988e7 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -69,8 +69,8 @@ struct p54_common { u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; - void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx); + void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; @@ -102,13 +102,14 @@ struct p54_common { struct ieee80211_low_level_stats stats; struct timer_list stats_timer; struct completion stats_comp; - void *cached_stats; + struct sk_buff *cached_stats; int noise; void *eeprom; struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_read_eeprom(struct ieee80211_hw *dev); struct ieee80211_hw *p54_init_common(size_t priv_data_len); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 68ae8c0..13080b1 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -528,11 +528,55 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + for (i = 0; i < dev->queues; i++) if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_tx_info *info; + struct memrecord *range; + unsigned long flags; + u32 freed = 0, last_addr = priv->rx_start; + + if (!skb || !dev) + return; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->prev); + mr = (struct memrecord *)ni->rate_driver_data; + last_addr = mr->end_addr; + } + if (skb->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; + } else + freed = priv->rx_end - last_addr; + __skb_unlink(skb, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + kfree_skb(skb); + + if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + p54_wake_free_queues(dev); +} +EXPORT_SYMBOL_GPL(p54_free_skb); + static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; @@ -705,12 +749,14 @@ EXPORT_SYMBOL_GPL(p54_rx); * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees * allocated areas. */ -static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, +static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, struct p54_control_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; + struct ieee80211_tx_info *info; + struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -718,12 +764,15 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int left; len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; + if (!skb) + return -EINVAL; + spin_lock_irqsave(&priv->tx_queue.lock, flags); left = skb_queue_len(&priv->tx_queue); while (left--) { u32 hole_size; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->rate_driver_data; + info = IEEE80211_SKB_CB(entry); + range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -738,27 +787,57 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); - struct memrecord *range = (void *)info->rate_driver_data; + info = IEEE80211_SKB_CB(target_skb); + range = (void *)info->rate_driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); - if (skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct memrecord *range = (void *)info->rate_driver_data; - range->start_addr = target_addr; - range->end_addr = target_addr + len; - __skb_queue_after(&priv->tx_queue, target_skb, skb); - if (largest_hole < priv->rx_mtu + priv->headroom + - priv->tailroom + - sizeof(struct p54_control_hdr)) - ieee80211_stop_queues(dev); + if (!target_skb) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + ieee80211_stop_queues(dev); + return -ENOMEM; } + + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + if (largest_hole < priv->headroom + sizeof(struct p54_control_hdr) + + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + ieee80211_stop_queues(dev); + data->req_id = cpu_to_le32(target_addr + priv->headroom); + return 0; +} + +static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, + u16 hdr_flags, u16 len, u16 type, gfp_t memflags) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct sk_buff *skb; + + skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags); + if (!skb) + return NULL; + skb_reserve(skb, priv->tx_hdr_len); + + hdr = (struct p54_control_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->magic1 = cpu_to_le16(hdr_flags); + hdr->len = cpu_to_le16(len - sizeof(*hdr)); + hdr->type = cpu_to_le16(type); + hdr->retry1 = hdr->retry2 = 0; + + if (unlikely(p54_assign_address(dev, skb, hdr, len))) { + kfree_skb(skb); + return NULL; + } + return skb; } int p54_read_eeprom(struct ieee80211_hw *dev) @@ -766,36 +845,31 @@ int p54_read_eeprom(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; + struct sk_buff *skb; size_t eeprom_size = 0x2020, offset = 0, blocksize; int ret = -ENOMEM; void *eeprom = NULL; - hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8000, sizeof(*hdr) + sizeof(*eeprom_hdr) + + EEPROM_READBACK_LEN, + P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); + if (!skb) goto free; - priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); if (!priv->eeprom) goto free; - eeprom = kzalloc(eeprom_size, GFP_KERNEL); if (!eeprom) goto free; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); - hdr->retry1 = hdr->retry2 = 0; - eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, + sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN); while (eeprom_size) { blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); - hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr)); eeprom_hdr->offset = cpu_to_le16(offset); eeprom_hdr->len = cpu_to_le16(blocksize); - p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) + - sizeof(*hdr)); - priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0); + priv->tx(dev, skb, 0); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -813,7 +887,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev) free: kfree(priv->eeprom); priv->eeprom = NULL; - kfree(hdr); + p54_free_skb(dev, skb); kfree(eeprom); return ret; @@ -936,9 +1010,11 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->align[0] = padding; /* modifies skb->cb and with it info, so must be last! */ - p54_assign_address(dev, skb, hdr, skb->len); - - priv->tx(dev, hdr, skb->len, 0); + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) { + skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + return NETDEV_TX_BUSY; + } + priv->tx(dev, skb, 0); return 0; } @@ -946,22 +1022,22 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, const u8 *bssid) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_filter *filter; - size_t data_len; - - hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + - priv->tx_hdr_len, GFP_ATOMIC); - if (!hdr) - return -ENOMEM; + u16 data_len = sizeof(struct p54_control_hdr) + sizeof(*filter); - hdr = (void *)hdr + priv->tx_hdr_len; + if (priv->fw_var < 0x500) + data_len += P54_TX_CONTROL_FILTER_V1_LEN; + else + data_len += P54_TX_CONTROL_FILTER_V2_LEN; - filter = (struct p54_tx_control_filter *) hdr->data; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); + skb = p54_alloc_skb(dev, 0x8001, data_len, P54_CONTROL_TYPE_FILTER_SET, + GFP_ATOMIC); + if (!skb) + return -ENOMEM; - priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); + filter = (struct p54_tx_control_filter *) skb_put(skb, sizeof(*filter)); + filter->filter_type = priv->filter_type = cpu_to_le16(filter_type); memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); if (!bssid) memset(filter->bssid, ~0, ETH_ALEN); @@ -969,47 +1045,37 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, memcpy(filter->bssid, bssid, ETH_ALEN); filter->rx_antenna = priv->rx_antenna; if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_FILTER_V1_LEN; filter->v1.basic_rate_mask = cpu_to_le32(0x15f); filter->v1.rx_addr = cpu_to_le32(priv->rx_end); filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); filter->v1.rxhw = cpu_to_le16(priv->rxhw); filter->v1.wakeup_timer = cpu_to_le16(500); } else { - data_len = P54_TX_CONTROL_FILTER_V2_LEN; filter->v2.rx_addr = cpu_to_le32(priv->rx_end); filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); filter->v2.rxhw = cpu_to_le16(priv->rxhw); filter->v2.timer = cpu_to_le16(1000); } - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb, 1); return 0; } static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_channel *chan; unsigned int i; - size_t data_len; + size_t data_len = sizeof(struct p54_control_hdr) + sizeof(*chan); void *entry; - hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, data_len, + P54_CONTROL_TYPE_CHANNEL_CHANGE, GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - - chan = (struct p54_tx_control_channel *) hdr->data; - - hdr->magic1 = cpu_to_le16(0x8001); - - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - + chan = (struct p54_tx_control_channel *) skb_put(skb, sizeof(*chan)); + memset(chan->padding1, 0, sizeof(chan->padding1)); chan->flags = cpu_to_le16(0x1); chan->dwell = cpu_to_le16(0x0); @@ -1065,48 +1131,37 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) chan->v1.rssical_mul = cpu_to_le16(130); chan->v1.rssical_add = cpu_to_le16(0xfe70); } else { - data_len = P54_TX_CONTROL_CHANNEL_V2_LEN; chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_add = cpu_to_le16(0xfe70); chan->v2.basic_rate_mask = cpu_to_le32(0x15f); } - - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb, 1); return 0; err: printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); - kfree(hdr); + kfree_skb(skb); return -EINVAL; } static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_led *led; - hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, sizeof(*led) + + sizeof(struct p54_control_hdr), + P54_CONTROL_TYPE_LED, GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*led)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); - - led = (struct p54_tx_control_led *) hdr->data; + led = (struct p54_tx_control_led *)skb_put(skb, sizeof(*led)); led->mode = cpu_to_le16(mode); led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); led->duration = cpu_to_le16(1000); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1); - + priv->tx(dev, skb, 1); return 0; } @@ -1121,20 +1176,15 @@ do { \ static int p54_set_edcf(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_edcf *edcf; - hdr = kzalloc(priv->tx_hdr_len + sizeof(*hdr) + sizeof(*edcf), - GFP_ATOMIC); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + + sizeof(*edcf), P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*edcf)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); - hdr->retry1 = hdr->retry2 = 0; - edcf = (struct p54_edcf *)hdr->data; + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); if (priv->use_short_slot) { edcf->slottime = 9; edcf->sifs = 0x10; @@ -1149,30 +1199,22 @@ static int p54_set_edcf(struct ieee80211_hw *dev) edcf->round_trip_delay = cpu_to_le16(0); memset(edcf->mapping, 0, sizeof(edcf->mapping)); memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*edcf)); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*edcf), 1); + priv->tx(dev, skb, 1); return 0; } static int p54_init_stats(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_statistics *stats; - - priv->cached_stats = kzalloc(priv->tx_hdr_len + - sizeof(*hdr) + sizeof(*stats), GFP_KERNEL); + priv->cached_stats = p54_alloc_skb(dev, 0x8000, + sizeof(struct p54_control_hdr) + + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, + GFP_KERNEL); if (!priv->cached_stats) return -ENOMEM; - hdr = (void *) priv->cached_stats + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*stats)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); - hdr->retry1 = hdr->retry2 = 0; - mod_timer(&priv->stats_timer, jiffies + HZ); return 0; } @@ -1202,10 +1244,11 @@ static void p54_stop(struct ieee80211_hw *dev) struct sk_buff *skb; del_timer(&priv->stats_timer); - kfree(priv->cached_stats); + p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); + priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -1333,27 +1376,21 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct sk_buff *skb; struct p54_tx_control_xbow_synth *xbow; - hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + + sizeof(*xbow), P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + GFP_KERNEL); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*xbow)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow)); - - xbow = (struct p54_tx_control_xbow_synth *) hdr->data; + xbow = (struct p54_tx_control_xbow_synth *)skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1); - + memset(xbow->padding, 0, sizeof(xbow->padding)); + priv->tx(dev, skb, 1); return 0; } @@ -1361,14 +1398,10 @@ static void p54_statistics_timer(unsigned long data) { struct ieee80211_hw *dev = (struct ieee80211_hw *) data; struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_statistics *stats; BUG_ON(!priv->cached_stats); - hdr = (void *) priv->cached_stats + priv->tx_hdr_len; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); + priv->tx(dev, priv->cached_stats, 0); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1486,7 +1519,8 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - kfree(priv->cached_stats); + del_timer(&priv->stats_timer); + kfree_skb(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index bba2c90..1bb9584 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -235,7 +235,7 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - kfree(tx_buf[i]); + p54_free_skb(dev, tx_buf[i]); tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -306,8 +306,8 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) return reg ? IRQ_HANDLED : IRQ_NONE; } -static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; @@ -322,18 +322,19 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); + mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = data->req_id; - desc->len = cpu_to_le16(len); + desc->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + desc->len = cpu_to_le16(skb->len); desc->flags = 0; wmb(); ring_control->host_idx[1] = cpu_to_le32(idx + 1); if (free_on_tx) - priv->tx_buf_data[i] = data; + priv->tx_buf_data[i] = skb; spin_unlock_irqrestore(&priv->lock, flags); @@ -342,8 +343,10 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, /* FIXME: unlikely to happen because the device usually runs out of memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) + if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) { + p54_free_skb(dev, skb); printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); + } } static void p54p_stop(struct ieee80211_hw *dev) @@ -393,7 +396,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_data[i]); + p54_free_skb(dev, priv->tx_buf_data[i]); priv->tx_buf_data[i] = NULL; } @@ -405,7 +408,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_mgmt[i]); + p54_free_skb(dev, priv->tx_buf_mgmt[i]); priv->tx_buf_mgmt[i] = NULL; } diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 68f1b80..88fb650 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -135,6 +135,16 @@ static void p54u_rx_cb(struct urb *urb) usb_submit_urb(urb, GFP_ATOMIC); } +static void p54u_tx_reuse_skb_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv; + + skb_pull(skb, priv->common.tx_hdr_len); + usb_free_urb(urb); +} + static void p54u_tx_cb(struct urb *urb) { usb_free_urb(urb); @@ -146,6 +156,16 @@ static void p54u_tx_free_cb(struct urb *urb) usb_free_urb(urb); } +static void p54u_tx_free_skb_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct ieee80211_hw *dev = (struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + + p54_free_skb(dev, skb); + usb_free_urb(urb); +} + static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; @@ -192,8 +212,8 @@ static void p54u_free_urbs(struct ieee80211_hw *dev) } } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; @@ -209,11 +229,14 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, } usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, - sizeof(data->req_id), p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + &((struct p54_control_hdr *)skb->data)->req_id, 4, + p54u_tx_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(addr_urb, GFP_ATOMIC); usb_submit_urb(data_urb, GFP_ATOMIC); @@ -232,31 +255,35 @@ static __le32 p54u_lm87_chksum(const u32 *data, size_t length) return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, - struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; - struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + struct lm87_tx_hdr *hdr; + __le32 checksum; + __le32 addr = ((struct p54_control_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) return; - hdr->chksum = p54u_lm87_chksum((u32 *)data, len); - hdr->device_addr = data->req_id; + checksum = p54u_lm87_chksum((u32 *)skb->data, skb->len); + hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->chksum = checksum; + hdr->device_addr = addr; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, - len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, - dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(data_urb, GFP_ATOMIC); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; @@ -284,11 +311,10 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da reg->addr = cpu_to_le32(P54U_DEV_BASE); reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - len += sizeof(*data); - hdr = (void *)data - sizeof(*hdr); + hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = data->req_id; - hdr->len = cpu_to_le16(len); + hdr->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_control_hdr)); usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), @@ -296,8 +322,10 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da usb_submit_urb(int_urb, GFP_ATOMIC); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(data_urb, GFP_ATOMIC); } -- cgit v1.1 From 5e73444e91889ea6c7a83bc174ef8e8b6aaeea9b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 15 Oct 2008 04:07:56 +0200 Subject: p54: borrow some setup code from stlc45xx This patch initialize all remaining values which are necessary for SPI firmwares. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 4 +- drivers/net/wireless/p54/p54common.c | 75 ++++++++++++++++++------------------ drivers/net/wireless/p54/p54common.h | 18 +++++---- 3 files changed, 51 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index e9988e7..7a3bf75 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -15,7 +15,7 @@ */ enum control_frame_types { - P54_CONTROL_TYPE_FILTER_SET = 0, + P54_CONTROL_TYPE_SETUP = 0, P54_CONTROL_TYPE_CHANNEL_CHANGE, P54_CONTROL_TYPE_FREQDONE, P54_CONTROL_TYPE_DCFINIT, @@ -80,7 +80,7 @@ struct p54_common { struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __le16 filter_type; + u16 mac_mode; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 13080b1..525a684 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1018,43 +1018,48 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) return 0; } -static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_filter *filter; - u16 data_len = sizeof(struct p54_control_hdr) + sizeof(*filter); + struct p54_setup_mac *setup; - if (priv->fw_var < 0x500) - data_len += P54_TX_CONTROL_FILTER_V1_LEN; - else - data_len += P54_TX_CONTROL_FILTER_V2_LEN; - - skb = p54_alloc_skb(dev, 0x8001, data_len, P54_CONTROL_TYPE_FILTER_SET, + skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + + sizeof(*setup), P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); if (!skb) return -ENOMEM; - filter = (struct p54_tx_control_filter *) skb_put(skb, sizeof(*filter)); - filter->filter_type = priv->filter_type = cpu_to_le16(filter_type); - memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + priv->mac_mode = mode; + setup->mac_mode = cpu_to_le16(mode); + memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); if (!bssid) - memset(filter->bssid, ~0, ETH_ALEN); + memset(setup->bssid, ~0, ETH_ALEN); else - memcpy(filter->bssid, bssid, ETH_ALEN); - filter->rx_antenna = priv->rx_antenna; + memcpy(setup->bssid, bssid, ETH_ALEN); + setup->rx_antenna = priv->rx_antenna; if (priv->fw_var < 0x500) { - filter->v1.basic_rate_mask = cpu_to_le32(0x15f); - filter->v1.rx_addr = cpu_to_le32(priv->rx_end); - filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v1.rxhw = cpu_to_le16(priv->rxhw); - filter->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.basic_rate_mask = cpu_to_le32(0x15f); + setup->v1.rx_addr = cpu_to_le32(priv->rx_end); + setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v1.rxhw = cpu_to_le16(priv->rxhw); + setup->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.unalloc0 = cpu_to_le16(0); } else { - filter->v2.rx_addr = cpu_to_le32(priv->rx_end); - filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v2.rxhw = cpu_to_le16(priv->rxhw); - filter->v2.timer = cpu_to_le16(1000); + setup->v2.rx_addr = cpu_to_le32(priv->rx_end); + setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v2.rxhw = cpu_to_le16(priv->rxhw); + setup->v2.timer = cpu_to_le16(1000); + setup->v2.truncate = cpu_to_le16(48896); + setup->v2.basic_rate_mask = cpu_to_le32(0x15f); + setup->v2.sbss_offset = 0; + setup->v2.mcast_window = 0; + setup->v2.rx_rssi_threshold = 0; + setup->v2.rx_ed_threshold = 0; + setup->v2.ref_clock = cpu_to_le32(644245094); + setup->v2.lpf_bandwidth = cpu_to_le16(65535); + setup->v2.osc_start_delay = cpu_to_le16(65535); } priv->tx(dev, skb, 1); return 0; @@ -1272,11 +1277,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + p54_setup_mac(dev, 0, NULL); switch (conf->type) { case NL80211_IFTYPE_STATION: - p54_set_filter(dev, 1, NULL); + p54_setup_mac(dev, 1, NULL); break; default: BUG(); /* impossible */ @@ -1294,7 +1299,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + p54_setup_mac(dev, 0, NULL); } static int p54_config(struct ieee80211_hw *dev, u32 changed) @@ -1320,7 +1325,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - p54_set_filter(dev, 0, conf->bssid); + p54_setup_mac(dev, 0, conf->bssid); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); memcpy(priv->bssid, conf->bssid, ETH_ALEN); mutex_unlock(&priv->conf_mutex); @@ -1342,20 +1347,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev, if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - NULL); + p54_setup_mac(dev, priv->mac_mode, NULL); else - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - priv->bssid); + p54_setup_mac(dev, priv->mac_mode, priv->bssid); } if (changed_flags & FIF_PROMISC_IN_BSS) { if (*total_flags & FIF_PROMISC_IN_BSS) - p54_set_filter(dev, le16_to_cpu(priv->filter_type) | - 0x8, NULL); + p54_setup_mac(dev, priv->mac_mode | 0x8, NULL); else - p54_set_filter(dev, le16_to_cpu(priv->filter_type) & - ~0x8, priv->bssid); + p54_setup_mac(dev, priv->mac_mode & ~0x8, priv->bssid); } } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 2cb3885..125f70a 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -219,8 +219,8 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); -struct p54_tx_control_filter { - __le16 filter_type; +struct p54_setup_mac { + __le16 mac_mode; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 rx_antenna; @@ -240,15 +240,19 @@ struct p54_tx_control_filter { __le16 max_rx; __le16 rxhw; __le16 timer; - __le16 unalloc0; - __le32 unalloc1; + __le16 truncate; + __le32 basic_rate_mask; + u8 sbss_offset; + u8 mcast_window; + u8 rx_rssi_threshold; + u8 rx_ed_threshold; + __le32 ref_clock; + __le16 lpf_bandwidth; + __le16 osc_start_delay; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter)) -#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8) - struct p54_tx_control_channel { __le16 flags; __le16 dwell; -- cgit v1.1 From 27df605ebe2c106c53957dfdaee5d948f01cfc97 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 22 Oct 2008 16:41:55 -0400 Subject: p54: integrate parts of lmac_longbow.h and other parts of stlc45xx This patch removes most/all? of the "magic" numbers and unknown structure variables inside the code and replaces them with meaningful prototypes. (Plus a one line warning fix from Larry Finger .) Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 29 +++-- drivers/net/wireless/p54/p54common.c | 142 +++++++++++---------- drivers/net/wireless/p54/p54common.h | 240 ++++++++++++++++++++++++++++++++--- drivers/net/wireless/p54/p54pci.c | 2 +- drivers/net/wireless/p54/p54usb.c | 8 +- 5 files changed, 316 insertions(+), 105 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 7a3bf75..eb69b90 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -14,17 +14,17 @@ * published by the Free Software Foundation. */ -enum control_frame_types { +enum p54_control_frame_types { P54_CONTROL_TYPE_SETUP = 0, - P54_CONTROL_TYPE_CHANNEL_CHANGE, - P54_CONTROL_TYPE_FREQDONE, + P54_CONTROL_TYPE_SCAN, + P54_CONTROL_TYPE_TRAP, P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_ENCRYPTION, + P54_CONTROL_TYPE_RX_KEYCACHE, P54_CONTROL_TYPE_TIM, - P54_CONTROL_TYPE_POWERMGT, - P54_CONTROL_TYPE_FREEQUEUE, + P54_CONTROL_TYPE_PSM, + P54_CONTROL_TYPE_TXCANCEL, P54_CONTROL_TYPE_TXDONE, - P54_CONTROL_TYPE_PING, + P54_CONTROL_TYPE_BURST, P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_EEPROM_READBACK, @@ -37,15 +37,20 @@ enum control_frame_types { P54_CONTROL_TYPE_XBOW_SYNTH_CFG, P54_CONTROL_TYPE_CCE_QUIET, P54_CONTROL_TYPE_PSM_STA_UNLOCK, + P54_CONTROL_TYPE_PCS, + P54_CONTROL_TYPE_BT_BALANCER = 28, + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, + P54_CONTROL_TYPE_ARPTABLE = 31, + P54_CONTROL_TYPE_BT_OPTIONS = 35 }; -struct p54_control_hdr { - __le16 magic1; +struct p54_hdr { + __le16 flags; __le16 len; __le32 req_id; - __le16 type; /* enum control_frame_types */ - u8 retry1; - u8 retry2; + __le16 type; /* enum p54_control_frame_types */ + u8 rts_tries; + u8 tries; u8 data[0]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 525a684..cf04c72 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -5,8 +5,11 @@ * Copyright (c) 2007, Christian Lamparter * Copyright 2008, Johannes Berg * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * C Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -481,13 +484,13 @@ static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; + struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); u32 tsf32; - if (!(hdr->magic & cpu_to_le16(0x0001))) { + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { if (priv->filter_flags & FIF_FCSFAIL) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; else @@ -512,7 +515,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.flag |= RX_FLAG_TSFT; - if (hdr->magic & cpu_to_le16(0x4000)) + if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; skb_pull(skb, header_len); @@ -571,7 +574,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); kfree_skb(skb); - if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } @@ -580,8 +583,8 @@ EXPORT_SYMBOL_GPL(p54_free_skb); static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; - struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct memrecord *range = NULL; @@ -593,8 +596,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) 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); - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; int pad = 0; range = (void *)info->rate_driver_data; @@ -628,13 +631,13 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) pad = entry_data->align[0]; /* walk through the rates array and adjust the counts */ - count = payload->retries; + count = payload->tries; for (idx = 0; idx < 4; idx++) { if (count >= info->status.rates[idx].count) { count -= info->status.rates[idx].count; @@ -654,7 +657,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if (payload->status & 0x02) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.ack_signal = p54_rssi_to_dbm(dev, - le16_to_cpu(payload->ack_rssi)); + (int)payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); ieee80211_tx_status_irqsafe(dev, entry); goto out; @@ -662,7 +665,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= priv->headroom + sizeof(struct p54_control_hdr) + 48 + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } @@ -670,7 +673,7 @@ out: static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; struct p54_common *priv = dev->priv; @@ -685,7 +688,7 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; u32 tsf32 = le32_to_cpu(stats->tsf32); @@ -705,7 +708,7 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; switch (le16_to_cpu(hdr->type)) { case P54_CONTROL_TYPE_TXDONE: @@ -750,7 +753,7 @@ EXPORT_SYMBOL_GPL(p54_rx); * allocated areas. */ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len) + struct p54_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; @@ -807,7 +810,7 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - if (largest_hole < priv->headroom + sizeof(struct p54_control_hdr) + + if (largest_hole < priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) ieee80211_stop_queues(dev); @@ -819,7 +822,7 @@ static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags, u16 len, u16 type, gfp_t memflags) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; + struct p54_hdr *hdr; struct sk_buff *skb; skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags); @@ -827,11 +830,11 @@ static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, return NULL; skb_reserve(skb, priv->tx_hdr_len); - hdr = (struct p54_control_hdr *) skb_put(skb, sizeof(*hdr)); - hdr->magic1 = cpu_to_le16(hdr_flags); + hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le16(hdr_flags); hdr->len = cpu_to_le16(len - sizeof(*hdr)); hdr->type = cpu_to_le16(type); - hdr->retry1 = hdr->retry2 = 0; + hdr->tries = hdr->rts_tries = 0; if (unlikely(p54_assign_address(dev, skb, hdr, len))) { kfree_skb(skb); @@ -843,7 +846,7 @@ static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, int p54_read_eeprom(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = NULL; + struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; struct sk_buff *skb; size_t eeprom_size = 0x2020, offset = 0, blocksize; @@ -899,8 +902,8 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_queue_stats *current_queue; struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_allocdata *txhdr; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; size_t padding, len; int i, j, ridx; u8 rate; @@ -920,17 +923,16 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - txhdr = (struct p54_tx_control_allocdata *) - skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) - hdr->magic1 = cpu_to_le16(0x4010); + hdr->flags = cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN); else - hdr->magic1 = cpu_to_le16(0x0010); + hdr->flags = cpu_to_le16(0); hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = info->control.rates[0].count; + hdr->rts_tries = info->control.rates[0].count; /* * we register the rates in perfect order, and @@ -996,16 +998,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ridx++; } } - hdr->retry2 = ridx; - + hdr->tries = ridx; + txhdr->crypt_offset = 0; + txhdr->rts_rate_idx = 0; txhdr->key_type = 0; txhdr->key_len = 0; txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->backlog = 32; + memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; txhdr->output_power = priv->output_power; - txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? - 0 : cts_rate; + txhdr->cts_rate = cts_rate; if (padding) txhdr->align[0] = padding; @@ -1024,8 +1028,8 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) struct sk_buff *skb; struct p54_setup_mac *setup; - skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + - sizeof(*setup), P54_CONTROL_TYPE_SETUP, + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1069,19 +1073,19 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_channel *chan; + struct p54_scan *chan; unsigned int i; - size_t data_len = sizeof(struct p54_control_hdr) + sizeof(*chan); void *entry; - skb = p54_alloc_skb(dev, 0x8001, data_len, - P54_CONTROL_TYPE_CHANNEL_CHANGE, GFP_ATOMIC); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, + GFP_ATOMIC); if (!skb) return -ENOMEM; - chan = (struct p54_tx_control_channel *) skb_put(skb, sizeof(*chan)); + chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); memset(chan->padding1, 0, sizeof(chan->padding1)); - chan->flags = cpu_to_le16(0x1); + chan->mode = cpu_to_le16(P54_SCAN_EXIT); chan->dwell = cpu_to_le16(0x0); for (i = 0; i < priv->iq_autocal_len; i++) { @@ -1132,13 +1136,13 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) } if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_CHANNEL_V1_LEN; chan->v1.rssical_mul = cpu_to_le16(130); chan->v1.rssical_add = cpu_to_le16(0xfe70); } else { chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_add = cpu_to_le16(0xfe70); chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + memset(chan->v2.rts_rates, 0, 8); } priv->tx(dev, skb, 1); return 0; @@ -1153,15 +1157,15 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_led *led; + struct p54_led *led; - skb = p54_alloc_skb(dev, 0x8001, sizeof(*led) + - sizeof(struct p54_control_hdr), - P54_CONTROL_TYPE_LED, GFP_ATOMIC); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_LED, + GFP_ATOMIC); if (!skb) return -ENOMEM; - led = (struct p54_tx_control_led *)skb_put(skb, sizeof(*led)); + led = (struct p54_led *)skb_put(skb, sizeof(*led)); led->mode = cpu_to_le16(mode); led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); @@ -1184,8 +1188,9 @@ static int p54_set_edcf(struct ieee80211_hw *dev) struct sk_buff *skb; struct p54_edcf *edcf; - skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + - sizeof(*edcf), P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_DCFINIT, + GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1212,11 +1217,9 @@ static int p54_init_stats(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - priv->cached_stats = p54_alloc_skb(dev, 0x8000, - sizeof(struct p54_control_hdr) + - sizeof(struct p54_statistics), - P54_CONTROL_TYPE_STAT_READBACK, - GFP_KERNEL); + priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, + sizeof(struct p54_hdr) + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); if (!priv->cached_stats) return -ENOMEM; @@ -1277,11 +1280,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_setup_mac(dev, 0, NULL); + p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); switch (conf->type) { case NL80211_IFTYPE_STATION: - p54_setup_mac(dev, 1, NULL); + p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); break; default: BUG(); /* impossible */ @@ -1299,7 +1302,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_setup_mac(dev, 0, NULL); + p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); } static int p54_config(struct ieee80211_hw *dev, u32 changed) @@ -1325,7 +1328,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - p54_setup_mac(dev, 0, conf->bssid); + p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); memcpy(priv->bssid, conf->bssid, ETH_ALEN); mutex_unlock(&priv->conf_mutex); @@ -1378,15 +1381,16 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; - struct p54_tx_control_xbow_synth *xbow; + struct p54_xbow_synth *xbow; - skb = p54_alloc_skb(dev, 0x8001, sizeof(struct p54_control_hdr) + - sizeof(*xbow), P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow) + + sizeof(struct p54_hdr), + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); if (!skb) return -ENOMEM; - xbow = (struct p54_tx_control_xbow_synth *)skb_put(skb, sizeof(*xbow)); + xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); @@ -1504,8 +1508,8 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) */ dev->max_rates = 4; dev->max_rate_tries = 7; - dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + - sizeof(struct p54_tx_control_allocdata); + dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + + sizeof(struct p54_tx_data); mutex_init(&priv->conf_mutex); init_completion(&priv->eeprom_comp); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 125f70a..b1101fe 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -33,6 +33,13 @@ struct bootrec_exp_if { __le16 top_compat; } __attribute__((packed)); +#define BR_DESC_PRIV_CAP_WEP BIT(0) +#define BR_DESC_PRIV_CAP_TKIP BIT(1) +#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) +#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) +#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) +#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) + struct bootrec_desc { __le16 modes; __le16 flags; @@ -40,7 +47,12 @@ struct bootrec_desc { __le32 rx_end; u8 headroom; u8 tailroom; - u8 unimportant[6]; + u8 tx_queues; + u8 tx_depth; + u8 privacy_caps; + u8 rx_keycache_size; + u8 time_size; + u8 padding; u8 rates[16]; u8 padding2[4]; __le16 rx_mtu; @@ -56,6 +68,34 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + +#define P54_HDR_FLAG_DATA_ALIGN BIT(14) +#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) +#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) +#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) +#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) +#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) +#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) +#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) +#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) +#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) +#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) +#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) +#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) + +#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) +#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) +#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) +#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) +#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) +#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) +#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) +#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) +#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) +#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) + /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ struct pda_entry { @@ -182,36 +222,91 @@ struct p54_eeprom_lm86 { u8 data[0]; } __attribute__ ((packed)); -struct p54_rx_hdr { - __le16 magic; +enum p54_rx_decrypt_status { + P54_DECRYPT_NONE = 0, + P54_DECRYPT_OK, + P54_DECRYPT_NOKEY, + P54_DECRYPT_NOMICHAEL, + P54_DECRYPT_NOCKIPMIC, + P54_DECRYPT_FAIL_WEP, + P54_DECRYPT_FAIL_TKIP, + P54_DECRYPT_FAIL_MICAHEL, + P54_DECRYPT_FAIL_CKIPKP, + P54_DECRYPT_FAIL_CKIPMIC, + P54_DECRYPT_FAIL_AESCCMP +}; + +struct p54_rx_data { + __le16 flags; __le16 len; __le16 freq; u8 antenna; u8 rate; u8 rssi; u8 quality; - u16 unknown2; + u8 decrypt_status; + u8 rssi_raw; __le32 tsf32; __le32 unalloc0; u8 align[0]; } __attribute__ ((packed)); -struct p54_frame_sent_hdr { +enum p54_trap_type { + P54_TRAP_SCAN = 0, + P54_TRAP_TIMER, + P54_TRAP_BEACON_TX, + P54_TRAP_FAA_RADIO_ON, + P54_TRAP_FAA_RADIO_OFF, + P54_TRAP_RADAR, + P54_TRAP_NO_BEACON, + P54_TRAP_TBTT, + P54_TRAP_SCO_ENTER, + P54_TRAP_SCO_EXIT +}; + +struct p54_trap { + __le16 event; + __le16 frequency; +} __attribute__ ((packed)); + +enum p54_frame_sent_status { + P54_TX_OK = 0, + P54_TX_FAILED, + P54_TX_PSM, + P54_TX_PSM_CANCELLED +}; + +struct p54_frame_sent { u8 status; - u8 retries; - __le16 ack_rssi; + u8 tries; + u8 ack_rssi; + u8 quality; __le16 seq; - u16 rate; + u8 antenna; + u8 padding; } __attribute__ ((packed)); -struct p54_tx_control_allocdata { +enum p54_tx_data_crypt { + P54_CRYPTO_NONE = 0, + P54_CRYPTO_WEP, + P54_CRYPTO_TKIP, + P54_CRYPTO_TKIPMICHAEL, + P54_CRYPTO_CCX_WEPMIC, + P54_CRYPTO_CCX_KPMIC, + P54_CRYPTO_CCX_KP, + P54_CRYPTO_AESCCMP +}; + +struct p54_tx_data { u8 rateset[8]; - u8 unalloc0[2]; + u8 rts_rate_idx; + u8 crypt_offset; u8 key_type; u8 key_len; u8 key[16]; u8 hw_queue; - u8 unalloc1[9]; + u8 backlog; + __le16 durations[4]; u8 tx_antenna; u8 output_power; u8 cts_rate; @@ -219,6 +314,16 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); +#define P54_FILTER_TYPE_NONE 0 +#define P54_FILTER_TYPE_STATION BIT(0) +#define P54_FILTER_TYPE_IBSS BIT(1) +#define P54_FILTER_TYPE_AP BIT(2) +#define P54_FILTER_TYPE_TRANSPARENT BIT(3) +#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) +#define P54_FILTER_TYPE_HIBERNATE BIT(5) +#define P54_FILTER_TYPE_NOACK BIT(6) +#define P54_FILTER_TYPE_RX_DISABLED BIT(7) + struct p54_setup_mac { __le16 mac_mode; u8 mac_addr[ETH_ALEN]; @@ -253,8 +358,16 @@ struct p54_setup_mac { } __attribute__ ((packed)); } __attribute__ ((packed)); -struct p54_tx_control_channel { - __le16 flags; +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) + +#define P54_SCAN_EXIT BIT(0) +#define P54_SCAN_TRAP BIT(1) +#define P54_SCAN_ACTIVE BIT(2) +#define P54_SCAN_FILTER BIT(3) + +struct p54_scan { + __le16 mode; __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; @@ -277,17 +390,17 @@ struct p54_tx_control_channel { struct { __le32 basic_rate_mask; - u8 rts_rates[8]; + u8 rts_rates[8]; __le16 rssical_mul; __le16 rssical_add; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12) -#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel)) +#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12) +#define P54_SCAN_V2_LEN (sizeof(struct p54_scan)) -struct p54_tx_control_led { +struct p54_led { __le16 mode; __le16 led_temporary; __le16 led_permanent; @@ -315,14 +428,103 @@ struct p54_statistics { __le32 tsf32; __le32 airtime; __le32 noise; - __le32 unkn[10]; /* CCE / CCA / RADAR */ + __le32 sample_noise[8]; + __le32 sample_cca; + __le32 sample_tx; } __attribute__ ((packed)); -struct p54_tx_control_xbow_synth { +struct p54_xbow_synth { __le16 magic1; __le16 magic2; __le16 freq; u32 padding[5]; } __attribute__ ((packed)); +struct p54_timer { + __le32 interval; +} __attribute__ ((packed)); + +struct p54_keycache { + u8 entry; + u8 key_id; + u8 mac[ETH_ALEN]; + u8 padding[2]; + u8 key_type; + u8 key_len; + u8 key[24]; +} __attribute__ ((packed)); + +struct p54_burst { + u8 flags; + u8 queue; + u8 backlog; + u8 pad; + __le16 durations[32]; +} __attribute__ ((packed)); + +struct p54_psm_interval { + __le16 interval; + __le16 periods; +} __attribute__ ((packed)); + +#define P54_PSM BIT(0) +#define P54_PSM_DTIM BIT(1) +#define P54_PSM_MCBC BIT(2) +#define P54_PSM_CHECKSUM BIT(3) +#define P54_PSM_SKIP_MORE_DATA BIT(4) +#define P54_PSM_BEACON_TIMEOUT BIT(5) +#define P54_PSM_HFOSLEEP BIT(6) +#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) +#define P54_PSM_LPIT BIT(8) +#define P54_PSM_BF_UCAST_SKIP BIT(9) +#define P54_PSM_BF_MCAST_SKIP BIT(10) + +struct p54_psm { + __le16 mode; + __le16 aid; + struct p54_psm_interval intervals[4]; + u8 beacon_rssi_skip_max; + u8 rssi_delta_threshold; + u8 nr; + u8 exclude[1]; +} __attribute__ ((packed)); + +#define MC_FILTER_ADDRESS_NUM 4 + +struct p54_group_address_table { + __le16 filter_enable; + __le16 num_address; + u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; +} __attribute__ ((packed)); + +struct p54_txcancel { + __le32 req_id; +} __attribute__ ((packed)); + +struct p54_sta_unlock { + u8 addr[ETH_ALEN]; + u16 padding; +} __attribute__ ((packed)); + +#define P54_TIM_CLEAR BIT(15) +struct p54_tx_control_tim { + u8 count; + u8 padding[3]; + __le16 entry[8]; +} __attribute__ ((packed)); + +struct p54_cce_quiet { + __le32 period; +} __attribute__ ((packed)); + +struct p54_bt_balancer { + __le16 prio_thresh; + __le16 acl_thresh; +} __attribute__ ((packed)); + +struct p54_arp_table { + __le16 filter_enable; + u8 ipv4_addr[4]; +} __attribute__ ((packed)); + #endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 1bb9584..3c9d030 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -326,7 +326,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + desc->device_addr = ((struct p54_hdr *)skb->data)->req_id; desc->len = cpu_to_le16(skb->len); desc->flags = 0; diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 88fb650..49739c3 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -230,7 +230,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(addr_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - &((struct p54_control_hdr *)skb->data)->req_id, 4, + &((struct p54_hdr *)skb->data)->req_id, 4, p54u_tx_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), @@ -262,7 +262,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, struct urb *data_urb; struct lm87_tx_hdr *hdr; __le32 checksum; - __le32 addr = ((struct p54_control_hdr *)skb->data)->req_id; + __le32 addr = ((struct p54_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) @@ -313,8 +313,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; - hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_control_hdr)); + hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; + hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr)); usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), -- cgit v1.1 From 65a0667b43ff746b2964b2a257ffff1a4747e19d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 15 Oct 2008 11:06:23 -0700 Subject: iwlwifi: protect headers from double inclusion This patch protects iwl-csr.h and iwl-fh.h from double inclusion by ifndef define endif idiom Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 4 +++- drivers/net/wireless/iwlwifi/iwl-fh.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 662edf4..84f56a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#ifndef __iwl_csr_h__ +#define __iwl_csr_h__ /*=== CSR (control and status registers) ===*/ #define CSR_BASE (0x000) @@ -286,4 +288,4 @@ #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - +#endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index a72efdf..8c48d88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#ifndef __iwl_fh_h__ +#define __iwl_fh_h__ /****************************/ /* Flow Handler Definitions */ @@ -391,3 +393,4 @@ /* TCSR: tx_config register values */ #define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ +#endif /* !__iwl_fh_h__ */ -- cgit v1.1 From 50fb2e4572141770380f5919793c6e575fa3474b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Oct 2008 11:21:49 +0200 Subject: mac80211: remove rate_control_clear "Clearing" the rate control algorithm is pointless, none of the algorithms actually uses this operation and it's not even invoked properly for all channel switching. Also, there's no need to since rate control algorithms work per station. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 7 ------- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 14 -------------- 3 files changed, 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 6afafed..9ce5359 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -2038,11 +2038,6 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, ath_rc_node_update(sc->hw, priv_sta); } -static void ath_rate_clear(void *priv) -{ - return; -} - static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { struct ath_softc *sc = hw->priv; @@ -2092,7 +2087,6 @@ static struct rate_control_ops ath_rate_ops = { .tx_status = ath_tx_status, .get_rate = ath_get_rate, .rate_init = ath_rate_init, - .clear = ath_rate_clear, .alloc = ath_rate_alloc, .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index f440ed0..bfeef70 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -355,12 +355,6 @@ static void rs_free(void *priv) return; } -static void rs_clear(void *priv) -{ - return; -} - - static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; @@ -784,7 +778,6 @@ static struct rate_control_ops rs_ops = { .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, .alloc = rs_alloc, .free = rs_free, .alloc_sta = rs_alloc_sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index f685e5d..6fdb2fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2393,19 +2393,6 @@ static void rs_free(void *priv_rate) return; } -static void rs_clear(void *priv_rate) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_priv *priv = (struct iwl_priv *) priv_rate; - - IWL_DEBUG_RATE("enter\n"); - - /* TODO - add rate scale state reset */ - - IWL_DEBUG_RATE("leave\n"); -#endif /* CONFIG_IWLWIFI_DEBUG */ -} - static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { @@ -2593,7 +2580,6 @@ static struct rate_control_ops rs_ops = { .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, .alloc = rs_alloc, .free = rs_free, .alloc_sta = rs_alloc_sta, -- cgit v1.1 From 8216bfe2518c25f16a60485636e477c9a3b795d5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 16 Oct 2008 16:44:03 -0700 Subject: hostap: Fix sparse warnings A compilation with the command "make C=2 CF="-D__CHECK_ENDIAN__" \ drivers/net/wireless/hostap/" yields the following warnings: CHECK drivers/net/wireless/hostap/hostap_info.c drivers/net/wireless/hostap/hostap_info.c:156:43: warning: incorrect type in argument 2 (different signedness) drivers/net/wireless/hostap/hostap_info.c:156:43: expected unsigned long volatile *addr drivers/net/wireless/hostap/hostap_info.c:156:43: got long * drivers/net/wireless/hostap/hostap_info.c:294:44: warning: incorrect type in argument 2 (different signedness) drivers/net/wireless/hostap/hostap_info.c:294:44: expected unsigned long volatile *addr drivers/net/wireless/hostap/hostap_info.c:294:44: got long * drivers/net/wireless/hostap/hostap_info.c:487:12: warning: incorrect type in argument 2 (different signedness) drivers/net/wireless/hostap/hostap_info.c:487:12: expected unsigned long volatile *addr drivers/net/wireless/hostap/hostap_info.c:487:12: got long * drivers/net/wireless/hostap/hostap_info.c:491:12: warning: incorrect type in argument 2 (different signedness) drivers/net/wireless/hostap/hostap_info.c:491:12: expected unsigned long volatile *addr drivers/net/wireless/hostap/hostap_info.c:491:12: got long * The warnings are fixed with the following compile-tested fix: Signed-off-by: Larry Finger Acked-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_wlan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index ffdf487..8431030b 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -822,7 +822,7 @@ struct local_info { int last_scan_results_count; enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; struct work_struct info_queue; - long pending_info; /* bit field of pending info_queue items */ + unsigned long pending_info; /* bit field of pending info_queue items */ #define PRISM2_INFO_PENDING_LINKSTATUS 0 #define PRISM2_INFO_PENDING_SCANRESULTS 1 int prev_link_status; /* previous received LinkStatus info */ -- cgit v1.1 From 0bbac08f0a23898787978c0b405474e453e9824c Mon Sep 17 00:00:00 2001 From: John Daiker Date: Fri, 17 Oct 2008 12:16:00 -0700 Subject: ath5k: reduce checkpatch.pl errors A few changes to reduce checkpatch.pl errors in the ath5k driver. For the most part, I only fixed cosmetic things, and left the actual 'code flow' untouched (hopefully)! Diff is against wireless-testing HEAD. Signed-off-by: John Daiker Reviewed-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 11 +++++------ drivers/net/wireless/ath5k/initvals.c | 8 ++++---- drivers/net/wireless/ath5k/phy.c | 5 +++-- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3773d98..6caabeb 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2528,8 +2528,7 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, led->led_dev.brightness_set = ath5k_led_brightness_set; err = led_classdev_register(&sc->pdev->dev, &led->led_dev); - if (err) - { + if (err) { ATH5K_WARN(sc, "could not register LED %s\n", name); led->sc = NULL; } @@ -2890,9 +2889,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (*new_flags & FIF_PROMISC_IN_BSS) { rfilt |= AR5K_RX_FILTER_PROM; __set_bit(ATH_STAT_PROMISC, sc->status); - } - else + } else { __clear_bit(ATH_STAT_PROMISC, sc->status); + } } /* Note, AR5K_RX_FILTER_MCAST is already enabled */ @@ -2956,7 +2955,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; /* Set filters */ - ath5k_hw_set_rx_filter(ah,rfilt); + ath5k_hw_set_rx_filter(ah, rfilt); /* Set multicast bits */ ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); @@ -2973,7 +2972,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath5k_softc *sc = hw->priv; int ret = 0; - switch(key->alg) { + switch (key->alg) { case ALG_WEP: /* XXX: fix hardware encryption, its not working. For now * allow software encryption */ diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index ceaa6c4..450bd6e 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -1681,7 +1681,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) */ /* For AR5212 and combatible */ - if (ah->ah_version == AR5K_AR5212){ + if (ah->ah_version == AR5K_AR5212) { /* First set of mode-specific settings */ ath5k_hw_ini_mode_registers(ah, @@ -1695,7 +1695,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ar5212_ini, change_channel); /* Second set of mode-specific settings */ - if (ah->ah_radio == AR5K_RF5111){ + if (ah->ah_radio == AR5K_RF5111) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5111_ini_mode_end), @@ -1706,7 +1706,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ARRAY_SIZE(rf5111_ini_bbgain), rf5111_ini_bbgain, change_channel); - } else if (ah->ah_radio == AR5K_RF5112){ + } else if (ah->ah_radio == AR5K_RF5112) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5112_ini_mode_end), @@ -1716,7 +1716,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, change_channel); - } else if (ah->ah_radio == AR5K_RF5413){ + } else if (ah->ah_radio == AR5K_RF5413) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5413_ini_mode_end), diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index e43f656..69625bf 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1412,7 +1412,8 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, rf_ini = rfregs_2112a; rf_size = ARRAY_SIZE(rfregs_5112a); if (mode < 2) { - ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode); + ATH5K_ERR(ah->ah_sc, "invalid channel mode: %i\n", + mode); return -EINVAL; } mode = mode - 2; /*no a/turboa modes for 2112*/ @@ -1708,7 +1709,7 @@ enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah) if (ah->ah_radio >= AR5K_RF5112) { ath5k_hw_rfregs_gainf_corr(ah); ah->ah_gain.g_current = - ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ? + ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : 0; } -- cgit v1.1 From 558875112c28c7b2744a92c9836c256dd57bc5b6 Mon Sep 17 00:00:00 2001 From: John Daiker Date: Fri, 17 Oct 2008 12:16:17 -0700 Subject: rt2x00: reduce checkpatch.pl errors A few changes to reduce checkpatch.pl errors in the rt2x00 driver. For the most part, I only fixed cosmetic things, and left the actual 'code flow' untouched (hopefully)! Diff is against wireless-testing HEAD. Signed-off-by: John Daiker Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 5cf4c85..96bc0a0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -285,7 +285,7 @@ exit: } static unsigned int rt2x00debug_poll_queue_dump(struct file *file, - poll_table *wait) + poll_table *wait) { struct rt2x00debug_intf *intf = file->private_data; @@ -377,7 +377,7 @@ static ssize_t rt2x00debug_read_crypto_stats(struct file *file, if (*offset) return 0; - data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL); + data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 070786e..e9f4261 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -570,7 +570,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) queue->length++; } else if (index == Q_INDEX_DONE) { queue->length--; - queue->count ++; + queue->count++; } spin_unlock_irqrestore(&queue->lock, irqflags); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 08eb896..921dcd5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1934,7 +1934,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } static void rt61pci_fill_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) + struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 7f89782..69a4931 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1685,7 +1685,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } static void rt73usb_fill_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) + struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); -- cgit v1.1 From 9b24001db145cf1da76a479918373c18aa10bb4b Mon Sep 17 00:00:00 2001 From: Zhaolei Date: Wed, 22 Oct 2008 17:06:12 +0800 Subject: Fix debugfs_create_bool's error checking method for wireless/iwlwifi/ debugfs_create_bool() returns NULL if an error occurs, returns -ENODEV when debugfs is not enabled in the kernel. Signed-off-by: Zhao Lei Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 753f938..c3df5aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -58,7 +58,8 @@ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ - if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ + || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ } while (0) -- cgit v1.1 From cfa3fa405a5eafd5d5c53b18abc00ca998c35eef Mon Sep 17 00:00:00 2001 From: Zhaolei Date: Wed, 22 Oct 2008 17:07:25 +0800 Subject: Fix debugfs_create_*'s error checking method for wireless/rt2x00/ debugfs_create_*() returns NULL if an error occurs, returns -ENODEV when debugfs is not enabled in the kernel. Signed-off-by: Zhao Lei Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 96bc0a0..a31418a7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -587,29 +587,29 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf->driver_folder = debugfs_create_dir(intf->rt2x00dev->ops->name, rt2x00dev->hw->wiphy->debugfsdir); - if (IS_ERR(intf->driver_folder)) + if (IS_ERR(intf->driver_folder) || !intf->driver_folder) goto exit; intf->driver_entry = rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); - if (IS_ERR(intf->driver_entry)) + if (IS_ERR(intf->driver_entry) || !intf->driver_entry) goto exit; intf->chipset_entry = rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob); - if (IS_ERR(intf->chipset_entry)) + if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry) goto exit; intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR, intf->driver_folder, intf, &rt2x00debug_fop_dev_flags); - if (IS_ERR(intf->dev_flags)) + if (IS_ERR(intf->dev_flags) || !intf->dev_flags) goto exit; intf->register_folder = debugfs_create_dir("register", intf->driver_folder); - if (IS_ERR(intf->register_folder)) + if (IS_ERR(intf->register_folder) || !intf->register_folder) goto exit; #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ @@ -619,7 +619,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ &(__intf)->offset_##__name); \ - if (IS_ERR((__intf)->__name##_off_entry)) \ + if (IS_ERR((__intf)->__name##_off_entry) \ + || !(__intf)->__name##_off_entry) \ goto exit; \ \ (__intf)->__name##_val_entry = \ @@ -627,7 +628,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ (__intf), &rt2x00debug_fop_##__name);\ - if (IS_ERR((__intf)->__name##_val_entry)) \ + if (IS_ERR((__intf)->__name##_val_entry) \ + || !(__intf)->__name##_val_entry) \ goto exit; \ }) @@ -640,13 +642,14 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf->queue_folder = debugfs_create_dir("queue", intf->driver_folder); - if (IS_ERR(intf->queue_folder)) + if (IS_ERR(intf->queue_folder) || !intf->queue_folder) goto exit; intf->queue_frame_dump_entry = debugfs_create_file("dump", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_dump); - if (IS_ERR(intf->queue_frame_dump_entry)) + if (IS_ERR(intf->queue_frame_dump_entry) + || !intf->queue_frame_dump_entry) goto exit; skb_queue_head_init(&intf->frame_dump_skbqueue); -- cgit v1.1 From 7e272fcff6f0a32a3d46e600ea5895f6058f4e2d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 24 Sep 2008 18:13:14 -0400 Subject: wireless: consolidate on a single escape_essid implementation Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/ipw2100.c | 10 +-- drivers/net/wireless/ipw2200.c | 118 ++++++++++++++-------------- drivers/net/wireless/ipw2200.h | 1 + drivers/net/wireless/iwlwifi/Kconfig | 2 + drivers/net/wireless/iwlwifi/iwl-scan.c | 52 ++---------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 48 +---------- drivers/net/wireless/libertas/assoc.c | 14 ++-- drivers/net/wireless/libertas/cmd.c | 3 +- drivers/net/wireless/libertas/debugfs.c | 3 +- drivers/net/wireless/libertas/decl.h | 4 - drivers/net/wireless/libertas/main.c | 27 ------- drivers/net/wireless/libertas/scan.c | 11 ++- drivers/net/wireless/libertas/wext.c | 3 +- 14 files changed, 99 insertions(+), 198 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 45bdf0b..42afaed 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -271,6 +271,7 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 select WIRELESS_EXT + select LIB80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices. diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 079dbd0..223914e 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1975,7 +1975,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) } IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", - priv->net_dev->name, escape_essid(essid, essid_len), + priv->net_dev->name, escape_ssid(essid, essid_len), txratename, chan, bssid); /* now we copy read ssid into dev */ @@ -2003,7 +2003,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, }; int err; - IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); + IPW_DEBUG_HC("SSID: '%s'\n", escape_ssid(essid, ssid_len)); if (ssid_len) memcpy(cmd.host_command_parameters, essid, ssid_len); @@ -2046,7 +2046,7 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "disassociated: '%s' %pM \n", - escape_essid(priv->essid, priv->essid_len), + escape_ssid(priv->essid, priv->essid_len), priv->bssid); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -6987,7 +6987,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, goto done; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length), + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_ssid(essid, length), length); priv->essid_len = length; @@ -7014,7 +7014,7 @@ static int ipw2100_wx_get_essid(struct net_device *dev, * configured ESSID then return that; otherwise return ANY */ if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + escape_ssid(priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 6ec6de2..22278f8 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4409,8 +4409,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "associated: '%s' %pM \n", - escape_essid(priv->essid, - priv->essid_len), + escape_ssid(priv->essid, + priv->essid_len), priv->bssid); switch (priv->ieee->iw_mode) { @@ -4490,10 +4490,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, "deauthenticated: '%s' " "%pM" ": (0x%04X) - %s \n", - escape_essid(priv-> - essid, - priv-> - essid_len), + escape_ssid(priv-> + essid, + priv-> + essid_len), priv->bssid, le16_to_cpu(auth->status), ipw_get_status_code @@ -4512,7 +4512,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "authenticated: '%s' %pM\n", - escape_essid(priv->essid, + escape_ssid(priv->essid, priv->essid_len), priv->bssid); break; @@ -4540,7 +4540,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "disassociated: '%s' %pM \n", - escape_essid(priv->essid, + escape_ssid(priv->essid, priv->essid_len), priv->bssid); @@ -4578,7 +4578,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, "authenticated: '%s' %pM \n", - escape_essid(priv->essid, + escape_ssid(priv->essid, priv->essid_len), priv->bssid); priv->status |= STATUS_AUTH; @@ -4597,8 +4597,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' %pM\n", - escape_essid(priv->essid, - priv->essid_len), + escape_ssid(priv->essid, + priv->essid_len), priv->bssid); priv->status &= ~(STATUS_ASSOCIATING | @@ -5430,7 +5430,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_IBSS))) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5440,7 +5440,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (network->flags & NETWORK_EMPTY_ESSID) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5453,8 +5453,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, network->ssid_len)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_essid(network->ssid, - network->ssid_len), + escape_ssid(network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5468,13 +5468,13 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), sizeof(escaped)); IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", escaped, network->bssid, - escape_essid(priv->essid, - priv->essid_len)); + escape_ssid(priv->essid, + priv->essid_len)); return 0; } } @@ -5485,14 +5485,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (network->time_stamp[0] < match->network->time_stamp[0]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + escape_ssid(match->network->ssid, + match->network->ssid_len)); return 0; } else if (network->time_stamp[1] < match->network->time_stamp[1]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + escape_ssid(match->network->ssid, + match->network->ssid_len)); return 0; } @@ -5501,7 +5501,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); @@ -5512,7 +5512,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, (network->channel != priv->channel)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, network->channel, priv->channel); return 0; @@ -5523,7 +5523,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, priv-> capability & CAP_PRIVACY_ON ? "on" : "off", @@ -5536,8 +5536,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of the same BSSID match: %pM" - ".\n", escape_essid(network->ssid, - network->ssid_len), + ".\n", escape_ssid(network->ssid, + network->ssid_len), network->bssid, priv->bssid); return 0; @@ -5548,7 +5548,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5559,7 +5559,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5567,7 +5567,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (rates.num_rates == 0) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5580,7 +5580,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 1; @@ -5618,8 +5618,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work) mutex_lock(&priv->mutex); if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { IPW_DEBUG_MERGE("remove network %s\n", - escape_essid(priv->essid, - priv->essid_len)); + escape_ssid(priv->essid, + priv->essid_len)); ipw_remove_current_network(priv); } @@ -5644,7 +5644,7 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_IBSS))) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5654,7 +5654,7 @@ static int ipw_best_network(struct ipw_priv *priv, if (network->flags & NETWORK_EMPTY_ESSID) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5667,7 +5667,7 @@ static int ipw_best_network(struct ipw_priv *priv, network->ssid_len)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_essid(network->ssid, + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; @@ -5681,13 +5681,13 @@ static int ipw_best_network(struct ipw_priv *priv, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), sizeof(escaped)); IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", escaped, network->bssid, - escape_essid(priv->essid, - priv->essid_len)); + escape_ssid(priv->essid, + priv->essid_len)); return 0; } } @@ -5697,13 +5697,13 @@ static int ipw_best_network(struct ipw_priv *priv, if (match->network && match->network->stats.rssi > network->stats.rssi) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), sizeof(escaped)); IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " "'%s (%pM)' has a stronger signal.\n", escaped, network->bssid, - escape_essid(match->network->ssid, - match->network->ssid_len), + escape_ssid(match->network->ssid, + match->network->ssid_len), match->network->bssid); return 0; } @@ -5715,7 +5715,7 @@ static int ipw_best_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of storming (%ums since last " "assoc attempt).\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, jiffies_to_msecs(jiffies - network->last_associate)); @@ -5727,7 +5727,7 @@ static int ipw_best_network(struct ipw_priv *priv, time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); @@ -5738,7 +5738,7 @@ static int ipw_best_network(struct ipw_priv *priv, (network->channel != priv->channel)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, network->channel, priv->channel); return 0; @@ -5749,7 +5749,7 @@ static int ipw_best_network(struct ipw_priv *priv, ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, priv->capability & CAP_PRIVACY_ON ? "on" : "off", @@ -5762,7 +5762,7 @@ static int ipw_best_network(struct ipw_priv *priv, memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of BSSID mismatch: %pM.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid, priv->bssid); return 0; } @@ -5772,7 +5772,7 @@ static int ipw_best_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5781,7 +5781,7 @@ static int ipw_best_network(struct ipw_priv *priv, if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5792,7 +5792,7 @@ static int ipw_best_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5800,7 +5800,7 @@ static int ipw_best_network(struct ipw_priv *priv, if (rates.num_rates == 0) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 0; } @@ -5814,7 +5814,7 @@ static int ipw_best_network(struct ipw_priv *priv, match->network = network; IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", - escape_essid(network->ssid, network->ssid_len), + escape_ssid(network->ssid, network->ssid_len), network->bssid); return 1; @@ -6065,7 +6065,7 @@ static void ipw_debug_config(struct ipw_priv *priv) IPW_DEBUG_INFO("Channel unlocked.\n"); if (priv->config & CFG_STATIC_ESSID) IPW_DEBUG_INFO("ESSID locked to '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + escape_ssid(priv->essid, priv->essid_len)); else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) @@ -7352,7 +7352,7 @@ static int ipw_associate_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", roaming ? "Rea" : "A", - escape_essid(priv->essid, priv->essid_len), + escape_ssid(priv->essid, priv->essid_len), network->channel, ipw_modes[priv->assoc_request.ieee_mode], rates->num_rates, @@ -7452,7 +7452,7 @@ static int ipw_associate_network(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", - escape_essid(priv->essid, priv->essid_len), + escape_ssid(priv->essid, priv->essid_len), priv->bssid); return 0; @@ -7604,8 +7604,8 @@ static int ipw_associate(void *data) target = oldest; IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " "network list.\n", - escape_essid(target->ssid, - target->ssid_len), + escape_ssid(target->ssid, + target->ssid_len), target->bssid); list_add_tail(&target->list, &priv->ieee->network_free_list); @@ -9057,7 +9057,7 @@ static int ipw_wx_set_essid(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length), + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_ssid(extra, length), length); priv->essid_len = length; @@ -9084,7 +9084,7 @@ static int ipw_wx_get_essid(struct net_device *dev, if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + escape_ssid(priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 0bad1ec..0a84d52 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -48,6 +48,7 @@ #include #include +#include #include #include diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b0ac0ce..47bee0e 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -4,6 +4,7 @@ config IWLWIFI config IWLCORE tristate "Intel Wireless Wifi Core" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select LIB80211 select IWLWIFI select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS @@ -105,6 +106,7 @@ config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select LIB80211 select IWLWIFI select MAC80211_LEDS if IWL3945_LEDS select LEDS_CLASS if IWL3945_LEDS diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 86b7457..1cc8aa5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -25,8 +25,10 @@ * Tomas Winkler * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ -#include +#include #include +#include +#include #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -64,48 +66,6 @@ #define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) -static int iwl_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - - - -static const char *iwl_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - /** * iwl_scan_cancel - Cancel any currently executing HW scan * @@ -775,8 +735,8 @@ static void iwl_bg_request_scan(struct work_struct *data) /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { IWL_DEBUG_SCAN("Start direct scan for '%s'\n", - iwl_escape_essid(priv->direct_ssid, - priv->direct_ssid_len)); + escape_ssid(priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, @@ -784,7 +744,7 @@ static void iwl_bg_request_scan(struct work_struct *data) n_probes++; } else if (!iwl_is_associated(priv) && priv->essid_len) { IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", - iwl_escape_essid(priv->essid, priv->essid_len)); + escape_ssid(priv->essid, priv->essid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2cd33b4..370cc46 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -107,46 +108,6 @@ static const struct ieee80211_supported_band *iwl3945_get_band( return priv->hw->wiphy->bands[band]; } -static int iwl3945_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl3945_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -6193,8 +6154,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->one_direct_scan) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s'\n", - iwl3945_escape_essid(priv->direct_ssid, - priv->direct_ssid_len)); + escape_ssid(priv->direct_ssid, priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, @@ -6203,7 +6163,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) } else if (!iwl3945_is_associated(priv) && priv->essid_len) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s' when not associated\n", - iwl3945_escape_essid(priv->essid, priv->essid_len)); + escape_ssid(priv->essid, priv->essid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); @@ -7018,7 +6978,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } if (len) { IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl3945_escape_essid(ssid, len), (int)len); + escape_ssid(ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 8b88e95..3492e89 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1,6 +1,8 @@ /* Copyright (C) 2006, Red Hat, Inc. */ +#include #include +#include #include "assoc.h" #include "decl.h" @@ -157,11 +159,11 @@ static int lbs_adhoc_join(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_join("current SSID '%s', ssid length %u\n", - escape_essid(priv->curbssparams.ssid, + escape_ssid(priv->curbssparams.ssid, priv->curbssparams.ssid_len), priv->curbssparams.ssid_len); lbs_deb_join("requested ssid '%s', ssid length %u\n", - escape_essid(bss->ssid, bss->ssid_len), + escape_ssid(bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ @@ -325,7 +327,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, 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), + escape_ssid(assoc_req->ssid, assoc_req->ssid_len), assoc_req->ssid_len); cmd.bsstype = CMD_BSS_TYPE_IBSS; @@ -704,7 +706,7 @@ static int assoc_helper_essid(struct lbs_private *priv, channel = assoc_req->channel; lbs_deb_assoc("SSID '%s' requested\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len)); + escape_ssid(assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { lbs_send_specific_ssid_scan(priv, assoc_req->ssid, assoc_req->ssid_len); @@ -1228,7 +1230,7 @@ void lbs_association_worker(struct work_struct *work) " secinfo: %s%s%s\n" " auth_mode: %d\n", assoc_req->flags, - escape_essid(assoc_req->ssid, assoc_req->ssid_len), + escape_ssid(assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, assoc_req->bssid, assoc_req->secinfo.WPAenabled ? " WPA" : "", @@ -1814,7 +1816,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", - escape_essid(bss->ssid, bss->ssid_len), + escape_ssid(bss->ssid, bss->ssid_len), priv->curbssparams.bssid, priv->curbssparams.channel); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index d45b07c..52feab6 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include "host.h" @@ -1092,7 +1093,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) } lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", action, priv->mesh_tlv, chan, - escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); + escape_ssid(priv->mesh_ssid, priv->mesh_ssid_len)); return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 5f6bee4..8493320 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "dev.h" #include "decl.h" @@ -85,7 +86,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, spectrum_mgmt ? 'S' : ' '); pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", - escape_essid(iter_bss->ssid, iter_bss->ssid_len)); + escape_ssid(iter_bss->ssid, iter_bss->ssid_len)); numscansdone++; } diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 1a8888c..0b84bdc 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -74,8 +74,4 @@ void lbs_host_to_card_done(struct lbs_private *priv); int lbs_update_channel(struct lbs_private *priv); -#ifndef CONFIG_IEEE80211 -const char *escape_essid(const char *essid, u8 essid_len); -#endif - #endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 34a47f6..e9d23f6 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1646,33 +1646,6 @@ out: return ret; } -#ifndef CONFIG_IEEE80211 -const char *escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (ieee80211_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else { - *d++ = *s++; - } - } - *d = '\0'; - return escaped; -} -#endif - module_init(lbs_init_module); module_exit(lbs_exit_module); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 351b3f6..7881890 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -4,9 +4,12 @@ * IOCTL handlers as well as command preperation and response routines * for sending scan commands to the firmware. */ +#include #include #include +#include + #include "host.h" #include "decl.h" #include "dev.h" @@ -452,7 +455,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) list_for_each_entry(iter, &priv->network_list, list) lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", i++, iter->bssid, iter->rssi, - escape_essid(iter->ssid, iter->ssid_len)); + escape_ssid(iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif @@ -599,7 +602,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, bss->ssid_len = min_t(int, 32, elem->len); memcpy(bss->ssid, elem->data, bss->ssid_len); lbs_deb_scan("got SSID IE: '%s', len %u\n", - escape_essid(bss->ssid, bss->ssid_len), + escape_ssid(bss->ssid, bss->ssid_len), bss->ssid_len); break; @@ -742,7 +745,7 @@ int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", - escape_essid(ssid, ssid_len)); + escape_ssid(ssid, ssid_len)); if (!ssid_len) goto out; @@ -966,7 +969,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, priv->scan_ssid_len = req->essid_len; memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); lbs_deb_wext("set_scan, essid '%s'\n", - escape_essid(priv->scan_ssid, priv->scan_ssid_len)); + escape_ssid(priv->scan_ssid, priv->scan_ssid_len)); } else { priv->scan_ssid_len = 0; } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 04f0bf2..2475799 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -2005,7 +2006,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("requested any SSID\n"); } else { lbs_deb_wext("requested SSID '%s'\n", - escape_essid(ssid, ssid_len)); + escape_ssid(ssid, ssid_len)); } out: -- cgit v1.1 From c5d3dce875ef055ed9b14f169cc967cc2c8faf1f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 30 Sep 2008 17:17:26 -0400 Subject: wireless: remove NETWORK_EMPTY_ESSID flag It is unnecessary and of questionable value. Also remove is_empty_ssid, as it is also unnecessary. Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 22278f8..6e0c55c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5435,16 +5435,6 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, return 0; } - /* If we do not have an ESSID for this AP, we can not associate with - * it */ - if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of hidden ESSID.\n", - escape_ssid(network->ssid, network->ssid_len), - network->bssid); - return 0; - } - if (unlikely(roaming)) { /* If we are roaming, then ensure check if this is a valid * network to try and roam to */ @@ -5649,16 +5639,6 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } - /* If we do not have an ESSID for this AP, we can not associate with - * it */ - if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of hidden ESSID.\n", - escape_ssid(network->ssid, network->ssid_len), - network->bssid); - return 0; - } - if (unlikely(roaming)) { /* If we are roaming, then ensure check if this is a valid * network to try and roam to */ @@ -6881,8 +6861,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, if ((priv->status & STATUS_ASSOCIATED) && (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) - if ((network->capability & WLAN_CAPABILITY_IBSS) && - !(network->flags & NETWORK_EMPTY_ESSID)) + if (network->capability & WLAN_CAPABILITY_IBSS) if ((network->ssid_len == priv->assoc_network->ssid_len) && !memcmp(network->ssid, -- cgit v1.1 From 9387b7caf3049168fc97a8a9111af8fe2143af18 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 30 Sep 2008 20:59:05 -0400 Subject: wireless: use individual buffers for printing ssid values Also change escape_ssid to print_ssid to match print_mac semantics. Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 20 ++-- drivers/net/wireless/ipw2200.c | 153 +++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-scan.c | 7 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +- drivers/net/wireless/libertas/assoc.c | 17 ++-- drivers/net/wireless/libertas/cmd.c | 3 +- drivers/net/wireless/libertas/debugfs.c | 4 +- drivers/net/wireless/libertas/scan.c | 12 ++- drivers/net/wireless/libertas/wext.c | 3 +- 9 files changed, 141 insertions(+), 87 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 223914e..062c9f2 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -163,6 +163,8 @@ that only one external action is invoked at a time. #include #include +#include + #include "ipw2100.h" #define IPW2100_VERSION "git-1.2.2" @@ -1914,6 +1916,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; + DECLARE_SSID_BUF(ssid); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1975,7 +1978,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) } IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", - priv->net_dev->name, escape_ssid(essid, essid_len), + priv->net_dev->name, print_ssid(ssid, essid, essid_len), txratename, chan, bssid); /* now we copy read ssid into dev */ @@ -2002,8 +2005,9 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, .host_command_length = ssid_len }; int err; + DECLARE_SSID_BUF(ssid); - IPW_DEBUG_HC("SSID: '%s'\n", escape_ssid(essid, ssid_len)); + IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len)); if (ssid_len) memcpy(cmd.host_command_parameters, essid, ssid_len); @@ -2044,9 +2048,11 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { + DECLARE_SSID_BUF(ssid); + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "disassociated: '%s' %pM \n", - escape_ssid(priv->essid, priv->essid_len), + print_ssid(ssid, priv->essid, priv->essid_len), priv->bssid); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -6958,6 +6964,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, char *essid = ""; /* ANY */ int length = 0; int err = 0; + DECLARE_SSID_BUF(ssid); mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { @@ -6987,8 +6994,8 @@ static int ipw2100_wx_set_essid(struct net_device *dev, goto done; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_ssid(essid, length), - length); + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, essid, length), length); priv->essid_len = length; memcpy(priv->essid, essid, priv->essid_len); @@ -7009,12 +7016,13 @@ static int ipw2100_wx_get_essid(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_ssid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 6e0c55c..2b9d96a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4395,6 +4395,7 @@ static void handle_scan_event(struct ipw_priv *priv) static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { + DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); notif->size = le16_to_cpu(notif->size); @@ -4409,8 +4410,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "associated: '%s' %pM \n", - escape_ssid(priv->essid, - priv->essid_len), + print_ssid(ssid, priv->essid, + priv->essid_len), priv->bssid); switch (priv->ieee->iw_mode) { @@ -4490,10 +4491,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, "deauthenticated: '%s' " "%pM" ": (0x%04X) - %s \n", - escape_ssid(priv-> - essid, - priv-> - essid_len), + print_ssid(ssid, + priv-> + essid, + priv-> + essid_len), priv->bssid, le16_to_cpu(auth->status), ipw_get_status_code @@ -4512,8 +4514,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "authenticated: '%s' %pM\n", - escape_ssid(priv->essid, - priv->essid_len), + print_ssid(ssid, priv->essid, + priv->essid_len), priv->bssid); break; } @@ -4540,8 +4542,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "disassociated: '%s' %pM \n", - escape_ssid(priv->essid, - priv->essid_len), + print_ssid(ssid, priv->essid, + priv->essid_len), priv->bssid); priv->status &= @@ -4578,8 +4580,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, "authenticated: '%s' %pM \n", - escape_ssid(priv->essid, - priv->essid_len), + print_ssid(ssid, priv->essid, + priv->essid_len), priv->bssid); priv->status |= STATUS_AUTH; break; @@ -4597,8 +4599,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' %pM\n", - escape_ssid(priv->essid, - priv->essid_len), + print_ssid(ssid, priv->essid, + priv->essid_len), priv->bssid); priv->status &= ~(STATUS_ASSOCIATING | @@ -5423,6 +5425,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, int roaming) { struct ipw_supported_rates rates; + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5430,7 +5433,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_IBSS))) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5443,8 +5447,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, network->ssid_len)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_ssid(network->ssid, - network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5458,13 +5462,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), sizeof(escaped)); IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", escaped, network->bssid, - escape_ssid(priv->essid, - priv->essid_len)); + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5475,14 +5480,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (network->time_stamp[0] < match->network->time_stamp[0]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_ssid(match->network->ssid, - match->network->ssid_len)); + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); return 0; } else if (network->time_stamp[1] < match->network->time_stamp[1]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_ssid(match->network->ssid, - match->network->ssid_len)); + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); return 0; } @@ -5491,7 +5496,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); @@ -5502,7 +5508,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, (network->channel != priv->channel)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, network->channel, priv->channel); return 0; @@ -5513,7 +5520,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, priv-> capability & CAP_PRIVACY_ON ? "on" : "off", @@ -5526,8 +5534,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of the same BSSID match: %pM" - ".\n", escape_ssid(network->ssid, - network->ssid_len), + ".\n", print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, priv->bssid); return 0; @@ -5538,7 +5546,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5549,7 +5558,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5557,7 +5567,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (rates.num_rates == 0) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5570,7 +5581,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, network->ssid_len), network->bssid); return 1; @@ -5578,6 +5589,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, static void ipw_merge_adhoc_network(struct work_struct *work) { + DECLARE_SSID_BUF(ssid); struct ipw_priv *priv = container_of(work, struct ipw_priv, merge_networks); struct ieee80211_network *network = NULL; @@ -5608,8 +5620,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work) mutex_lock(&priv->mutex); if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { IPW_DEBUG_MERGE("remove network %s\n", - escape_ssid(priv->essid, - priv->essid_len)); + print_ssid(ssid, priv->essid, + priv->essid_len)); ipw_remove_current_network(priv); } @@ -5625,6 +5637,7 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5634,7 +5647,8 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_IBSS))) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5647,8 +5661,8 @@ static int ipw_best_network(struct ipw_priv *priv, network->ssid_len)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_ssid(network->ssid, - network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5661,13 +5675,14 @@ static int ipw_best_network(struct ipw_priv *priv, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), sizeof(escaped)); IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", escaped, network->bssid, - escape_ssid(priv->essid, - priv->essid_len)); + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5677,13 +5692,13 @@ static int ipw_best_network(struct ipw_priv *priv, if (match->network && match->network->stats.rssi > network->stats.rssi) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, network->ssid_len), sizeof(escaped)); IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " "'%s (%pM)' has a stronger signal.\n", escaped, network->bssid, - escape_ssid(match->network->ssid, - match->network->ssid_len), + print_ssid(ssid, match->network->ssid, + match->network->ssid_len), match->network->bssid); return 0; } @@ -5695,7 +5710,8 @@ static int ipw_best_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of storming (%ums since last " "assoc attempt).\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, jiffies_to_msecs(jiffies - network->last_associate)); @@ -5707,7 +5723,8 @@ static int ipw_best_network(struct ipw_priv *priv, time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); @@ -5718,7 +5735,8 @@ static int ipw_best_network(struct ipw_priv *priv, (network->channel != priv->channel)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, network->channel, priv->channel); return 0; @@ -5729,7 +5747,8 @@ static int ipw_best_network(struct ipw_priv *priv, ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, priv->capability & CAP_PRIVACY_ON ? "on" : "off", @@ -5742,7 +5761,8 @@ static int ipw_best_network(struct ipw_priv *priv, memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of BSSID mismatch: %pM.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid, priv->bssid); return 0; } @@ -5752,7 +5772,8 @@ static int ipw_best_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5761,7 +5782,8 @@ static int ipw_best_network(struct ipw_priv *priv, if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5772,7 +5794,8 @@ static int ipw_best_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5780,7 +5803,8 @@ static int ipw_best_network(struct ipw_priv *priv, if (rates.num_rates == 0) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), network->bssid); return 0; } @@ -5794,7 +5818,7 @@ static int ipw_best_network(struct ipw_priv *priv, match->network = network; IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", - escape_ssid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, network->ssid_len), network->bssid); return 1; @@ -6037,6 +6061,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { + DECLARE_SSID_BUF(ssid); IPW_DEBUG_INFO("Scan completed, no valid APs matched " "[CFG 0x%08X]\n", priv->config); if (priv->config & CFG_STATIC_CHANNEL) @@ -6045,7 +6070,7 @@ static void ipw_debug_config(struct ipw_priv *priv) IPW_DEBUG_INFO("Channel unlocked.\n"); if (priv->config & CFG_STATIC_ESSID) IPW_DEBUG_INFO("ESSID locked to '%s'\n", - escape_ssid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) @@ -7263,6 +7288,7 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; + DECLARE_SSID_BUF(ssid); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7331,7 +7357,7 @@ static int ipw_associate_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", roaming ? "Rea" : "A", - escape_ssid(priv->essid, priv->essid_len), + print_ssid(ssid, priv->essid, priv->essid_len), network->channel, ipw_modes[priv->assoc_request.ieee_mode], rates->num_rates, @@ -7431,7 +7457,7 @@ static int ipw_associate_network(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", - escape_ssid(priv->essid, priv->essid_len), + print_ssid(ssid, priv->essid, priv->essid_len), priv->bssid); return 0; @@ -7522,6 +7548,7 @@ static int ipw_associate(void *data) struct ipw_supported_rates *rates; struct list_head *element; unsigned long flags; + DECLARE_SSID_BUF(ssid); if (priv->ieee->iw_mode == IW_MODE_MONITOR) { IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n"); @@ -7583,8 +7610,8 @@ static int ipw_associate(void *data) target = oldest; IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " "network list.\n", - escape_ssid(target->ssid, - target->ssid_len), + print_ssid(ssid, target->ssid, + target->ssid_len), target->bssid); list_add_tail(&target->list, &priv->ieee->network_free_list); @@ -9012,6 +9039,7 @@ static int ipw_wx_set_essid(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int length; + DECLARE_SSID_BUF(ssid); mutex_lock(&priv->mutex); @@ -9036,8 +9064,8 @@ static int ipw_wx_set_essid(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_ssid(extra, length), - length); + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, extra, length), length); priv->essid_len = length; memcpy(priv->essid, extra, priv->essid_len); @@ -9056,6 +9084,7 @@ static int ipw_wx_get_essid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ @@ -9063,7 +9092,7 @@ static int ipw_wx_get_essid(struct net_device *dev, if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_ssid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 1cc8aa5..3379b41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -643,6 +643,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u8 n_probes = 2; u8 rx_chain = priv->hw_params.valid_rx_ant; u8 rate; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -735,8 +736,8 @@ static void iwl_bg_request_scan(struct work_struct *data) /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { IWL_DEBUG_SCAN("Start direct scan for '%s'\n", - escape_ssid(priv->direct_ssid, - priv->direct_ssid_len)); + print_ssid(ssid, priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, @@ -744,7 +745,7 @@ static void iwl_bg_request_scan(struct work_struct *data) n_probes++; } else if (!iwl_is_associated(priv) && priv->essid_len) { IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", - escape_ssid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 370cc46..8009094 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6054,6 +6054,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct ieee80211_conf *conf = NULL; u8 n_probes = 2; enum ieee80211_band band; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -6154,7 +6155,8 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->one_direct_scan) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s'\n", - escape_ssid(priv->direct_ssid, priv->direct_ssid_len)); + print_ssid(ssid, priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, @@ -6163,7 +6165,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) } else if (!iwl3945_is_associated(priv) && priv->essid_len) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s' when not associated\n", - escape_ssid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); @@ -6945,6 +6947,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) int rc = 0; unsigned long flags; struct iwl3945_priv *priv = hw->priv; + DECLARE_SSID_BUF(ssid_buf); IWL_DEBUG_MAC80211("enter\n"); @@ -6978,7 +6981,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } if (len) { IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - escape_ssid(ssid, len), (int)len); + print_ssid(ssid_buf, ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 3492e89..9286378 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -153,17 +153,18 @@ static int lbs_adhoc_join(struct lbs_private *priv, struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; u8 preamble = RADIO_PREAMBLE_LONG; + DECLARE_SSID_BUF(ssid); u16 ratesize = 0; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_join("current SSID '%s', ssid length %u\n", - escape_ssid(priv->curbssparams.ssid, + print_ssid(ssid, priv->curbssparams.ssid, priv->curbssparams.ssid_len), priv->curbssparams.ssid_len); lbs_deb_join("requested ssid '%s', ssid length %u\n", - escape_ssid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ @@ -308,6 +309,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, size_t ratesize = 0; u16 tmpcap = 0; int ret = 0; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -327,7 +329,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", - escape_ssid(assoc_req->ssid, assoc_req->ssid_len), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->ssid_len); cmd.bsstype = CMD_BSS_TYPE_IBSS; @@ -695,6 +697,7 @@ static int assoc_helper_essid(struct lbs_private *priv, int ret = 0; struct bss_descriptor * bss; int channel = -1; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -706,7 +709,7 @@ static int assoc_helper_essid(struct lbs_private *priv, channel = assoc_req->channel; lbs_deb_assoc("SSID '%s' requested\n", - escape_ssid(assoc_req->ssid, assoc_req->ssid_len)); + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { lbs_send_specific_ssid_scan(priv, assoc_req->ssid, assoc_req->ssid_len); @@ -1207,6 +1210,7 @@ void lbs_association_worker(struct work_struct *work) struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -1230,7 +1234,7 @@ void lbs_association_worker(struct work_struct *work) " secinfo: %s%s%s\n" " auth_mode: %d\n", assoc_req->flags, - escape_ssid(assoc_req->ssid, assoc_req->ssid_len), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, assoc_req->bssid, assoc_req->secinfo.WPAenabled ? " WPA" : "", @@ -1767,6 +1771,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_JOIN); @@ -1816,7 +1821,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", - escape_ssid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), priv->curbssparams.bssid, priv->curbssparams.channel); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 52feab6..38843c8 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1063,6 +1063,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) { struct cmd_ds_mesh_config cmd; struct mrvl_meshie *ie; + DECLARE_SSID_BUF(ssid); memset(&cmd, 0, sizeof(cmd)); cmd.channel = cpu_to_le16(chan); @@ -1093,7 +1094,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) } lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", action, priv->mesh_tlv, chan, - escape_ssid(priv->mesh_ssid, priv->mesh_ssid_len)); + print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len)); return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 8493320..ec4efd7 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -66,6 +66,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -86,7 +87,8 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, spectrum_mgmt ? 'S' : ' '); pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", - escape_ssid(iter_bss->ssid, iter_bss->ssid_len)); + print_ssid(ssid, iter_bss->ssid, + iter_bss->ssid_len)); numscansdone++; } diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 7881890..5c34ac5 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -362,6 +362,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor *iter; int i = 0; + DECLARE_SSID_BUF(ssid); #endif lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); @@ -455,7 +456,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) list_for_each_entry(iter, &priv->network_list, list) lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", i++, iter->bssid, iter->rssi, - escape_ssid(iter->ssid, iter->ssid_len)); + print_ssid(ssid, iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif @@ -514,6 +515,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; + DECLARE_SSID_BUF(ssid); struct ieeetypes_countryinfoset *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; @@ -602,7 +604,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, bss->ssid_len = min_t(int, 32, elem->len); memcpy(bss->ssid, elem->data, bss->ssid_len); lbs_deb_scan("got SSID IE: '%s', len %u\n", - escape_ssid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); break; @@ -742,10 +744,11 @@ done: int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, uint8_t ssid_len) { + DECLARE_SSID_BUF(ssid_buf); int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", - escape_ssid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); if (!ssid_len) goto out; @@ -940,6 +943,7 @@ out: int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { + DECLARE_SSID_BUF(ssid); struct lbs_private *priv = dev->priv; int ret = 0; @@ -969,7 +973,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, priv->scan_ssid_len = req->essid_len; memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); lbs_deb_wext("set_scan, essid '%s'\n", - escape_ssid(priv->scan_ssid, priv->scan_ssid_len)); + print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len)); } else { priv->scan_ssid_len = 0; } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 2475799..d4c6a65 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1978,6 +1978,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, u8 ssid_len = 0; struct assoc_request * assoc_req; int in_ssid_len = dwrq->length; + DECLARE_SSID_BUF(ssid_buf); lbs_deb_enter(LBS_DEB_WEXT); @@ -2006,7 +2007,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("requested any SSID\n"); } else { lbs_deb_wext("requested SSID '%s'\n", - escape_ssid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); } out: -- cgit v1.1 From 72118015271e6d3852cb9f647efe0987d131adaa Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 30 Sep 2008 21:43:03 -0400 Subject: wireless: avoid some net/ieee80211.h vs. linux/ieee80211.h conflicts There is quite a lot of overlap in definitions between these headers... Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_common.h | 13 ------------- drivers/net/wireless/ipw2200.c | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index b470c74..90b64b09 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -6,19 +6,6 @@ /* IEEE 802.11 defines */ -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_CHALLENGE 16 -#define WLAN_EID_RSN 48 -#define WLAN_EID_GENERIC 221 - - /* HFA384X Configuration RIDs */ #define HFA384X_RID_CNFPORTTYPE 0xFC00 #define HFA384X_RID_CNFOWNMACADDR 0xFC01 diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 2b9d96a..051ae92 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4446,7 +4446,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_QOS #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ - le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl)) + le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control)) if ((priv->status & STATUS_AUTH) && (IPW_GET_PACKET_STYPE(¬if->u.raw) == IEEE80211_STYPE_ASSOC_RESP)) { @@ -7665,12 +7665,12 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, u16 fc; hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_ctl); + fc = le16_to_cpu(hdr->frame_control); if (!(fc & IEEE80211_FCTL_PROTECTED)) return; fc &= ~IEEE80211_FCTL_PROTECTED; - hdr->frame_ctl = cpu_to_le16(fc); + hdr->frame_control = cpu_to_le16(fc); switch (priv->ieee->sec.level) { case SEC_LEVEL_3: /* Remove CCMP HDR */ @@ -7982,17 +7982,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, } hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -8010,7 +8010,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, ipw_rt = (void *)skb->data; if (hdr_only) - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); memcpy(ipw_rt->payload, hdr, len); @@ -8230,7 +8230,7 @@ static int is_duplicate_packet(struct ipw_priv *priv, /* Comment this line now since we observed the card receives * duplicate packets but the FCTL_RETRY bit is not set in the * IBSS mode with fragmentation enabled. - BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */ + BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */ return 1; } @@ -10381,17 +10381,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, /* Filtering of fragment chains is done agains the first fragment */ hdr = (void *)txb->fragments[0]->data; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -10406,7 +10406,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (hdr_only) { hdr = (void *)src->data; - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); } else len = src->len; -- cgit v1.1 From b139a10a0aaf3c8041af348c2268d59e1610dc83 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 22 Oct 2008 13:28:43 -0700 Subject: ath9k: remove pointless sc_txintrperiod and spin_lock_bh on tx prepare sc_txintrperiod is currently set to 0 and never updated. We won't be using this, if anything we will consider using TX interrupt mitigation but that is different and not yet tested. So remove sc_txintrperiod and the pointless spin_lock_bh() on tx prepare. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 13 +++++++++++++ drivers/net/wireless/ath9k/core.h | 4 ---- drivers/net/wireless/ath9k/xmit.c | 27 ++------------------------- 3 files changed, 15 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index accace5..a6063de 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -138,6 +138,19 @@ struct ath_desc { #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 #define ATH9K_TXDESC_CTSENA 0x0008 +/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for + * the descriptor its marked on. We take a tx interrupt to reap + * descriptors when the h/w hits an EOL condition or + * when the descriptor is specifically marked to generate + * an interrupt with this flag. Descriptors should be + * marked periodically to insure timely replenishing of the + * supply needed for sending frames. Defering interrupts + * reduces system load and potentially allows more concurrent + * work to be done but if done to aggressively can cause + * senders to backup. When the hardware queue is left too + * large rate control information may also be too out of + * date. An Alternative for this is TX interrupt mitigation + * but this needs more testing. */ #define ATH9K_TXDESC_INTREQ 0x0010 #define ATH9K_TXDESC_VEOL 0x0020 #define ATH9K_TXDESC_EXT_ONLY 0x0040 diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 59d835b..fbff9aa 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -443,9 +443,6 @@ struct ath_txq { u8 axq_aggr_depth; /* aggregates queued */ u32 axq_totalqueued; /* total ever queued */ - /* count to determine if descriptor should generate int on this txq. */ - u32 axq_intrcnt; - bool stopped; /* Is mac80211 queue stopped ? */ struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/ @@ -1007,7 +1004,6 @@ struct ath_softc { struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES]; struct ath_descdma sc_txdma; 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 */ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 9fa3954..8073c71 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -286,7 +286,8 @@ 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 */ + | ATH9K_TXDESC_INTREQ; /* Generate an interrupt */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) txctl->flags |= ATH9K_TXDESC_NOACK; @@ -363,28 +364,6 @@ static int ath_tx_prepare(struct ath_softc *sc, rcs[0].tries = ATH_TXMAXTRY; } - /* - * Determine if a tx interrupt should be generated for - * this descriptor. We take a tx interrupt to reap - * descriptors when the h/w hits an EOL condition or - * when the descriptor is specifically marked to generate - * an interrupt. We periodically mark descriptors in this - * way to insure timely replenishing of the supply needed - * for sending frames. Defering interrupts reduces system - * load and potentially allows more concurrent work to be - * done but if done to aggressively can cause senders to - * backup. - * - * NB: use >= to deal with sc_txintrperiod changing - * dynamically through sysctl. - */ - spin_lock_bh(&txq->axq_lock); - if ((++txq->axq_intrcnt >= sc->sc_txintrperiod)) { - txctl->flags |= ATH9K_TXDESC_INTREQ; - txq->axq_intrcnt = 0; - } - spin_unlock_bh(&txq->axq_lock); - if (is_multicast_ether_addr(hdr->addr1)) { antenna = sc->sc_mcastantenna + 1; sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; @@ -1166,7 +1145,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) nacked = 0; for (;;) { spin_lock_bh(&txq->axq_lock); - txq->axq_intrcnt = 0; /* reset periodic desc intr count */ if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; txq->axq_linkbuf = NULL; @@ -2164,7 +2142,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_depth = 0; txq->axq_aggr_depth = 0; txq->axq_totalqueued = 0; - txq->axq_intrcnt = 0; txq->axq_linkbuf = NULL; sc->sc_txqsetup |= 1< Date: Wed, 22 Oct 2008 13:28:44 -0700 Subject: ath9k: enable RX interrupt mitigation This enables hardware interrupt mitigation on RX. It should alleviate system interrupt load intelligently. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index d5b513e..84263c8 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -345,7 +345,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) ah->ah_config.spurchans[i][1] = AR_NO_SPUR; } - ah->ah_config.intr_mitigation = 0; + ah->ah_config.intr_mitigation = 1; } static void ath9k_hw_override_ini(struct ath_hal *ah, -- cgit v1.1 From 5c020dc6a0f75de3cd75d9cca3b589abc1826fc5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 22 Oct 2008 13:28:45 -0700 Subject: ath9k: Allow user to change tx power when asked We were also changing tx power even when we were not asked to, this enforces the change only when we are asked nicely. When not asked we simply try to use the max power, we don't tx power at all for rate control. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 3 ++- drivers/net/wireless/ath9k/xmit.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index a7656a3..795fed5 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1250,7 +1250,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan); - sc->sc_config.txpowlimit = 2 * conf->power_level; + if (changed & IEEE80211_CONF_CHANGE_POWER) + sc->sc_config.txpowlimit = 2 * conf->power_level; /* set h/w channel */ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 8073c71..2f27a04 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -230,7 +230,13 @@ static int ath_tx_prepare(struct ath_softc *sc, txctl->if_id = 0; txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); - txctl->txpower = MAX_RATE_POWER; /* FIXME */ + + /* Always try at highest power possible unless the the device + * was configured by the user to use another power. */ + if (likely(sc->sc_config.txpowlimit == ATH_TXPOWER_MAX)) + txctl->txpower = ATH_TXPOWER_MAX; + else + txctl->txpower = sc->sc_config.txpowlimit; /* Fill Key related fields */ -- cgit v1.1 From a4510bf8d96698496d7d2bb242917b4bbfa9bf28 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Oct 2008 12:15:19 +0530 Subject: ath9k: Check if the STA supports HT when initializing rate control Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 9ce5359..ecffd6f 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -2026,7 +2026,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); ath_setup_rates(sc, sband, sta, ath_rc_priv); - if (sc->hw->conf.ht.enabled) { + if (sta->ht_cap.ht_supported) { for (i = 0; i < 77; i++) { if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; -- cgit v1.1 From 8b30b1fe368ab03049435884c11c5c50e4c4ef0b Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 24 Oct 2008 09:55:27 +0530 Subject: mac80211: Re-enable aggregation Wireless HW without any dedicated queues for aggregation do not need the ampdu_queues mechanism present right now in mac80211. Since mac80211 is still incomplete wrt TX MQ changes, do not allow aggregation sessions for drivers that set ampdu_queues. This is only an interim hack until Intel fixes the requeue issue. Signed-off-by: Sujith Signed-off-by: Luis Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 795fed5..f6dc4c8 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -953,10 +953,7 @@ static int ath_attach(u16 devid, &sc->sbands[IEEE80211_BAND_5GHZ]; } - /* FIXME: Have to figure out proper hw init values later */ - hw->queues = 4; - hw->ampdu_queues = 1; /* Register rate control */ hw->rate_control_algorithm = "ath9k_rate_control"; @@ -1745,7 +1742,8 @@ 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; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 20c7ff3..ba05f5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -871,7 +871,8 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | -- cgit v1.1 From 3fd07a1e5aba89d4be3696c46cb7297f1873195a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Oct 2008 23:48:49 -0700 Subject: iwlwifi: refactor TX response flow This patch utilize 5000 new TX response command which contains all necessary information and avoids back referencing to the original TX frame. It also change handling of software queue tracking 4965 flow is aligned with changes as much as possible. Signed-off-by: Tomas Winkler Reviewed-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 63 ++++++++++------------ drivers/net/wireless/iwlwifi/iwl-5000.c | 81 ++++++++++++----------------- drivers/net/wireless/iwlwifi/iwl-commands.h | 50 +++++++++++++----- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 + drivers/net/wireless/iwlwifi/iwl-dev.h | 9 ++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 39 +++++++------- 6 files changed, 125 insertions(+), 119 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 222c2baa9..881bf04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -822,7 +822,6 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE; priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; @@ -2059,7 +2058,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->rate_n_flags = rate_n_flags; agg->bitmap = 0; - /* # frames attempted by Tx command */ + /* num frames attempted by Tx command */ if (agg->frame_count == 1) { /* Only one frame was attempted; no block-ack will arrive */ status = le16_to_cpu(frame_status[0].status); @@ -2158,12 +2157,13 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info; struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->u.status); - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - __le16 fc; - struct ieee80211_hdr *hdr; + int tid = MAX_TID_COUNT; + int sta_id; + int freed; u8 *qc = NULL; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { @@ -2178,8 +2178,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, memset(&info->status, 0, sizeof(info->status)); hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - fc = hdr->frame_control; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } @@ -2194,8 +2193,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; - if (!qc) - return; + WARN_ON(!qc); agg = &priv->stations[sta_id].tid[tid].agg; @@ -2206,54 +2204,49 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE + - priv->hw->queues; + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark) && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) ieee80211_wake_queue(priv->hw, txq_id); else - ieee80211_wake_queue(priv->hw, ampdu_q); + ieee80211_wake_queue(priv->hw, + txq->swq_id); } - iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags |= - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", txq_id, - iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); - - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) " + "rate_n_flags 0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); - if (index != -1) { - int freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (qc) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) + + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark)) ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); - } } + if (qc) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ad566ef..a8c8c85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -683,7 +683,7 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, int tx_fifo_id, int scd_retry) { int txq_id = txq->q.id; - int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | @@ -801,7 +801,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE; priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; @@ -1159,7 +1158,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; info->flags |= iwl_is_tx_success(status)? - IEEE80211_TX_STAT_ACK : 0; + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -1245,9 +1244,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, struct ieee80211_tx_info *info; struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le16_to_cpu(tx_resp->status.status); - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - struct ieee80211_hdr *hdr; - u8 *qc = NULL; + int tid; + int sta_id; + int freed; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -1260,25 +1259,13 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); memset(&info->status, 0, sizeof(info->status)); - hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - if (ieee80211_is_data_qos(hdr->frame_control)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - sta_id = iwl_get_ra_sta_id(priv, hdr); - if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERROR("Station not known\n"); - return; - } + tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; + sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS; if (txq->sched_retry) { const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; - if (!qc) - return; - agg = &priv->stations[sta_id].tid[tid].agg; iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); @@ -1288,53 +1275,53 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); - IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " - "%d index %d\n", scd_ssn , index); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim " + "scd_ssn=%d idx=%d txq=%d swq=%d\n", + scd_ssn , index, txq_id, txq->swq_id); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE + - priv->hw->queues; + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark) && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) ieee80211_wake_queue(priv->hw, txq_id); else - ieee80211_wake_queue(priv->hw, ampdu_q); + ieee80211_wake_queue(priv->hw, + txq->swq_id); } - iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { + BUG_ON(txq_id != txq->swq_id); + info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags = - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", txq_id, - iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) rate_n_flags " + "0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) { - int freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) + + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark)) ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); - } } + if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 67680a7..8f8734f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1413,21 +1413,21 @@ enum { }; enum { - TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ TX_STATUS_DELAY_MSK = 0x00000040, TX_STATUS_ABORT_MSK = 0x00000080, TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ - TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; -static inline int iwl_is_tx_success(u32 status) +static inline bool iwl_is_tx_success(u32 status) { status &= TX_STATUS_MSK; - return (status == TX_STATUS_SUCCESS) - || (status == TX_STATUS_DIRECT_DONE); + return (status == TX_STATUS_SUCCESS) || + (status == TX_STATUS_DIRECT_DONE); } @@ -1452,10 +1452,9 @@ enum { AGG_TX_STATE_DELAY_TX_MSK = 0x400 }; -#define AGG_TX_STATE_LAST_SENT_MSK \ -(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) +#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) /* # tx attempts for first frame in aggregation */ #define AGG_TX_STATE_TRY_CNT_POS 12 @@ -1528,6 +1527,28 @@ struct iwl4965_tx_resp { } u; } __attribute__ ((packed)); +/* + * definitions for initial rate index field + * bits [3:0] inital rate index + * bits [6:4] rate table color, used for the initial rate + * bit-7 invalid rate indication + * i.e. rate was not chosen from rate table + * or rate table color was changed during frame retries + * refer tlc rate info + */ + +#define IWL50_TX_RES_INIT_RATE_INDEX_POS 0 +#define IWL50_TX_RES_INIT_RATE_INDEX_MSK 0x0f +#define IWL50_TX_RES_RATE_TABLE_COLOR_POS 4 +#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK 0x70 +#define IWL50_TX_RES_INV_RATE_INDEX_MSK 0x80 + +/* refer to ra_tid */ +#define IWL50_TX_RES_TID_POS 0 +#define IWL50_TX_RES_TID_MSK 0x0f +#define IWL50_TX_RES_RA_POS 4 +#define IWL50_TX_RES_RA_MSK 0xf0 + struct iwl5000_tx_resp { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ @@ -1542,14 +1563,17 @@ struct iwl5000_tx_resp { * For agg: RTS + CTS + aggregation tx time + block-ack time. */ __le16 wireless_media_time; /* uSecs */ - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; + u8 pa_status; /* RF power amplifier measurement (not used) */ + u8 pa_integ_res_a[3]; + u8 pa_integ_res_b[3]; + u8 pa_integ_res_C[3]; __le32 tfd_info; __le16 seq_ctl; __le16 byte_cnt; - __le32 tlc_info; + u8 tlc_info; + u8 ra_tid; /* tid (0:3), sta_id (4:7) */ + __le16 frame_ctrl; /* * For non-agg: frame status TX_STATUS_* * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e548d67..2b48a4c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -183,6 +183,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) +#define IWL_DEBUG_TX_REPLY_LIMIT(f, a...) \ + IWL_DEBUG_LIMIT(IWL_DL_TX_REPLY, f, ## a) #define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) #define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) #define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1f42e90..2f871f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -135,9 +135,10 @@ struct iwl_tx_queue { struct iwl_tfd *tfds; struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; struct iwl_tx_info *txb; - int need_update; - int sched_retry; - int active; + u8 need_update; + u8 sched_retry; + u8 active; + u8 swq_id; }; #define IWL_NUM_SCAN_RATES (2) @@ -519,7 +520,6 @@ struct iwl_sensitivity_ranges { * @ct_kill_threshold: temperature threshold * @calib_init_cfg: setup initial claibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values - * @first_ampdu_q: first HW queue available for ampdu */ struct iwl_hw_params { u16 max_txq_num; @@ -541,7 +541,6 @@ struct iwl_hw_params { u32 ct_kill_threshold; /* value in hw-dependent units */ u32 calib_init_cfg; const struct iwl_sensitivity_ranges *sens; - u8 first_ampdu_q; }; #define HT_SHORT_GI_20MHZ (1 << 0) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 6cf4a7c..cfa7826 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -895,9 +895,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) priv->stations[sta_id].tid[tid].tfds_in_queue++; } - /* Descriptor for chosen Tx queue */ txq = &priv->txq[txq_id]; q = &txq->q; + txq->swq_id = swq_id; spin_lock_irqsave(&priv->lock, flags); @@ -1023,7 +1023,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } else { - ieee80211_stop_queue(priv->hw, swq_id); + ieee80211_stop_queue(priv->hw, txq->swq_id); } } @@ -1395,8 +1395,8 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) case IWL_EMPTYING_HW_QUEUE_DELBA: /* We are reclaiming the last packet of the */ /* aggregated HW queue */ - if (txq_id == tid_data->agg.txq_id && - q->read_ptr == q->write_ptr) { + if ((txq_id == tid_data->agg.txq_id) && + (q->read_ptr == q->write_ptr)) { u16 ssn = SEQ_TO_SN(tid_data->seq_number); int tx_fifo = default_tid_to_tx_fifo[tid]; IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n"); @@ -1447,7 +1447,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); /* Calculate shift to align block-ack bits with our Tx window bits */ - sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4); + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); if (sh < 0) /* tbw something is wrong with indices */ sh += 0x100; @@ -1497,9 +1497,11 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; - int index; struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; + int index; + int sta_id; + int tid; /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); @@ -1514,14 +1516,16 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, } txq = &priv->txq[scd_flow]; - agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + sta_id = ba_resp->sta_id; + tid = ba_resp->tid; + agg = &priv->stations[sta_id].tid[tid].agg; /* Find index just before block-ack window */ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); /* TODO: Need to get this copy more safely - now good for debug */ - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %pM, " + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d] Received from %pM, " "sta_id = %d\n", agg->wait_for_ba, (u8 *) &ba_resp->sta_addr_lo32, @@ -1545,18 +1549,15 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, * transmitted ... if not, it's too late anyway). */ if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { /* calculate mac80211 ampdu sw queue to wake */ - int ampdu_q = - scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues; int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); - priv->stations[ba_resp->sta_id]. - tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, ampdu_q); - - iwl_txq_check_empty(priv, ba_resp->sta_id, - ba_resp->tid, scd_flow); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && + priv->mac80211_registered && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) + ieee80211_wake_queue(priv->hw, txq->swq_id); + + iwl_txq_check_empty(priv, sta_id, tid, scd_flow); } } EXPORT_SYMBOL(iwl_rx_reply_compressed_ba); -- cgit v1.1 From ed7fafec5e566a30fb21586c98cbef76c306d209 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Oct 2008 23:48:50 -0700 Subject: iwlwifi: don't update TFD free counter for invalid station This patch makes sure that station table is not accessed with invalid station id in 4965 TX response path Signed-off-by: Tomas Winkler Reported-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 881bf04..741b425 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2236,7 +2236,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, tx_resp->failure_frame); freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (qc) + if (qc && likely(sta_id != IWL_INVALID_STATION)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (priv->mac80211_registered && @@ -2244,7 +2244,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, ieee80211_wake_queue(priv->hw, txq_id); } - if (qc) + if (qc && likely(sta_id != IWL_INVALID_STATION)) iwl_txq_check_empty(priv, sta_id, tid, txq_id); if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) -- cgit v1.1 From 0ef2ca67b19e2286eed8eeb7ef7a35ce57d6d629 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Oct 2008 23:48:51 -0700 Subject: iwlwifi: parametrize eeprom versions This patch uses new parameters eeprom_ver and eeprom_calib_ver to support additional HW. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 26 +++++--------------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 29 +++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 18 +++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 5 ++++- 5 files changed, 41 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 741b425..f53cd2b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -318,27 +318,9 @@ static int is_fat_channel(__le32 rxon_flags) /* * EEPROM handlers */ - -static int iwl4965_eeprom_check_version(struct iwl_priv *priv) +static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv) { - u16 eeprom_ver; - u16 calib_ver; - - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - - calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); - - if (eeprom_ver < EEPROM_4965_EEPROM_VERSION || - calib_ver < EEPROM_4965_TX_POWER_VERSION) - goto err; - - return 0; -err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, EEPROM_4965_EEPROM_VERSION, - calib_ver, EEPROM_4965_TX_POWER_VERSION); - return -EINVAL; - + return iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); } /* @@ -2355,7 +2337,7 @@ static struct iwl_lib_ops iwl4965_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, - .check_version = iwl4965_eeprom_check_version, + .calib_version = iwl4965_eeprom_calib_version, .query_addr = iwlcore_eeprom_query_addr, }, .send_tx_power = iwl4965_send_tx_power, @@ -2374,6 +2356,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .eeprom_size = IWL4965_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_4965_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a8c8c85..f3316d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -293,30 +293,17 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } -static int iwl5000_eeprom_check_version(struct iwl_priv *priv) +static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) { - u16 eeprom_ver; struct iwl_eeprom_calib_hdr { u8 version; u8 pa_type; u16 voltage; } *hdr; - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, EEPROM_5000_CALIB_ALL); - - if (eeprom_ver < EEPROM_5000_EEPROM_VERSION || - hdr->version < EEPROM_5000_TX_POWER_VERSION) - goto err; - - return 0; -err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, EEPROM_5000_EEPROM_VERSION, - hdr->version, EEPROM_5000_TX_POWER_VERSION); - return -EINVAL; + return hdr->version; } @@ -1510,7 +1497,7 @@ static struct iwl_lib_ops iwl5000_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, - .check_version = iwl5000_eeprom_check_version, + .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, }, }; @@ -1537,6 +1524,8 @@ struct iwl_cfg iwl5300_agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; @@ -1546,6 +1535,8 @@ struct iwl_cfg iwl5100_bg_cfg = { .sku = IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; @@ -1555,6 +1546,8 @@ struct iwl_cfg iwl5100_abg_cfg = { .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; @@ -1564,6 +1557,8 @@ struct iwl_cfg iwl5100_agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; @@ -1573,6 +1568,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2d8afe..fb95c6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -173,6 +173,8 @@ struct iwl_cfg { const char *fw_name; unsigned int sku; int eeprom_size; + u16 eeprom_ver; + u16 eeprom_calib_ver; const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 3715575..5160b4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -279,7 +279,23 @@ EXPORT_SYMBOL(iwl_eeprom_free); int iwl_eeprom_check_version(struct iwl_priv *priv) { - return priv->cfg->ops->lib->eeprom_ops.check_version(priv); + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) + goto err; + + return 0; +err: + IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, priv->cfg->eeprom_ver, + calib_ver, priv->cfg->eeprom_calib_ver); + return -EINVAL; + } EXPORT_SYMBOL(iwl_eeprom_check_version); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d3a2a5b..997f23c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -174,6 +174,9 @@ struct iwl_eeprom_channel { #define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +/* 5050 Specific */ +#define EEPROM_5050_TX_POWER_VERSION (4) +#define EEPROM_5050_EEPROM_VERSION (0x21E) /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; @@ -371,7 +374,7 @@ struct iwl_eeprom_ops { int (*verify_signature) (struct iwl_priv *priv); int (*acquire_semaphore) (struct iwl_priv *priv); void (*release_semaphore) (struct iwl_priv *priv); - int (*check_version) (struct iwl_priv *priv); + u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); }; -- cgit v1.1 From f69f42a6bbefb311ccb1626fdb61f723160afbfd Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Oct 2008 23:48:52 -0700 Subject: iwlwifi: calibration command namespace renaming Since calibration framework is not HW specific remove 5000 and 4965 prefix This patch doesn't provide any functional changes only code renaming and movement Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 8 ++-- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 9 ---- drivers/net/wireless/iwlwifi/iwl-5000.c | 42 +++++++++--------- drivers/net/wireless/iwlwifi/iwl-commands.h | 69 +++++++++++++++-------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 15 ++++++- 5 files changed, 74 insertions(+), 69 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f53cd2b..aad32a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -519,10 +519,10 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv) struct iwl_chain_noise_data *data = &(priv->chain_noise_data); if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl4965_calibration_cmd cmd; + struct iwl_calib_diff_gain_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.opCode = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; @@ -569,11 +569,11 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, /* Differential gain gets sent to uCode only once */ if (!data->radio_write) { - struct iwl4965_calibration_cmd cmd; + struct iwl_calib_diff_gain_cmd cmd; data->radio_write = 1; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.opCode = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 66ed993..fa06443 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -129,14 +129,5 @@ struct iwl5000_shared { __le32 padding2; } __attribute__ ((packed)); -/* calibrations defined for 5000 */ -/* defines the order in which results should be sent to the runtime uCode */ -enum iwl5000_calib { - IWL5000_CALIB_XTAL, - IWL5000_CALIB_LO, - IWL5000_CALIB_TX_IQ, - IWL5000_CALIB_TX_IQ_PERD, -}; - #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f3316d4..b4b7e8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -337,10 +337,10 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->delta_gain_code[1], data->delta_gain_code[2]); if (!data->radio_write) { - struct iwl5000_calibration_chain_noise_gain_cmd cmd; + struct iwl_calib_chain_noise_gain_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; cmd.delta_gain_1 = data->delta_gain_code[1]; cmd.delta_gain_2 = data->delta_gain_code[2]; iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, @@ -364,10 +364,10 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv) struct iwl_chain_noise_data *data = &priv->chain_noise_data; if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl5000_calibration_chain_noise_reset_cmd cmd; + struct iwl_calib_chain_noise_reset_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; + cmd.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd)) IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); @@ -420,25 +420,25 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, */ static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { - u8 data[sizeof(struct iwl5000_calib_hdr) + + u8 data[sizeof(struct iwl_calib_hdr) + sizeof(struct iwl_cal_xtal_freq)]; - struct iwl5000_calib_cmd *cmd = (struct iwl5000_calib_cmd *)data; + struct iwl_calib_cmd *cmd = (struct iwl_calib_cmd *)data; struct iwl_cal_xtal_freq *xtal = (struct iwl_cal_xtal_freq *)cmd->data; u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); - cmd->hdr.op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; + cmd->hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; xtal->cap_pin1 = (u8)xtal_calib[0]; xtal->cap_pin2 = (u8)xtal_calib[1]; - return iwl_calib_set(&priv->calib_results[IWL5000_CALIB_XTAL], + return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], data, sizeof(data)); } static int iwl5000_send_calib_cfg(struct iwl_priv *priv) { - struct iwl5000_calib_cfg_cmd calib_cfg_cmd; + struct iwl_calib_cfg_cmd calib_cfg_cmd; struct iwl_host_cmd cmd = { .id = CALIBRATION_CFG_CMD, - .len = sizeof(struct iwl5000_calib_cfg_cmd), + .len = sizeof(struct iwl_calib_cfg_cmd), .data = &calib_cfg_cmd, }; @@ -455,7 +455,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; + struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; int index; @@ -466,14 +466,14 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, * uCode. iwl_send_calib_results sends them in a row according to their * index. We sort them here */ switch (hdr->op_code) { - case IWL5000_PHY_CALIBRATE_LO_CMD: - index = IWL5000_CALIB_LO; + case IWL_PHY_CALIBRATE_LO_CMD: + index = IWL_CALIB_LO; break; - case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: - index = IWL5000_CALIB_TX_IQ; + case IWL_PHY_CALIBRATE_TX_IQ_CMD: + index = IWL_CALIB_TX_IQ; break; - case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: - index = IWL5000_CALIB_TX_IQ_PERD; + case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD: + index = IWL_CALIB_TX_IQ_PERD; break; default: IWL_ERROR("Unknown calibration notification %d\n", @@ -839,10 +839,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: priv->hw_params.calib_init_cfg = - BIT(IWL5000_CALIB_XTAL) | - BIT(IWL5000_CALIB_LO) | - BIT(IWL5000_CALIB_TX_IQ) | - BIT(IWL5000_CALIB_TX_IQ_PERD); + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD); break; case CSR_HW_REV_TYPE_5150: priv->hw_params.calib_init_cfg = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8f8734f..56964ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2875,36 +2875,25 @@ struct iwl_sensitivity_cmd { * 1-0: amount of gain, units of 1.5 dB */ -/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ -#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) - -struct iwl4965_calibration_cmd { - u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ - u8 flags; /* not used */ - __le16 reserved; - s8 diff_gain_a; /* see above */ - s8 diff_gain_b; - s8 diff_gain_c; - u8 reserved1; -} __attribute__ ((packed)); - -/* Phy calibration command for 5000 series */ +/* Phy calibration command for series */ enum { - IWL5000_PHY_CALIBRATE_DC_CMD = 8, - IWL5000_PHY_CALIBRATE_LO_CMD = 9, - IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, - IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, - IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, - IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, - IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, - IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, - IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, - IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, + IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7, + IWL_PHY_CALIBRATE_DC_CMD = 8, + IWL_PHY_CALIBRATE_LO_CMD = 9, + IWL_PHY_CALIBRATE_RX_BB_CMD = 10, + IWL_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL_PHY_CALIBRATION_NOISE_CMD = 13, + IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, + IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, + IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, }; + struct iwl_cal_xtal_freq { u8 cap_pin1; u8 cap_pin2; @@ -2926,32 +2915,44 @@ struct iwl_calib_cfg_status_s { __le32 flags; } __attribute__ ((packed)); -struct iwl5000_calib_cfg_cmd { +struct iwl_calib_cfg_cmd { struct iwl_calib_cfg_status_s ucd_calib_cfg; struct iwl_calib_cfg_status_s drv_calib_cfg; __le32 reserved1; } __attribute__ ((packed)); -struct iwl5000_calib_hdr { +struct iwl_calib_hdr { u8 op_code; u8 first_group; u8 groups_num; u8 data_valid; } __attribute__ ((packed)); -struct iwl5000_calib_cmd { - struct iwl5000_calib_hdr hdr; +struct iwl_calib_cmd { + struct iwl_calib_hdr hdr; u8 data[0]; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_reset_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ +/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ + +struct iwl_calib_diff_gain_cmd { + u8 opCode; /* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ + u8 flags; /* not used */ + __le16 reserved; + s8 diff_gain_a; /* see above */ + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +struct iwl_calib_chain_noise_reset_cmd { + u8 op_code; /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ u8 flags; /* not used */ __le16 reserved; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_gain_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ +struct iwl_calib_chain_noise_gain_cmd { + u8 op_code; /* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ u8 flags; /* not used */ __le16 reserved; u8 delta_gain_1; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2f871f0..f546b7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -690,6 +690,20 @@ struct statistics_general_data { u32 beacon_energy_c; }; + +/* + * enum iwl_calib + * defines the order in which results of initial calibrations + * should be sent to the runtime uCode + */ +enum iwl_calib { + IWL_CALIB_XTAL, + IWL_CALIB_LO, + IWL_CALIB_TX_IQ, + IWL_CALIB_TX_IQ_PERD, + IWL_CALIB_MAX +}; + /* Opaque calibration results */ struct iwl_calib_result { void *buf; @@ -756,7 +770,6 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ -#define IWL_CALIB_MAX 4 struct iwl_priv { -- cgit v1.1 From 60d32215a94ebba2517b8d92612200ab610943fd Mon Sep 17 00:00:00 2001 From: "Daniel C. Halperin" Date: Thu, 23 Oct 2008 23:48:53 -0700 Subject: iwlwifi: convert correctly rate_n_flags to PLCP index for mimo3 packets The driver does not properly convert rate_n_flags to PLCP index for mimo3 packets. This makes mac80211 drop the packets Signed-off-by: Daniel C. Halperin Reviewed-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ba05f5d..a7cb40b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -120,7 +120,9 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) if (rate_n_flags & RATE_MCS_HT_MSK) { idx = (rate_n_flags & 0xff); - if (idx >= IWL_RATE_MIMO2_6M_PLCP) + if (idx >= IWL_RATE_MIMO3_6M_PLCP) + idx = idx - IWL_RATE_MIMO3_6M_PLCP; + else if (idx >= IWL_RATE_MIMO2_6M_PLCP) idx = idx - IWL_RATE_MIMO2_6M_PLCP; idx += IWL_FIRST_OFDM_RATE; -- cgit v1.1 From 951891c7ef844919d30aac7b1fc7396fd8be23ff Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Thu, 23 Oct 2008 23:48:54 -0700 Subject: iwlwifi: clear scanning bits upon failure In iwl_bg_request_scan function, if we could not send a scan command it will go to done. In done it does the right thing to call mac80211 with scan complete, but the problem is STATUS_SCAN_HW is still set causing any future scan to fail. Fix by clearing the scanning status bits if scan fails. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 3379b41..b0abf89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -834,6 +834,13 @@ static void iwl_bg_request_scan(struct work_struct *data) return; done: + /* Cannot perform scan. Make sure we clear scanning + * bits from status so next scan request can be performed. + * If we don't clear scanning status bit here all next scan + * will fail + */ + clear_bit(STATUS_SCAN_HW, &priv->status); + clear_bit(STATUS_SCANNING, &priv->status); /* inform mac80211 scan aborted */ queue_work(priv->workqueue, &priv->scan_completed); mutex_unlock(&priv->mutex); -- cgit v1.1 From 127901ab69bbb263fb2b46e850cf20c57ac321d3 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Oct 2008 23:48:55 -0700 Subject: iwlwifi: refactor tx byte count table usage This patch drops unreadable usage of IWL_SET/GET_BITS16 in byte count tables handling This patch also cleans a bit the byte count table code and adds WARN_ON traps on invalid values This patch is pure cleanup, no functional changes. Signed-off-by: Tomas Winkler Cc: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 38 ++--------- drivers/net/wireless/iwlwifi/iwl-4965.c | 21 +++--- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 29 ++++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 52 +++++++-------- drivers/net/wireless/iwlwifi/iwl-fh.h | 5 ++ drivers/net/wireless/iwlwifi/iwl-helpers.h | 102 ----------------------------- 6 files changed, 62 insertions(+), 185 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index b66dd09..f3f41a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -111,7 +111,6 @@ #define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -#define TFD_QUEUE_SIZE_MAX (256) #define IWL_NUM_SCAN_RATES (2) @@ -815,8 +814,6 @@ enum { * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array * in DRAM containing 256 Transmit Frame Descriptors (TFDs). */ -#define IWL49_MAX_WIN_SIZE 64 -#define IWL49_QUEUE_SIZE 256 #define IWL49_NUM_FIFOS 7 #define IWL49_CMD_FIFO_NUM 4 #define IWL49_NUM_QUEUES 16 @@ -882,26 +879,7 @@ struct iwl_tfd { /** - * struct iwl4965_queue_byte_cnt_entry - * - * Byte Count Table Entry - * - * Bit fields: - * 15-12: reserved - * 11- 0: total to-be-transmitted byte count of frame (does not include command) - */ -struct iwl4965_queue_byte_cnt_entry { - __le16 val; - /* __le16 byte_cnt:12; */ -#define IWL_byte_cnt_POS 0 -#define IWL_byte_cnt_LEN 12 -#define IWL_byte_cnt_SYM val - /* __le16 rsvd:4; */ -} __attribute__ ((packed)); - - -/** - * struct iwl4965_sched_queue_byte_cnt_tbl + * struct iwl4965_schedq_bc_tbl * * Byte Count table * @@ -915,15 +893,12 @@ struct iwl4965_queue_byte_cnt_entry { * count table for the chosen Tx queue. If the TFD index is 0-63, the driver * must duplicate the byte count entry in corresponding index 256-319. * - * "dont_care" padding puts each byte count table on a 1024-byte boundary; + * padding puts each byte count table on a 1024-byte boundary; * 4965 assumes tables are separated by 1024 bytes. */ -struct iwl4965_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE + - IWL49_MAX_WIN_SIZE]; - u8 dont_care[1024 - - (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) * - sizeof(__le16)]; +struct iwl4965_schedq_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; + u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)]; } __attribute__ ((packed)); @@ -951,8 +926,7 @@ struct iwl4965_sched_queue_byte_cnt_tbl { * 31- 0: Not used */ struct iwl4965_shared { - struct iwl4965_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL49_NUM_QUEUES]; + struct iwl4965_schedq_bc_tbl queues_bc_tbls[IWL49_NUM_QUEUES]; __le32 rb_closed; /* __le32 rb_closed_stts_rb_num:12; */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index aad32a3..1f22140 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -716,7 +716,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) /* Tel 4965 where to find Tx byte count tables */ iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, (priv->shared_phys + - offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); + offsetof(struct iwl4965_shared, queues_bc_tbls)) >> 10); /* Disable chain mode for all queues */ iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); @@ -1668,21 +1668,22 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - int len; - int txq_id = txq->q.id; struct iwl4965_shared *shared_data = priv->shared_virt; + int txq_id = txq->q.id; + int write_ptr = txq->q.write_ptr; + int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + __le16 bc_ent; - len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); + bc_ent = cpu_to_le16(len & 0xFFF); /* Set up byte count within first 256 entries */ - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], byte_cnt, len); + shared_data->queues_bc_tbls[txq_id].tfd_offset[write_ptr] = bc_ent; /* If within first 64 entries, duplicate at end */ - if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE) - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr], - byte_cnt, len); + if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) + shared_data->queues_bc_tbls[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index fa06443..49ede54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -76,30 +76,31 @@ /* EERPROM */ #define IWL_5000_EEPROM_IMG_SIZE 2048 - -#define IWL50_MAX_WIN_SIZE 64 -#define IWL50_QUEUE_SIZE 256 #define IWL50_CMD_FIFO_NUM 7 #define IWL50_NUM_QUEUES 20 #define IWL50_NUM_AMPDU_QUEUES 10 #define IWL50_FIRST_AMPDU_QUEUE 10 -#define IWL_sta_id_POS 12 -#define IWL_sta_id_LEN 4 -#define IWL_sta_id_SYM val - /* Fixed (non-configurable) rx data from phy */ -/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR - * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ -struct iwl5000_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE + - IWL50_MAX_WIN_SIZE]; +/** + * struct iwl5000_schedq_bc_tbl scheduler byte count table + * base physical address of iwl5000_shared + * is provided to SCD_DRAM_BASE_ADDR + * @tfd_offset 0-12 - tx command byte count + * 12-16 - station index + */ +struct iwl5000_schedq_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; } __attribute__ ((packed)); +/** + * struct iwl5000_shared + * @rb_closed + * address is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG + */ struct iwl5000_shared { - struct iwl5000_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL50_NUM_QUEUES]; + struct iwl5000_schedq_bc_tbl queues_bc_tbls[IWL50_NUM_QUEUES]; __le32 rb_closed; /* __le32 rb_closed_stts_rb_num:12; */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b4b7e8b..0c9281e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -723,7 +723,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, (priv->shared_phys + - offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); + offsetof(struct iwl5000_shared, queues_bc_tbls)) >> 10); iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, IWL50_SCD_QUEUECHAIN_SEL_ALL( priv->hw_params.max_txq_num)); @@ -891,15 +891,17 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, u16 byte_cnt) { struct iwl5000_shared *shared_data = priv->shared_virt; + int write_ptr = txq->q.write_ptr; int txq_id = txq->q.id; u8 sec_ctl = 0; - u8 sta = 0; - int len; + u8 sta_id = 0; + u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + __le16 bc_ent; - len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != IWL_CMD_QUEUE_NUM) { - sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { @@ -915,40 +917,36 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, } } - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], byte_cnt, len); + bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], sta_id, sta); + shared_data->queues_bc_tbls[txq_id].tfd_offset[write_ptr] = bc_ent; - if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], - byte_cnt, len); - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], - sta_id, sta); - } + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + shared_data->queues_bc_tbls[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int txq_id = txq->q.id; struct iwl5000_shared *shared_data = priv->shared_virt; - u8 sta = 0; + int txq_id = txq->q.id; + int read_ptr = txq->q.read_ptr; + u8 sta_id = 0; + __le16 bc_ent; + + WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != IWL_CMD_QUEUE_NUM) - sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id; + sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; - shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. - val = cpu_to_le16(1 | (sta << 12)); + bc_ent = cpu_to_le16(1 | (sta_id << 12)); + shared_data->queues_bc_tbls[txq_id]. + tfd_offset[read_ptr] = bc_ent; - if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { - shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr]. - val = cpu_to_le16(1 | (sta << 12)); - } + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + shared_data->queues_bc_tbls[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 8c48d88..f2688d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -393,4 +393,9 @@ /* TCSR: tx_config register values */ #define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ +#define TFD_QUEUE_SIZE_MAX (256) +#define TFD_QUEUE_SIZE_BC_DUP (64) +#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) + + #endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 029d19c..4f0fa21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -32,108 +32,6 @@ #include -/* - * The structures defined by the hardware/uCode interface - * have bit-wise operations. For each bit-field there is - * a data symbol in the structure, the start bit position - * and the length of the bit-field. - * - * iwl_get_bits and iwl_set_bits will return or set the - * appropriate bits on a 32-bit value. - * - * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to - * expand out to the appropriate call to iwl_get_bits - * and iwl_set_bits without having to reference all of the - * numerical constants and defines provided in the hardware - * definition - */ - -/** - * iwl_get_bits - Extract a hardware bit-field value - * @src: source hardware value (__le32) - * @pos: bit-position (0-based) of first bit of value - * @len: length of bit-field - * - * iwl_get_bits will return the bit-field in cpu endian ordering. - * - * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and - * will collapse to minimal code by the compiler. - */ -static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len) -{ - u32 tmp = le32_to_cpu(src); - - tmp >>= pos; - tmp &= (1UL << len) - 1; - return tmp; -} - -/** - * iwl_set_bits - Set a hardware bit-field value - * @dst: Address of __le32 hardware value - * @pos: bit-position (0-based) of first bit of value - * @len: length of bit-field - * @val: cpu endian value to encode into the bit-field - * - * iwl_set_bits will encode val into dst, masked to be len bits long at bit - * position pos. - * - * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and - * will collapse to minimal code by the compiler. - */ -static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val) -{ - u32 tmp = le32_to_cpu(*dst); - - tmp &= ~(((1UL << len) - 1) << pos); - tmp |= (val & ((1UL << len) - 1)) << pos; - *dst = cpu_to_le32(tmp); -} - -static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) -{ - u16 tmp = le16_to_cpu(*dst); - - tmp &= ~((1UL << (pos + len)) - (1UL << pos)); - tmp |= (val & ((1UL << len) - 1)) << pos; - *dst = cpu_to_le16(tmp); -} - -/* - * The bit-field definitions in iwl-xxxx-hw.h are in the form of: - * - * struct example { - * __le32 val1; - * #define IWL_name_POS 8 - * #define IWL_name_LEN 4 - * #define IWL_name_SYM val1 - * }; - * - * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver - * to call: - * - * struct example bar; - * u32 val = IWL_GET_BITS(bar, name); - * val = val * 2; - * IWL_SET_BITS(bar, name, val); - * - * All cpu / host ordering, masking, and shifts are performed by the macros - * and iwl_{get,set}_bits. - * - */ -#define IWL_SET_BITS(s, sym, v) \ - iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN, (v)) - -#define IWL_SET_BITS16(s, sym, v) \ - iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN, (v)) - -#define IWL_GET_BITS(s, sym) \ - iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN) - - #define KELVIN_TO_CELSIUS(x) ((x)-273) #define CELSIUS_TO_KELVIN(x) ((x)+273) #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) -- cgit v1.1 From a96a27f97f2bbfc1fca54bc3c0b0d41484152740 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Oct 2008 23:48:56 -0700 Subject: iwlwifi: run through spell checker Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-commands.h | 6 ++--- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 12 +++++----- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 ++++----- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 10 ++++----- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 28 ++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 7 +++--- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 2 +- drivers/net/wireless/iwlwifi/iwl-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-power.c | 18 +++++++-------- drivers/net/wireless/iwlwifi/iwl-prph.h | 6 ++--- drivers/net/wireless/iwlwifi/iwl-rfkill.c | 8 +++---- drivers/net/wireless/iwlwifi/iwl-rx.c | 8 +++---- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 6 ++--- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 28 ++++++++++++------------ 26 files changed, 91 insertions(+), 92 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 817ece7..8772d9d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -121,7 +121,7 @@ enum { REPLY_TX_PWR_TABLE_CMD = 0x97, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* Bluetooth device coexistance config command */ + /* Bluetooth device coexistence config command */ REPLY_BT_CONFIG = 0x9b, /* Statistics */ @@ -158,7 +158,7 @@ struct iwl3945_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* IWL_CMD_* */ /* - * The driver sets up the sequence number to values of its chosing. + * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so * the driver can match the response to the command. Since the values @@ -991,7 +991,7 @@ struct iwl3945_rate_scaling_cmd { * * 3945 and 4965 support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; - * wireless device can delay or kill its own Tx to accomodate. + * wireless device can delay or kill its own Tx to accommodate. */ struct iwl3945_bt_cmd { u8 flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index b3fe48d..1daa3f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -53,7 +53,7 @@ * _iwl3945_read32.) * * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with + * which result in misconfiguration of the hardware I/O. In combination with * git-bisect and the IO debug level you can quickly determine the specific * commit which breaks the IO sequence to the hardware. * diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7afafb6..af77ea7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -200,7 +200,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp) * priv->eeprom is used to determine if antenna AUX/MAIN are reversed * priv->antenna specifies the antenna diversity mode: * - * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself + * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself * IWL_ANTENNA_MAIN - Force MAIN antenna * IWL_ANTENNA_AUX - Force AUX antenna */ @@ -1882,7 +1882,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv) ref_temp = (s16)priv->eeprom.groups[ch_info->group_index]. temperature; - /* get power index adjustment based on curr and factory + /* get power index adjustment based on current and factory * temps */ delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, ref_temp); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index f3f41a6..9da7c7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -71,7 +71,7 @@ #include "iwl-fh.h" -/* EERPROM */ +/* EEPROM */ #define IWL4965_EEPROM_IMG_SIZE 1024 /* @@ -286,13 +286,13 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * that target txpower. * * - * 3) Determine (EEPROM) calibration subband for the target channel, by - * comparing against first and last channels in each subband + * 3) Determine (EEPROM) calibration sub band for the target channel, by + * comparing against first and last channels in each sub band * (see struct iwl4965_eeprom_calib_subband_info). * * * 4) Linearly interpolate (EEPROM) factory calibration measurement sets, - * referencing the 2 factory-measured (sample) channels within the subband. + * referencing the 2 factory-measured (sample) channels within the sub band. * * Interpolation is based on difference between target channel's frequency * and the sample channels' frequencies. Since channel numbers are based @@ -300,7 +300,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * to interpolating based on channel number differences. * * Note that the sample channels may or may not be the channels at the - * edges of the subband. The target channel may be "outside" of the + * edges of the sub band. The target channel may be "outside" of the * span of the sampled channels. * * Driver may choose the pair (for 2 Tx chains) of measurements (see @@ -344,7 +344,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * "4965 temperature calculation". * * If current temperature is higher than factory temperature, driver must - * increase gain (lower gain table index), and vice versa. + * increase gain (lower gain table index), and vice verse. * * Temperature affects gain differently for different channels: * diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1f22140..0953a9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -246,7 +246,7 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); - /* Inst bytecount must be last to set up, bit 31 signals uCode + /* Inst byte count must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); @@ -324,7 +324,7 @@ static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv) } /* - * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) @@ -396,7 +396,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv) /* L1 is enabled by BIOS */ if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* diable L0S disabled L1A enabled */ + /* disable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else /* L0S enabled L1A disabled */ @@ -625,7 +625,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) mutex_lock(&priv->mutex); - /* Regardless of if we are assocaited, we must reconfigure the + /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while * not associated */ iwl4965_send_tx_power(priv); @@ -2019,7 +2019,7 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) } /** - * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue + * iwl4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue */ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, struct iwl_ht_agg *agg, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 49ede54..12c7404 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -73,7 +73,7 @@ #define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) #define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) -/* EERPROM */ +/* EEPROM */ #define IWL_5000_EEPROM_IMG_SIZE 2048 #define IWL50_CMD_FIFO_NUM 7 diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0c9281e..4348c7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -94,7 +94,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - /* Set FH wait treshold to maximum (HW error during stress W/A) */ + /* Set FH wait threshold to maximum (HW error during stress W/A) */ iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); /* enable HAP INTA to move device L1a -> L0s */ @@ -134,7 +134,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -/* FIXME: this is indentical to 4965 */ +/* FIXME: this is identical to 4965 */ static void iwl5000_apm_stop(struct iwl_priv *priv) { unsigned long flags; @@ -219,7 +219,7 @@ static void iwl5000_nic_config(struct iwl_priv *priv) /* L1 is enabled by BIOS */ if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* diable L0S disabled L1A enabled */ + /* disable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else /* L0S enabled L1A disabled */ @@ -1093,7 +1093,7 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) /* - * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) @@ -1311,7 +1311,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } -/* Currently 5000 is the supperset of everything */ +/* Currently 5000 is the superset of everything */ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) { return len; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 6fdb2fb..f5e94b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -188,7 +188,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * "G" is the only table that supports CCK (the first 4 rates). */ -/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/ +/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/ static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -2253,7 +2253,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->active_mimo2_rate, lq_sta->active_mimo3_rate); - /* These values will be overriden later */ + /* These values will be overridden later */ lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index bac91f1..ccfafcf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -229,7 +229,7 @@ enum { #define IWL_MIMO2_SWITCH_SISO_C 4 #define IWL_MIMO2_SWITCH_GI 5 -/*FIXME:RS:add posible acctions for MIMO3*/ +/*FIXME:RS:add possible actions for MIMO3*/ #define IWL_ACTION_LIMIT 3 /* # possible actions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7c3eb3d..7a7caac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1484,7 +1484,7 @@ static void iwl4965_enable_interrupts(struct iwl_priv *priv) /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl_priv *priv) { - /* wait to make sure we flush pedding tasklet*/ + /* wait to make sure we flush pending tasklet*/ synchronize_irq(priv->pci_dev->irq); tasklet_kill(&priv->irq_tasklet); } diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 56964ee..5ab74fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -134,7 +134,7 @@ enum { REPLY_TX_POWER_DBM_CMD = 0x98, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* Bluetooth device coexistance config command */ + /* Bluetooth device coexistence config command */ REPLY_BT_CONFIG = 0x9b, /* Statistics */ @@ -185,7 +185,7 @@ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ /* - * The driver sets up the sequence number to values of its chosing. + * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so * the driver can match the response to the command. Since the values @@ -347,7 +347,7 @@ struct iwl4965_tx_power_db { } __attribute__ ((packed)); /** - * Commad REPLY_TX_POWER_DBM_CMD = 0x98 + * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwl5000_tx_power_dbm_cmd */ #define IWL50_TX_POWER_AUTO 0x7f @@ -383,7 +383,7 @@ struct iwl5000_tx_power_dbm_cmd { * calculating txpower settings: * * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice versa. + * values for lower voltage, and vice verse. * * 2) Temperature measurement parameters, for each of two channel widths * (20 MHz and 40 MHz) supported by the radios. Temperature sensing @@ -622,7 +622,7 @@ struct iwl4965_rxon_cmd { u8 ofdm_ht_dual_stream_basic_rates; } __attribute__ ((packed)); -/* 5000 HW just extend this cmmand */ +/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -1113,7 +1113,7 @@ struct iwl4965_rx_non_cfg_phy { #define IWL50_OFDM_RSSI_C_BIT_POS 0 struct iwl5000_non_cfg_phy { - __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */ + __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */ } __attribute__ ((packed)); @@ -1169,7 +1169,7 @@ struct iwl4965_rx_mpdu_res_start { /* REPLY_TX Tx flags field */ -/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it +/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it * before this frame. if CTS-to-self required check * RXON_FLG_SELF_CTS_EN status. */ #define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0) @@ -1529,7 +1529,7 @@ struct iwl4965_tx_resp { /* * definitions for initial rate index field - * bits [3:0] inital rate index + * bits [3:0] initial rate index * bits [6:4] rate table color, used for the initial rate * bit-7 invalid rate indication * i.e. rate was not chosen from rate table @@ -1768,7 +1768,7 @@ struct iwl_link_qual_agg_params { * match the modulation characteristics of the history set. * * When using block-ack (aggregation), all frames are transmitted at the same - * rate, since there is no per-attempt acknowledgement from the destination + * rate, since there is no per-attempt acknowledgment from the destination * station. The Tx response struct iwl_tx_resp indicates the Tx rate in * rate_n_flags field. After receiving a block-ack, the driver can update * history for the entire block all at once. @@ -1907,7 +1907,7 @@ struct iwl_link_quality_cmd { * * 3945 and 4965 support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; - * wireless device can delay or kill its own Tx to accomodate. + * wireless device can delay or kill its own Tx to accommodate. */ struct iwl4965_bt_cmd { u8 flags; @@ -2069,7 +2069,7 @@ struct iwl4965_spectrum_notification { * '11' Illegal set * * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then - * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * ucode assume sleep over DTIM is allowed and we don't need to wake up * for every DTIM. */ #define IWL_POWER_VEC_SIZE 5 @@ -3017,11 +3017,11 @@ struct iwl_wimax_coex_event_entry { /* COEX flag masks */ -/* Staion table is valid */ +/* Station table is valid */ #define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1) -/* UnMask wakeup src at unassociated sleep */ +/* UnMask wake up src at unassociated sleep */ #define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4) -/* UnMask wakeup src at associated sleep */ +/* UnMask wake up src at associated sleep */ #define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8) /* Enable CoEx feature. */ #define COEX_FLAGS_COEX_ENABLE_MSK (0x80) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a7cb40b..8eb0203 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -747,7 +747,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) break; case WLAN_HT_CAP_SM_PS_INVALID: default: - IWL_ERROR("invalide mimo ps mode %d\n", + IWL_ERROR("invalid mimo ps mode %d\n", priv->current_ht_config.sm_ps); WARN_ON(1); idle_cnt = -1; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index fb95c6a..10f07f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -100,7 +100,7 @@ struct iwl_hcmd_utils_ops { }; struct iwl_lib_ops { - /* set hw dependant perameters */ + /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); /* ucode shared memory */ int (*alloc_shared_mem)(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 2b48a4c..84b7772 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -101,13 +101,12 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) * * To add your debug level to the list of levels seen when you perform * - * % cat /proc/net/iwl/debug_level + * % cat /sys/class/net/wlanX/device/debug_level * * you simply need to add your entry to the iwl_debug_levels array. * - * If you do not see debug_level in /proc/net/iwl then you do not have - * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration - * + * If you do not see debug_level in /sys/class/net/wlanX/device/debug_level + * then you do not have CONFIG_IWLWIFI_DEBUG defined in your kernel config file */ #define IWL_DL_INFO (1 << 0) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f546b7e..b58fcde 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -518,7 +518,7 @@ struct iwl_sensitivity_ranges { * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses * @ct_kill_threshold: temperature threshold - * @calib_init_cfg: setup initial claibrations for the hw + * @calib_init_cfg: setup initial calibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values */ struct iwl_hw_params { @@ -911,7 +911,7 @@ struct iwl_priv { unsigned long status; - int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_rssi; /* From Rx packet statistics */ int last_rx_noise; /* From beacon statistics */ /* counts mgmt, ctl, and data packets */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 5160b4b..792a3c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -291,7 +291,7 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) return 0; err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + IWL_ERROR("Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", eeprom_ver, priv->cfg->eeprom_ver, calib_ver, priv->cfg->eeprom_calib_ver); return -EINVAL; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 9740fcc..40e0050 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -55,7 +55,7 @@ * _iwl_read32.) * * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with + * which result in misconfiguration of the hardware I/O. In combination with * git-bisect and the IO debug level you can quickly determine the specific * commit which breaks the IO sequence to the hardware. * diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 4eee1b1..ffb428a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -278,7 +278,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) /* FIXME: + priv->rx_stats[2].bytes; */ s64 tpt = current_tpt - priv->led_tpt; - if (tpt < 0) /* wrapparound */ + if (tpt < 0) /* wraparound */ tpt = -tpt; IWL_DEBUG_LED("tpt %lld current_tpt %llu\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 60a03d2..07a5f60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -80,7 +80,7 @@ #define IWL_REDUCED_POWER_TEMPERATURE 95 /* default power management (not Tx power) table values */ -/* for tim 0-10 */ +/* for TIM 0-10 */ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, @@ -91,7 +91,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { }; -/* for tim = 3-10 */ +/* for TIM = 3-10 */ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, @@ -101,7 +101,7 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for tim > 11 */ +/* for TIM > 11 */ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, @@ -183,7 +183,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) return 0; } -/* adjust power command according to dtim period and power level*/ +/* adjust power command according to DTIM period and power level*/ static int iwl_update_power_command(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, u16 mode) @@ -325,7 +325,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) EXPORT_SYMBOL(iwl_power_update_mode); /* Allow other iwl code to disable/enable power management active - * this will be usefull for rate scale to disable PM during heavy + * this will be useful for rate scale to disable PM during heavy * Tx/Rx activities */ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) @@ -352,8 +352,8 @@ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) EXPORT_SYMBOL(iwl_power_disable_management); /* Allow other iwl code to disable/enable power management active - * this will be usefull for rate scale to disable PM during hight - * valume activities + * this will be useful for rate scale to disable PM during high + * volume activities */ int iwl_power_enable_management(struct iwl_priv *priv) { @@ -391,7 +391,7 @@ int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_system_mode); -/* initilize to default */ +/* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { @@ -443,7 +443,7 @@ static void iwl_bg_set_power_save(struct work_struct *work) mutex_lock(&priv->mutex); - /* on starting association we disable power managment + /* on starting association we disable power management * until association, if association failed then this * timer will expire and enable PM again. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index ee5afd4..b0ffb89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -158,9 +158,9 @@ * * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction * images in host DRAM. The last register loaded must be the instruction - * bytecount register ("1" in MSbit tells initialization uCode to load + * byte count register ("1" in MSbit tells initialization uCode to load * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD + * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD * * 5) Wait for "alive" notification, then issue normal runtime commands. * @@ -244,7 +244,7 @@ /** * Tx Scheduler * - * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs + * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in * host DRAM. It steers each frame's Tx command (which contains the frame * data) into one of up to 7 prioritized Tx DMA FIFO channels within the diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 5d64229..618841a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -64,7 +64,7 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) iwl_radio_kill_sw_disable_radio(priv); break; default: - IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + IWL_WARNING("we received unexpected RFKILL state %d\n", state); break; } out_unlock: @@ -83,7 +83,7 @@ int iwl_rfkill_init(struct iwl_priv *priv) IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); if (!priv->rfkill) { - IWL_ERROR("Unable to allocate rfkill device.\n"); + IWL_ERROR("Unable to allocate RFKILL device.\n"); ret = -ENOMEM; goto error; } @@ -99,7 +99,7 @@ int iwl_rfkill_init(struct iwl_priv *priv) ret = rfkill_register(priv->rfkill); if (ret) { - IWL_ERROR("Unable to register rfkill: %d\n", ret); + IWL_ERROR("Unable to register RFKILL: %d\n", ret); goto free_rfkill; } @@ -127,7 +127,7 @@ void iwl_rfkill_unregister(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rfkill_unregister); -/* set rf-kill to the right state. */ +/* set RFKILL to the right state. */ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) { if (!priv->rfkill) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 7cde9d7..b86f958 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -407,7 +407,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (priv->shared_phys + priv->rb_closed_offset) >> 4); /* Enable Rx DMA - * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in * the credit mechanism in 5000 HW RX FIFO * Direct rx interrupts to hosts * Rx buffer size 4 or 8k @@ -1149,7 +1149,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; /* Set "1" to report good data frames in groups of 100 */ - /* FIXME: need to optimze the call: */ + /* FIXME: need to optimize the call: */ iwl_dbg_report_frame(priv, pkt, header, 1); IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", @@ -1160,12 +1160,12 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * "antenna number" * * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, + * is actually a bit field. This is undefined by radiotap, * it wants an actual antenna number but I always get "7" * for most legacy frames I receive indicating that the * same frame was received on all three RX chains. * - * I think this field should be removed in favour of a + * I think this field should be removed in favor of a * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index b0abf89..6c5654f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -654,7 +654,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } - /* Make sure the scan wasn't cancelled before this queued work + /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index dde0850..bfc009c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -693,7 +693,7 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, /* else, we are overriding an existing key => no need to allocated room * in uCode. */ - /* This copy is acutally not needed: we get the key with each TX */ + /* This copy is actually not needed: we get the key with each TX */ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16); @@ -788,7 +788,7 @@ static void iwl_dump_lq_cmd(struct iwl_priv *priv, { int i; IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id); - IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", + IWL_DEBUG_RATE("lq ant 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk, lq->general_params.dual_stream_ant_msk); @@ -890,7 +890,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) * iwl_rxon_add_station - add station into station table. * * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling this fnction + * NOTE: mutex must be held before calling this function */ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index cfa7826..6008c0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -524,7 +524,7 @@ EXPORT_SYMBOL(iwl_hw_txq_ctx_free); /** * iwl_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialise them again + * Destroys all DMA structures and initialize them again * * @param priv * @return error code @@ -764,7 +764,7 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); if (info->flags & IEEE80211_TX_CTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n"); break; case ALG_TKIP: diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8009094..a4d9247 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1805,7 +1805,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) spin_unlock_irqrestore(&priv->lock, flags); if (force || iwl3945_is_associated(priv)) { - IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + IWL_DEBUG_QOS("send QoS cmd with QoS active %d \n", priv->qos_data.qos_active); iwl3945_send_qos_params_command(priv, @@ -1829,7 +1829,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) /* default power management (not Tx power) table values */ -/* for tim 0-10 */ +/* for TIM 0-10 */ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, @@ -1839,7 +1839,7 @@ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} }; -/* for tim > 10 */ +/* for TIM > 10 */ static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), @@ -2282,7 +2282,7 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) iwl3945_clear_stations_table(priv); - /* dont commit rxon if rf-kill is on*/ + /* don't commit rxon if rf-kill is on*/ if (!iwl3945_is_ready_rf(priv)) return -EAGAIN; @@ -2311,7 +2311,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_CCMP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n"); break; case ALG_TKIP: @@ -4002,7 +4002,7 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv) /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl3945_priv *priv) { - /* wait to make sure we flush pedding tasklet*/ + /* wait to make sure we flush pending tasklet*/ synchronize_irq(priv->pci_dev->irq); tasklet_kill(&priv->irq_tasklet); } @@ -5559,7 +5559,7 @@ static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv) iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); - /* Inst bytecount must be last to set up, bit 31 signals uCode + /* Inst byte count must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); @@ -5651,7 +5651,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) rc = iwl3945_grab_nic_access(priv); if (rc) { - IWL_WARNING("Can not read rfkill status from adapter\n"); + IWL_WARNING("Can not read RFKILL status from adapter\n"); return; } @@ -5661,7 +5661,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (rfkill & 0x1) { clear_bit(STATUS_RF_KILL_HW, &priv->status); - /* if rfkill is not on, then wait for thermal + /* if RFKILL is not on, then wait for thermal * sensor in adapter to kick in */ while (iwl3945_hw_get_temperature(priv) == 0) { thermal_spin++; @@ -5855,7 +5855,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) } if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERROR("ucode not available for device bringup\n"); + IWL_ERROR("ucode not available for device bring up\n"); return -EIO; } @@ -6065,7 +6065,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) goto done; } - /* Make sure the scan wasn't cancelled before this queued work + /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; @@ -7728,7 +7728,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); /***************************************************************************** * - * driver setup and teardown + * driver setup and tear down * *****************************************************************************/ @@ -8157,7 +8157,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; - IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state); mutex_lock(&priv->mutex); switch (state) { @@ -8172,7 +8172,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) iwl3945_radio_kill_sw(priv, 1); break; default: - IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + IWL_WARNING("we received unexpected RFKILL state %d\n", state); break; } out_unlock: -- cgit v1.1 From 9fe1c5052019da3d2770abd7b727cbc1083f7937 Mon Sep 17 00:00:00 2001 From: Fabrice Bellet Date: Thu, 23 Oct 2008 23:48:57 -0700 Subject: iwl3945: iwl3945_mac_get_tsf() should not return zero The problem fixed here is that iwl3945_mac_get_tsf() returns 0, as the function is not implemented, and this is considered as a valid value by the mac layer in mlme.c:1605. The consequence is that the STA in ad-hoc mode is inserted/removed quite frequently due to IBSS merging. This patch fixes : http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1781 and https://bugzilla.redhat.com/show_bug.cgi?id=459401 Signed-off-by: Fabrice Bellet Acked-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a4d9247..5436cb4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7155,14 +7155,6 @@ static int iwl3945_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw) -{ - IWL_DEBUG_MAC80211("enter\n"); - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} - static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl3945_priv *priv = hw->priv; @@ -7805,7 +7797,6 @@ static struct ieee80211_ops iwl3945_hw_ops = { .get_stats = iwl3945_mac_get_stats, .get_tx_stats = iwl3945_mac_get_tx_stats, .conf_tx = iwl3945_mac_conf_tx, - .get_tsf = iwl3945_mac_get_tsf, .reset_tsf = iwl3945_mac_reset_tsf, .bss_info_changed = iwl3945_bss_info_changed, .hw_scan = iwl3945_mac_hw_scan -- cgit v1.1 From 7dddaf1a36a372c14ca96a0b5fdfbe2015c43841 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Thu, 23 Oct 2008 23:48:58 -0700 Subject: iwlwifi: Update reclaim flag The reclaim flag should include REPLY_RX_MPDU_CMD in the list of commands issued by uCode. This is for safety in case the SEQ_RX_FRAME bit is set incorrectly. Signed-off-by: Daniel Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7a7caac..82e98b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1391,6 +1391,7 @@ void iwl_rx_handle(struct iwl_priv *priv) reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && (pkt->hdr.cmd != REPLY_RX) && + (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); -- cgit v1.1 From be3d48106c1e5d075784e5e67928a6b5ffc0f3b6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Oct 2008 20:32:21 +0200 Subject: wireless: remove struct regdom hinting The code needs to be split out and cleaned up, so as a first step remove the capability, to add it back in a subsequent patch as a separate function. Also remove the publically facing return value of the function and the wiphy argument. A number of internal functions go from being generic helpers to just being used for alpha2 setting. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 2f0802b..07513e4 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -171,7 +171,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) - regulatory_hint(hw->wiphy, alpha2, NULL); + regulatory_hint(hw->wiphy, alpha2); r = 0; disable_int: -- cgit v1.1 From 4c674c60bd567597f1224973712b352f4f474890 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 26 Oct 2008 20:40:25 +0200 Subject: ath5k: Update interrupt masking code *Properly get/set all available ISR/IMR values and review common/uncommon bits *Better handling of per-txq interrupts (we can now resolve what q is generating each interrupt -this will help in debuging wme later) *Some minor updates from legacy-hal *Properly handle RXNOFRM and TXNOFRM interrupt masking (even when we don't set them on IMR they keep showing up, so we disable them by zeroing AR5K_RXNOFRM and AR5K_TXNOFRM registers). This doesn't exist on legacy-hal but i've tested it on various cards and it works fine. Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 86 ++++++++++++----- drivers/net/wireless/ath5k/base.c | 7 +- drivers/net/wireless/ath5k/dma.c | 190 ++++++++++++++++++++++++++++--------- drivers/net/wireless/ath5k/qcu.c | 37 +++++++- drivers/net/wireless/ath5k/reg.h | 3 +- drivers/net/wireless/ath5k/reset.c | 3 +- 6 files changed, 247 insertions(+), 79 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 53ea439..b117920 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -507,11 +507,15 @@ enum ath5k_tx_queue_id { #define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ #define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ #define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ -#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */ -#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/ -#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */ -#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */ -#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/ +#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */ +#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */ +#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */ +#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */ +#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */ +#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/ +#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */ +#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ +#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ /* * A struct to hold tx queue's parameters @@ -853,7 +857,7 @@ enum ath5k_ant_setting { * checked. We should do this with ath5k_hw_update_mib_counters() but * it seems we should also then do some noise immunity work. * @AR5K_INT_RXPHY: RX PHY Error - * @AR5K_INT_RXKCM: ?? + * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a * beacon that must be handled in software. The alternative is if you * have VEOL support, in that case you let the hardware deal with things. @@ -869,7 +873,7 @@ enum ath5k_ant_setting { * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA * errors. These types of errors we can enable seem to be of type * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. - * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER + * @AR5K_INT_GLOBAL: Used to clear and set the IER * @AR5K_INT_NOCARD: signals the card has been removed * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same * bit value @@ -881,36 +885,61 @@ enum ath5k_ant_setting { * MACs. */ enum ath5k_int { - AR5K_INT_RX = 0x00000001, /* Not common */ + AR5K_INT_RXOK = 0x00000001, AR5K_INT_RXDESC = 0x00000002, + AR5K_INT_RXERR = 0x00000004, AR5K_INT_RXNOFRM = 0x00000008, AR5K_INT_RXEOL = 0x00000010, AR5K_INT_RXORN = 0x00000020, - AR5K_INT_TX = 0x00000040, /* Not common */ + AR5K_INT_TXOK = 0x00000040, AR5K_INT_TXDESC = 0x00000080, + AR5K_INT_TXERR = 0x00000100, + AR5K_INT_TXNOFRM = 0x00000200, + AR5K_INT_TXEOL = 0x00000400, AR5K_INT_TXURN = 0x00000800, AR5K_INT_MIB = 0x00001000, + AR5K_INT_SWI = 0x00002000, AR5K_INT_RXPHY = 0x00004000, AR5K_INT_RXKCM = 0x00008000, AR5K_INT_SWBA = 0x00010000, + AR5K_INT_BRSSI = 0x00020000, AR5K_INT_BMISS = 0x00040000, - AR5K_INT_BNR = 0x00100000, /* Not common */ - AR5K_INT_GPIO = 0x01000000, - AR5K_INT_FATAL = 0x40000000, /* Not common */ - AR5K_INT_GLOBAL = 0x80000000, - - AR5K_INT_COMMON = AR5K_INT_RXNOFRM - | AR5K_INT_RXDESC - | AR5K_INT_RXEOL - | AR5K_INT_RXORN - | AR5K_INT_TXURN - | AR5K_INT_TXDESC - | AR5K_INT_MIB - | AR5K_INT_RXPHY - | AR5K_INT_RXKCM - | AR5K_INT_SWBA - | AR5K_INT_BMISS - | AR5K_INT_GPIO, + AR5K_INT_FATAL = 0x00080000, /* Non common */ + AR5K_INT_BNR = 0x00100000, /* Non common */ + AR5K_INT_TIM = 0x00200000, /* Non common */ + AR5K_INT_DTIM = 0x00400000, /* Non common */ + AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */ + AR5K_INT_GPIO = 0x01000000, + AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ + AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ + AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ + AR5K_INT_QCBRORN = 0x10000000, /* Non common */ + AR5K_INT_QCBRURN = 0x20000000, /* Non common */ + AR5K_INT_QTRIG = 0x40000000, /* Non common */ + AR5K_INT_GLOBAL = 0x80000000, + + AR5K_INT_COMMON = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN + | AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXNOFRM + | AR5K_INT_TXEOL + | AR5K_INT_TXURN + | AR5K_INT_MIB + | AR5K_INT_SWI + | AR5K_INT_RXPHY + | AR5K_INT_RXKCM + | AR5K_INT_SWBA + | AR5K_INT_BRSSI + | AR5K_INT_BMISS + | AR5K_INT_GPIO + | AR5K_INT_GLOBAL, + AR5K_INT_NOCARD = 0xffffffff }; @@ -1081,6 +1110,11 @@ struct ath5k_hw { u32 ah_txq_imr_txurn; u32 ah_txq_imr_txdesc; u32 ah_txq_imr_txeol; + u32 ah_txq_imr_cbrorn; + u32 ah_txq_imr_cbrurn; + u32 ah_txq_imr_qtrig; + u32 ah_txq_imr_nofrm; + u32 ah_txq_isr; u32 *ah_rf_banks; size_t ah_rf_banks_size; struct ath5k_gain ah_gain; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 6caabeb..7ac5f28 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2216,7 +2216,7 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume) */ sc->curchan = sc->hw->conf.channel; sc->curband = &sc->sbands[sc->curchan->band]; - sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | + sc->imask = AR5K_INT_RXOK | AR5K_INT_TXOK | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; ret = ath5k_reset(sc, false, false); @@ -2410,9 +2410,10 @@ ath5k_intr(int irq, void *dev_id) /* bump tx trigger level */ ath5k_hw_update_tx_triglevel(ah, true); } - if (status & AR5K_INT_RX) + if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) tasklet_schedule(&sc->rxtq); - if (status & AR5K_INT_TX) + if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC + | AR5K_INT_TXERR | AR5K_INT_TXEOL)) tasklet_schedule(&sc->txtq); if (status & AR5K_INT_BMISS) { } diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c index 7adceb2..7e2b1a6 100644 --- a/drivers/net/wireless/ath5k/dma.c +++ b/drivers/net/wireless/ath5k/dma.c @@ -472,9 +472,6 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) * * NOTE: We use read-and-clear register, so after this function is called ISR * is zeroed. - * - * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all - * plus it can be misleading (one might thing that we save interrupts this way) */ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) { @@ -494,11 +491,16 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) } } else { /* - * Read interrupt status from the Read-And-Clear - * shadow register. + * Read interrupt status from Interrupt + * Status Register shadow copy (Read And Clear) + * * Note: PISR/SISR Not available on 5210 */ data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } } /* @@ -506,17 +508,9 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) */ *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; - if (unlikely(data == AR5K_INT_NOCARD)) - return -ENODEV; - - if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) - *interrupt_mask |= AR5K_INT_RX; - - if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR - | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) - *interrupt_mask |= AR5K_INT_TX; - if (ah->ah_version != AR5K_AR5210) { + u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); + /*HIU = Host Interface Unit (PCI etc)*/ if (unlikely(data & (AR5K_ISR_HIUERR))) *interrupt_mask |= AR5K_INT_FATAL; @@ -524,24 +518,93 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) /*Beacon Not Ready*/ if (unlikely(data & (AR5K_ISR_BNR))) *interrupt_mask |= AR5K_INT_BNR; - } - /* - * XXX: BMISS interrupts may occur after association. - * I found this on 5210 code but it needs testing. If this is - * true we should disable them before assoc and re-enable them - * after a successfull assoc + some jiffies. - */ -#if 0 - interrupt_mask &= ~AR5K_INT_BMISS; -#endif + if (unlikely(sisr2 & (AR5K_SISR2_SSERR | + AR5K_SISR2_DPERR | + AR5K_SISR2_MCABT))) + *interrupt_mask |= AR5K_INT_FATAL; + + if (data & AR5K_ISR_TIM) + *interrupt_mask |= AR5K_INT_TIM; + + if (data & AR5K_ISR_BCNMISC) { + if (sisr2 & AR5K_SISR2_TIM) + *interrupt_mask |= AR5K_INT_TIM; + if (sisr2 & AR5K_SISR2_DTIM) + *interrupt_mask |= AR5K_INT_DTIM; + if (sisr2 & AR5K_SISR2_DTIM_SYNC) + *interrupt_mask |= AR5K_INT_DTIM_SYNC; + if (sisr2 & AR5K_SISR2_BCN_TIMEOUT) + *interrupt_mask |= AR5K_INT_BCN_TIMEOUT; + if (sisr2 & AR5K_SISR2_CAB_TIMEOUT) + *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; + } + + if (data & AR5K_ISR_RXDOPPLER) + *interrupt_mask |= AR5K_INT_RX_DOPPLER; + if (data & AR5K_ISR_QCBRORN) { + *interrupt_mask |= AR5K_INT_QCBRORN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRORN); + } + if (data & AR5K_ISR_QCBRURN) { + *interrupt_mask |= AR5K_INT_QCBRURN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRURN); + } + if (data & AR5K_ISR_QTRIG) { + *interrupt_mask |= AR5K_INT_QTRIG; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), + AR5K_SISR4_QTRIG); + } + + if (data & AR5K_ISR_TXOK) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXOK); + + if (data & AR5K_ISR_TXDESC) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXDESC); + + if (data & AR5K_ISR_TXERR) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXERR); + + if (data & AR5K_ISR_TXEOL) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXEOL); + + if (data & AR5K_ISR_TXURN) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), + AR5K_SISR2_QCU_TXURN); + } else { + if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT + | AR5K_ISR_HIUERR | AR5K_ISR_DPERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /* + * XXX: BMISS interrupts may occur after association. + * I found this on 5210 code but it needs testing. If this is + * true we should disable them before assoc and re-enable them + * after a successfull assoc + some jiffies. + interrupt_mask &= ~AR5K_INT_BMISS; + */ + } /* * In case we didn't handle anything, * print the register value. */ if (unlikely(*interrupt_mask == 0 && net_ratelimit())) - ATH5K_PRINTF("0x%08x\n", data); + ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr); return 0; } @@ -560,14 +623,17 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) { enum ath5k_int old_mask, int_mask; + old_mask = ah->ah_imr; + /* * Disable card interrupts to prevent any race conditions - * (they will be re-enabled afterwards). + * (they will be re-enabled afterwards if AR5K_INT GLOBAL + * is set again on the new mask). */ - ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - - old_mask = ah->ah_imr; + if (old_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } /* * Add additional, chipset-dependent interrupt mask flags @@ -575,30 +641,64 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) */ int_mask = new_mask & AR5K_INT_COMMON; - if (new_mask & AR5K_INT_RX) - int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | - AR5K_IMR_RXDESC; - - if (new_mask & AR5K_INT_TX) - int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | - AR5K_IMR_TXURN; - if (ah->ah_version != AR5K_AR5210) { + /* Preserve per queue TXURN interrupt mask */ + u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) + & AR5K_SIMR2_QCU_TXURN; + if (new_mask & AR5K_INT_FATAL) { int_mask |= AR5K_IMR_HIUERR; - AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | - AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); + simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR + | AR5K_SIMR2_DPERR); } + + /*Beacon Not Ready*/ + if (new_mask & AR5K_INT_BNR) + int_mask |= AR5K_INT_BNR; + + if (new_mask & AR5K_INT_TIM) + int_mask |= AR5K_IMR_TIM; + + if (new_mask & AR5K_INT_TIM) + simr2 |= AR5K_SISR2_TIM; + if (new_mask & AR5K_INT_DTIM) + simr2 |= AR5K_SISR2_DTIM; + if (new_mask & AR5K_INT_DTIM_SYNC) + simr2 |= AR5K_SISR2_DTIM_SYNC; + if (new_mask & AR5K_INT_BCN_TIMEOUT) + simr2 |= AR5K_SISR2_BCN_TIMEOUT; + if (new_mask & AR5K_INT_CAB_TIMEOUT) + simr2 |= AR5K_SISR2_CAB_TIMEOUT; + + if (new_mask & AR5K_INT_RX_DOPPLER) + int_mask |= AR5K_IMR_RXDOPPLER; + + /* Note: Per queue interrupt masks + * are set via reset_tx_queue (qcu.c) */ + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); + + } else { + if (new_mask & AR5K_INT_FATAL) + int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT + | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); + + ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); } - ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + /* If RXNOFRM interrupt is masked disable it + * by setting AR5K_RXNOFRM to zero */ + if (!(new_mask & AR5K_INT_RXNOFRM)) + ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM); /* Store new interrupt mask */ ah->ah_imr = new_mask; - /* ..re-enable interrupts */ - ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); + /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */ + if (new_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } return old_mask; } diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c index 01bf091..1b7bc50 100644 --- a/drivers/net/wireless/ath5k/qcu.c +++ b/drivers/net/wireless/ath5k/qcu.c @@ -432,13 +432,30 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); /* Update secondary interrupt mask registers */ + + /* Filter out inactive queues */ ah->ah_txq_imr_txok &= ah->ah_txq_status; ah->ah_txq_imr_txerr &= ah->ah_txq_status; ah->ah_txq_imr_txurn &= ah->ah_txq_status; ah->ah_txq_imr_txdesc &= ah->ah_txq_status; ah->ah_txq_imr_txeol &= ah->ah_txq_status; + ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; + ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; + ah->ah_txq_imr_qtrig &= ah->ah_txq_status; + ah->ah_txq_imr_nofrm &= ah->ah_txq_status; ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, AR5K_SIMR0_QCU_TXOK) | @@ -448,8 +465,24 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_SIMR1_QCU_TXERR) | AR5K_REG_SM(ah->ah_txq_imr_txeol, AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, - AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); + /* Update simr2 but don't overwrite rest simr2 settings */ + AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); + AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, + AR5K_REG_SM(ah->ah_txq_imr_txurn, + AR5K_SIMR2_QCU_TXURN)); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, + AR5K_SIMR3_QCBRORN) | + AR5K_REG_SM(ah->ah_txq_imr_cbrurn, + AR5K_SIMR3_QCBRURN), AR5K_SIMR3); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, + AR5K_SIMR4_QTRIG), AR5K_SIMR4); + /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, + AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); + /* No queue has TXNOFRM enabled, disable the interrupt + * by setting AR5K_TXNOFRM to zero */ + if (ah->ah_txq_imr_nofrm == 0) + ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); } return 0; diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index e557fe1..0dae54d 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -234,6 +234,7 @@ #define AR5K_TXNOFRM 0x004c #define AR5K_TXNOFRM_M 0x000003ff #define AR5K_TXNOFRM_QCU 0x000ffc00 +#define AR5K_TXNOFRM_QCU_S 10 /* * Receive frame gap timeout register @@ -350,7 +351,7 @@ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ -#define AR5K_SISR3_QCBORN_S 0 +#define AR5K_SISR3_QCBRORN_S 0 #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ #define AR5K_SISR3_QCBRURN_S 16 diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 1b6d45b..b51bc03 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -864,8 +864,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Pre-enable interrupts on 5211/5212*/ if (ah->ah_version != AR5K_AR5210) - ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX | - AR5K_INT_FATAL); + ath5k_hw_set_imr(ah, ah->ah_imr); /* * Set RF kill flags if supported by the device (read from the EEPROM) -- cgit v1.1 From 0df6cbb7d8a0a8fea69138e9e463671a8ad99f16 Mon Sep 17 00:00:00 2001 From: Andrey Borzenkov Date: Sun, 12 Oct 2008 20:15:43 +0400 Subject: orinoco: reload firmware on resume On resume card state is likely lost so we have to reload firmware again. Signed-off-by: Andrey Borzenkov Acked-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 366556f..7bd1559 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2300,6 +2300,11 @@ int orinoco_reinit_firmware(struct net_device *dev) int err; err = hermes_init(hw); + if (priv->do_fw_download && !err) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + } if (!err) err = orinoco_allocate_fid(dev); @@ -2925,12 +2930,6 @@ static void orinoco_reset(struct work_struct *work) } } - if (priv->do_fw_download) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", -- cgit v1.1 From 4fb30784c720b863203957f76e3fde0d53932746 Mon Sep 17 00:00:00 2001 From: Andrey Borzenkov Date: Sun, 19 Oct 2008 12:06:11 +0400 Subject: orinoco: cache downloadable firmware image in memory for use during resume If card is using downloadable firmware (like Agere 9.x), firmware has to be reloaded during resume. It is not possible to use request_firmware for that, because tasks are still frozen, so request_firmware will just timeout and fail. So cache firmware image in memory for later reuse in ->resume method. Signed-off-by: Andrey Borzenkov Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 28 +++++++++++++++++++++------- drivers/net/wireless/orinoco.h | 5 +++++ 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 7bd1559..5a39166 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -487,12 +487,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, if (err) goto free; - err = request_firmware(&fw_entry, firmware, priv->dev); - if (err) { - printk(KERN_ERR "%s: Cannot find firmware %s\n", - dev->name, firmware); - err = -ENOENT; - goto free; + if (priv->cached_fw) + fw_entry = priv->cached_fw; + else { + err = request_firmware(&fw_entry, firmware, priv->dev); + if (err) { + printk(KERN_ERR "%s: Cannot find firmware %s\n", + dev->name, firmware); + err = -ENOENT; + goto free; + } + priv->cached_fw = fw_entry; } hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -535,7 +540,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, hermes_present(hw)); abort: - release_firmware(fw_entry); + /* In case of error, assume firmware was bogus and release it */ + if (err) { + priv->cached_fw = NULL; + release_firmware(fw_entry); + } free: kfree(pda); @@ -3532,6 +3541,8 @@ struct net_device netif_carrier_off(dev); priv->last_linkstatus = 0xffff; + priv->cached_fw = NULL; + return dev; } @@ -3543,6 +3554,9 @@ void free_orinocodev(struct net_device *dev) * when we call tasklet_kill it will run one final time, * emptying the list */ tasklet_kill(&priv->rx_tasklet); + if (priv->cached_fw) + release_firmware(priv->cached_fw); + priv->cached_fw = NULL; priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 981570b..8c29538 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -66,6 +66,8 @@ struct orinoco_rx_data { struct list_head list; }; +struct firmware; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ struct device *dev; @@ -164,6 +166,9 @@ struct orinoco_private { unsigned int wpa_enabled:1; unsigned int tkip_cm_active:1; unsigned int key_mgmt:3; + + /* Cached in memory firmware to use in ->resume */ + const struct firmware *cached_fw; }; #ifdef ORINOCO_DEBUG -- cgit v1.1 From 9371dd685d212599f0f07e6bf1510c751f70bb37 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sun, 26 Oct 2008 11:24:48 -0400 Subject: ath9k: remove useless conditional ath9k_hw_keyreset returns true in either branch. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 84263c8..1417ba0 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -7193,9 +7193,6 @@ bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) } - if (ah->ah_curchan == NULL) - return true; - return true; } -- cgit v1.1 From 4c2442980043b9585be12b4f59e1bbe7e1f7a801 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Oct 2008 10:17:29 -0700 Subject: ath9k: use ETH_P_PAE It was being discussed where we would put this, but now it found a home so use its define. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 2f27a04..7cfab5a 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -177,8 +177,8 @@ static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl) txctl->min_rate = tx_info_priv->min_rate; } else if (ieee80211_is_data(fc)) { if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(0x888E))) { + /* Port Access Entity (IEEE 802.1X) */ + (skb->protocol == cpu_to_be16(ETH_P_PAE))) { txctl->use_minrate = 1; txctl->min_rate = tx_info_priv->min_rate; } -- cgit v1.1 From babcda74e9d96bb58fd9c6c5112dbdbff169e695 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 3 Nov 2008 21:11:17 -0800 Subject: drivers/net: Kill now superfluous ->last_rx stores. The generic packet receive code takes care of setting netdev->last_rx when necessary, for the sake of the bonding ARP monitor. Drivers need not do it any more. Some cases had to be skipped over because the drivers were making use of the ->last_rx value themselves. Signed-off-by: David S. Miller --- drivers/net/wireless/airo.c | 3 --- drivers/net/wireless/arlan-main.c | 1 - drivers/net/wireless/atmel.c | 2 -- drivers/net/wireless/hostap/hostap_80211_rx.c | 3 --- drivers/net/wireless/netwave_cs.c | 1 - drivers/net/wireless/orinoco.c | 2 -- drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/strip.c | 2 -- drivers/net/wireless/wavelan.c | 1 - drivers/net/wireless/wavelan_cs.c | 1 - drivers/net/wireless/wl3501_cs.c | 1 - drivers/net/wireless/zd1201.c | 2 -- 12 files changed, 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index d7388d2..c8dc656 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3366,7 +3366,6 @@ badrx: skb->protocol = htons(ETH_P_802_2); } else skb->protocol = eth_type_trans(skb,dev); - skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); @@ -3596,7 +3595,6 @@ badmic: skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, ai->dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } badrx: @@ -3690,7 +3688,6 @@ void mpi_receive_802_11 (struct airo_info *ai) skb->pkt_type = PACKET_OTHERHOST; skb->dev = ai->wifidev; skb->protocol = htons(ETH_P_802_2); - skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); badrx: diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index b608643..bfca15d 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1529,7 +1529,6 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 6e20552..d169315 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -919,7 +919,6 @@ static void fast_rx_path(struct atmel_private *priv, else memcpy(&skbp[6], header->addr2, 6); /* source address */ - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -1026,7 +1025,6 @@ static void frag_rx_path(struct atmel_private *priv, memcpy(skb_put(skb, priv->frag_len + 12), priv->rx_buf, priv->frag_len + 12); - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index bbb8ec6..5f64461 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -67,7 +67,6 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, iface = netdev_priv(dev); local = iface->local; - dev->last_rx = jiffies; if (dev->type == ARPHRD_IEEE80211_PRISM) { if (local->monitor_type == PRISM2_MONITOR_PRISM) { @@ -883,8 +882,6 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, from_assoc_ap = 1; } - dev->last_rx = jiffies; - if ((local->iw_mode == IW_MODE_MASTER || local->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index be80c00..24caec6 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -1307,7 +1307,6 @@ static int netwave_rx(struct net_device *dev) /* Queue packet for network layer */ netif_rx(skb); - dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += rcvLen; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 5a39166..b657a91 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1289,7 +1289,6 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_802_2); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += skb->len; @@ -1538,7 +1537,6 @@ static void orinoco_rx(struct net_device *dev, else memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; if (fc & IEEE80211_FCTL_TODS) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index bf0b9299..81b71f0 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2284,7 +2284,6 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; local->stats.rx_packets++; local->stats.rx_bytes += total_len; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 417e9e6..cf0d070 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1997,7 +1997,6 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header * header, #ifdef EXT_COUNTERS strip_info->rx_bytes += packetlen; #endif - skb->dev->last_rx = jiffies; netif_rx(skb); } } @@ -2490,7 +2489,6 @@ static void strip_dev_setup(struct net_device *dev) */ dev->trans_start = 0; - dev->last_rx = 0; dev->tx_queue_len = 30; /* Drop after 30 frames queued */ dev->flags = 0; diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 6fa3d79..1ac37e8 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2528,7 +2528,6 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) netif_rx(skb); /* Keep statistics up to date */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += sksize; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 0a3bacc..de717f8 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -2878,7 +2878,6 @@ wv_packet_read(struct net_device * dev, netif_rx(skb); /* Keep stats up to date */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += sksize; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 8b96f50..c99a1b6 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1013,7 +1013,6 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev, wl3501_receive(this, skb->data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; this->stats.rx_packets++; this->stats.rx_bytes += skb->len; netif_rx(skb); diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index b16ec6e..bf744c1 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -328,7 +328,6 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, 2), &data[datalen-24], 2); memcpy(skb_put(skb, len), data, len); skb->protocol = eth_type_trans(skb, zd->dev); - skb->dev->last_rx = jiffies; zd->stats.rx_packets++; zd->stats.rx_bytes += skb->len; netif_rx(skb); @@ -385,7 +384,6 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, len), data+8, len); } skb->protocol = eth_type_trans(skb, zd->dev); - skb->dev->last_rx = jiffies; zd->stats.rx_packets++; zd->stats.rx_bytes += skb->len; netif_rx(skb); -- cgit v1.1 From 4ceb7b6ae2cf5b6e32c403a11bb54081bf8f8b83 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Fri, 5 Sep 2008 11:28:47 +0800 Subject: netdevice libertas: Fix directly reference of netdev->priv We have some reasons to kill netdev->priv: 1. netdev->priv is equal to netdev_priv(). 2. netdev_priv() wraps the calculation of netdev->priv's offset, obviously netdev_priv() is more flexible than netdev->priv. But we cann't kill netdev->priv, because so many drivers reference to it directly. OK, becasue Dave S. Miller said, "every direct netdev->priv usage is a bug", and I want to kill netdev->priv later, I decided to convert all the direct reference of netdev->priv first. Different to readonly reference of netdev->priv, in this driver, netdev->priv was changed. I use netdev->ml_priv to replace netdev->priv. Signed-off-by: Wang Chen Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e9d23f6..7a1e8b6 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -223,7 +223,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate) static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_access mesh_access; int ret; @@ -242,7 +242,7 @@ static ssize_t lbs_anycast_get(struct device *dev, static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_access mesh_access; uint32_t datum; int ret; @@ -270,7 +270,7 @@ static void lbs_remove_mesh(struct lbs_private *priv); static ssize_t lbs_rtap_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); return snprintf(buf, 5, "0x%X\n", priv->monitormode); } @@ -281,7 +281,7 @@ static ssize_t lbs_rtap_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { int monitor_mode; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); sscanf(buf, "%x", &monitor_mode); if (monitor_mode) { @@ -332,7 +332,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); } @@ -342,7 +342,7 @@ static ssize_t lbs_mesh_get(struct device *dev, static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); int enable; int ret, action = CMD_ACT_MESH_CONFIG_STOP; @@ -393,7 +393,7 @@ static struct attribute_group lbs_mesh_attr_group = { */ static int lbs_dev_open(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv ; + struct lbs_private *priv = netdev_priv(dev) ; int ret = 0; lbs_deb_enter(LBS_DEB_NET); @@ -435,7 +435,7 @@ static int lbs_dev_open(struct net_device *dev) */ static int lbs_mesh_stop(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) (dev->priv); + struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_MESH); spin_lock_irq(&priv->driver_lock); @@ -462,7 +462,7 @@ static int lbs_mesh_stop(struct net_device *dev) */ static int lbs_eth_stop(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_NET); @@ -479,7 +479,7 @@ static int lbs_eth_stop(struct net_device *dev) static void lbs_tx_timeout(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_TX); @@ -531,7 +531,7 @@ EXPORT_SYMBOL_GPL(lbs_host_to_card_done); */ static struct net_device_stats *lbs_get_stats(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_NET); return &priv->stats; @@ -540,7 +540,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev) static int lbs_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct sockaddr *phwaddr = addr; struct cmd_ds_802_11_mac_address cmd; @@ -673,7 +673,7 @@ static void lbs_set_mcast_worker(struct work_struct *work) static void lbs_set_multicast_list(struct net_device *dev) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); schedule_work(&priv->mcast_work); } @@ -689,7 +689,7 @@ static void lbs_set_multicast_list(struct net_device *dev) static int lbs_thread(void *data) { struct net_device *dev = data; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); wait_queue_t wait; lbs_deb_enter(LBS_DEB_THREAD); @@ -1124,7 +1124,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) lbs_pr_err("init ethX device failed\n"); goto done; } - priv = dev->priv; + priv = netdev_priv(dev); if (lbs_init_adapter(priv)) { lbs_pr_err("failed to initialize adapter structure.\n"); @@ -1377,7 +1377,7 @@ static int lbs_add_mesh(struct lbs_private *priv) ret = -ENOMEM; goto done; } - mesh_dev->priv = priv; + mesh_dev->ml_priv = priv; priv->mesh_dev = mesh_dev; mesh_dev->open = lbs_dev_open; @@ -1590,7 +1590,7 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_NET); return &priv->stats; } @@ -1631,7 +1631,7 @@ static int lbs_add_rtap(struct lbs_private *priv) rtap_dev->stop = lbs_rtap_stop; rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; - rtap_dev->priv = priv; + rtap_dev->ml_priv = priv; SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); ret = register_netdev(rtap_dev); -- cgit v1.1 From 9a8675d712d57da0993ad2e43b168c9585892097 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:04:15 +0200 Subject: p54: introduce new names for device firmwares Johannes thought it would have been a good idea to change the firmware names. Note: we still have fallbacks in case our users don't want to "break their running system", but we won't advertise them with MODULE_FIRMWARE. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 5 +++++ drivers/net/wireless/p54/p54pci.c | 9 ++++++--- drivers/net/wireless/p54/p54usb.c | 23 ++++++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index cf04c72..8e5e1ab 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -214,6 +214,11 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + if (priv->fw_var < 0x500) + printk(KERN_INFO "p54: you are using an obsolete firmware. " + "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "and grab one for \"kernel >= 2.6.28\"!\n"); + if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ priv->tx_stats[4].limit = 3; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 3c9d030..c4a868a 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 PCI wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54pci"); +MODULE_FIRMWARE("isl3886pci"); static struct pci_device_id p54p_table[] __devinitdata = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ @@ -72,11 +73,13 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); + err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev); if (err) { printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886)\n", pci_name(priv->pdev)); - return err; + "(isl3886pci)\n", pci_name(priv->pdev)); + err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); + if (err) + return err; } err = p54_parse_firmware(dev, fw_entry); diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 49739c3..21ba526 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 USB wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54usb"); +MODULE_FIRMWARE("isl3886usb"); +MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ @@ -415,10 +417,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) goto err_reset; } - err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); - goto err_req_fw_failed; + printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n"); + err = request_firmware(&fw_entry, "isl3887usb_bare", + &priv->udev->dev); + if (err) + goto err_req_fw_failed; } err = p54_parse_firmware(dev, fw_entry); @@ -553,11 +558,15 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return -ENOMEM; } - err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); - kfree(buf); - return err; + printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n"); + err = request_firmware(&fw_entry, "isl3890usb", + &priv->udev->dev); + if (err) { + kfree(buf); + return err; + } } err = p54_parse_firmware(dev, fw_entry); -- cgit v1.1 From 9e7f3f8e4acdc480584d6b5e6a6be5d1f7bda8fa Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:18:01 +0200 Subject: p54: more definitions form lmac_longbow.h and pda.h This patch ports more useful features to p54 - PDR definitions for the synth chips & regulatory domain. - honour IEEE80211_TX_CTL_ASSIGN_SEQ flag, if it's set. - adds some lost mutex_lock & mutex_unlock. - replace two more "magic values" that sneaked past. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 83 ++++++++++++++++++++++-------------- drivers/net/wireless/p54/p54common.h | 31 +++++++++++++- 2 files changed, 82 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 8e5e1ab..ae8d1f6 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -221,10 +221,10 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[4].limit = 3; - priv->tx_stats[5].limit = 4; - priv->tx_stats[6].limit = 3; - priv->tx_stats[7].limit = 1; + priv->tx_stats[4].limit = 3; /* AC_VO */ + priv->tx_stats[5].limit = 4; /* AC_VI */ + priv->tx_stats[6].limit = 3; /* AC_BE */ + priv->tx_stats[7].limit = 2; /* AC_BK */ dev->queues = 4; } @@ -436,12 +436,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } - priv->rxhw = synth & 0x07; + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == 4) p54_init_xbow_synth(dev); - if (!(synth & 0x40)) + if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - if (!(synth & 0x80)) + if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { @@ -659,7 +659,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && (!payload->status)) info->flags |= IEEE80211_TX_STAT_ACK; - if (payload->status & 0x02) + if (payload->status & P54_TX_PSM_CANCELLED) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.ack_signal = p54_rssi_to_dbm(dev, (int)payload->ack_rssi); @@ -739,9 +739,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) /* returns zero if skb can be reused */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) { - u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; + u16 type = le16_to_cpu(*((__le16 *)skb->data)); - if (type == 0x80) + if (type & P54_HDR_FLAG_CONTROL) return p54_rx_control(dev, skb); else return p54_rx_data(dev, skb); @@ -905,12 +905,13 @@ EXPORT_SYMBOL_GPL(p54_read_eeprom); static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_queue_stats *current_queue; + struct ieee80211_tx_queue_stats *current_queue = NULL; struct p54_common *priv = dev->priv; struct p54_hdr *hdr; struct p54_tx_data *txhdr; size_t padding, len; int i, j, ridx; + u16 hdr_flags = 0; u8 rate; u8 cts_rate = 0x20; u8 rc_flags; @@ -932,9 +933,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) - hdr->flags = cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN); - else - hdr->flags = cpu_to_le16(0); + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; hdr->len = cpu_to_le16(len); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); hdr->rts_tries = info->control.rates[0].count; @@ -1003,6 +1002,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ridx++; } } + + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; + + /* TODO: enable bursting */ + hdr->flags = cpu_to_le16(hdr_flags); hdr->tries = ridx; txhdr->crypt_offset = 0; txhdr->rts_rate_idx = 0; @@ -1021,6 +1026,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) /* modifies skb->cb and with it info, so must be last! */ if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) { skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + if (current_queue) { + current_queue->len--; + current_queue->count--; + } return NETDEV_TX_BUSY; } priv->tx(dev, skb, 0); @@ -1074,13 +1083,14 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) { struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_scan *chan; unsigned int i; void *entry; + __le16 freq = cpu_to_le16(frequency); skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, @@ -1237,6 +1247,7 @@ static int p54_start(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int err; + mutex_lock(&priv->conf_mutex); err = priv->open(dev); if (!err) priv->mode = NL80211_IFTYPE_MONITOR; @@ -1248,6 +1259,7 @@ static int p54_start(struct ieee80211_hw *dev) if (!err) err = p54_init_stats(dev); + mutex_unlock(&priv->conf_mutex); return err; } @@ -1256,6 +1268,7 @@ static void p54_stop(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct sk_buff *skb; + mutex_lock(&priv->conf_mutex); del_timer(&priv->stats_timer); p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; @@ -1265,6 +1278,7 @@ static void p54_stop(struct ieee80211_hw *dev) priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = NL80211_IFTYPE_UNSPECIFIED; + mutex_unlock(&priv->conf_mutex); } static int p54_add_interface(struct ieee80211_hw *dev, @@ -1272,14 +1286,18 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - if (priv->mode != NL80211_IFTYPE_MONITOR) + mutex_lock(&priv->conf_mutex); + if (priv->mode != NL80211_IFTYPE_MONITOR) { + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; + } switch (conf->type) { case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } @@ -1298,6 +1316,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, p54_set_leds(dev, 1, 0, 0); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1305,9 +1324,12 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); + mutex_unlock(&priv->conf_mutex); } static int p54_config(struct ieee80211_hw *dev, u32 changed) @@ -1319,7 +1341,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) mutex_lock(&priv->conf_mutex); priv->rx_antenna = 2; /* automatic */ priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); + ret = p54_set_freq(dev, conf->channel->center_freq); if (!ret) ret = p54_set_edcf(dev); mutex_unlock(&priv->conf_mutex); @@ -1372,14 +1394,18 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; + int ret; + mutex_lock(&priv->conf_mutex); if ((params) && !(queue > 4)) { P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else - return -EINVAL; - - return p54_set_edcf(dev); + ret = -EINVAL; + if (!ret) + ret = p54_set_edcf(dev); + mutex_unlock(&priv->conf_mutex); + return ret; } static int p54_init_xbow_synth(struct ieee80211_hw *dev) @@ -1488,19 +1514,14 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - /* - * XXX: when this driver gets support for any mode that - * requires beacons (AP, MESH, IBSS) then it must - * implement IEEE80211_TX_CTL_ASSIGN_SEQ. - */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ - 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; + priv->tx_stats[0].limit = 1; /* Beacon queue */ + priv->tx_stats[1].limit = 1; /* Probe queue for HW scan */ + priv->tx_stats[2].limit = 3; /* queue for MLMEs */ + priv->tx_stats[3].limit = 3; /* Broadcast / MC queue */ + priv->tx_stats[4].limit = 5; /* Data */ dev->queues = 1; priv->noise = -94; /* diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index b1101fe..8c8793c 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -25,6 +25,22 @@ struct bootrec { u32 data[10]; } __attribute__((packed)); +#define PDR_SYNTH_FRONTEND_MASK 0x0007 +#define PDR_SYNTH_IQ_CAL_MASK 0x0018 +#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 +#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 +#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 +#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 +#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0001 +#define PDR_SYNTH_24_GHZ_MASK 0x0040 +#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 +#define PDR_SYNTH_5_GHZ_MASK 0x0080 +#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 +#define PDR_SYNTH_RX_DIV_MASK 0x0100 +#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 +#define PDR_SYNTH_TX_DIV_MASK 0x0200 +#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 + struct bootrec_exp_if { __le16 role; __le16 if_id; @@ -210,6 +226,19 @@ struct pda_pa_curve_data { #define PDR_BASEBAND_REGISTERS 0x8000 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 +/* PDR definitions for default country & country list */ +#define PDR_COUNTRY_CERT_CODE 0x80 +#define PDR_COUNTRY_CERT_CODE_REAL 0x00 +#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 +#define PDR_COUNTRY_CERT_BAND 0x40 +#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 +#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 +#define PDR_COUNTRY_CERT_IODOOR 0x30 +#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 +#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 +#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 +#define PDR_COUNTRY_CERT_INDEX 0x0F + /* stored in skb->cb */ struct memrecord { u32 start_addr; @@ -507,7 +536,7 @@ struct p54_sta_unlock { } __attribute__ ((packed)); #define P54_TIM_CLEAR BIT(15) -struct p54_tx_control_tim { +struct p54_tim { u8 count; u8 padding[3]; __le16 entry[8]; -- cgit v1.1 From 94585b090baf982a850678a1dc3395bce0c1e302 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:18:44 +0200 Subject: p54: put broadcast frames into the right queues stlc45xx's specs finally brought some light what all the 4 extra queues for. now CAB data and managment frames have their own queue. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 82 +++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index ae8d1f6..e93bca8 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -902,6 +902,55 @@ free: } EXPORT_SYMBOL_GPL(p54_read_eeprom); +static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, + u16 *flags, u16 *aid) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct p54_common *priv = dev->priv; + int ret = 0; + + if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { + if (ieee80211_is_beacon(hdr->frame_control)) { + *aid = 0; + *queue = 0; + *extra_len = IEEE80211_MAX_TIM_LEN; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP; + return 0; + } else if (ieee80211_is_probe_resp(hdr->frame_control)) { + *aid = 0; + *queue = 2; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP | + P54_HDR_FLAG_DATA_OUT_NOCANCEL; + return 0; + } else { + *queue = 2; + ret = 0; + } + } else { + *queue += 4; + ret = 1; + } + + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + *aid = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + *aid = 0; + *queue = 3; + return 0; + } + if (info->control.sta) + *aid = info->control.sta->aid; + else + *flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL; + } + return ret; +} + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -909,22 +958,26 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_common *priv = dev->priv; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - size_t padding, len; + size_t padding, len, tim_len; int i, j, ridx; - u16 hdr_flags = 0; - u8 rate; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue; u8 cts_rate = 0x20; u8 rc_flags; u8 calculated_tries[4]; u8 nrates = 0, nremaining = 8; - 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++; - current_queue->count++; - if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); + queue = skb_get_queue_mapping(skb); + + if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) { + current_queue = &priv->tx_stats[queue]; + if (unlikely(current_queue->len > current_queue->limit)) + return NETDEV_TX_BUSY; + current_queue->len++; + current_queue->count++; + if (current_queue->len == current_queue->limit) + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); + } padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -935,7 +988,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (padding) hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; hdr->len = cpu_to_le16(len); - hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->type = cpu_to_le16(aid); hdr->rts_tries = info->control.rates[0].count; /* @@ -1013,7 +1066,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->rts_rate_idx = 0; txhdr->key_type = 0; txhdr->key_len = 0; - txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->hw_queue = queue; txhdr->backlog = 32; memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? @@ -1024,7 +1077,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->align[0] = padding; /* modifies skb->cb and with it info, so must be last! */ - if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) { + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) { skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); if (current_queue) { current_queue->len--; @@ -1509,8 +1562,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = NL80211_IFTYPE_UNSPECIFIED; skb_queue_head_init(&priv->tx_queue); - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS | + dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; -- cgit v1.1 From e5ea92a7528d304e8e327d0d261653e98b163e8a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 18 Oct 2008 23:19:00 +0200 Subject: p54: AP & Ad-hoc testing This patch finally adds all necessary code to test Ad-hoc & AP mode with p54. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 245 ++++++++++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index eb69b90..b585ff6 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -108,6 +108,7 @@ struct p54_common { struct timer_list stats_timer; struct completion stats_comp; struct sk_buff *cached_stats; + struct sk_buff *cached_beacon; int noise; void *eeprom; struct completion eeprom_comp; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index e93bca8..8423c43 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -626,6 +626,12 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + if (unlikely(entry == priv->cached_beacon)) { + kfree_skb(entry); + priv->cached_beacon = NULL; + goto out; + } + /* * Clear manually, ieee80211_tx_info_clear_status would * clear the counts too and we need them. @@ -711,6 +717,35 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) mod_timer(&priv->stats_timer, jiffies + 5 * HZ); } +static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_trap *trap = (struct p54_trap *) hdr->data; + u16 event = le16_to_cpu(trap->event); + u16 freq = le16_to_cpu(trap->frequency); + + switch (event) { + case P54_TRAP_BEACON_TX: + break; + case P54_TRAP_RADAR: + printk(KERN_INFO "%s: radar (freq:%d MHz)\n", + wiphy_name(dev->wiphy), freq); + break; + case P54_TRAP_NO_BEACON: + break; + case P54_TRAP_SCAN: + break; + case P54_TRAP_TBTT: + break; + case P54_TRAP_TIMER: + break; + default: + printk(KERN_INFO "%s: received event:%x freq:%d\n", + wiphy_name(dev->wiphy), event, freq); + break; + } +} + static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_hdr *hdr = (struct p54_hdr *) skb->data; @@ -719,6 +754,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) case P54_CONTROL_TYPE_TXDONE: p54_rx_frame_sent(dev, skb); break; + case P54_CONTROL_TYPE_TRAP: + p54_rx_trap(dev, skb); + break; case P54_CONTROL_TYPE_BBP: break; case P54_CONTROL_TYPE_STAT_READBACK: @@ -902,6 +940,64 @@ free: } EXPORT_SYMBOL_GPL(p54_read_eeprom); +static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, + bool set) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_tim *tim; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*tim), + P54_CONTROL_TYPE_TIM, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim->count = 1; + tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); + priv->tx(dev, skb, 1); + return 0; +} + +static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_sta_unlock *sta; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*sta), + P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + memcpy(sta->addr, addr, ETH_ALEN); + priv->tx(dev, skb, 1); + return 0; +} + +static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_hdr *hdr; + struct p54_txcancel *cancel; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*cancel), + P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (void *)entry->data; + cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel->req_id = hdr->req_id; + priv->tx(dev, skb, 1); + return 0; +} + static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, u16 *flags, u16 *aid) @@ -982,6 +1078,17 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) { + if (info->control.sta) + if (p54_sta_unlock(dev, info->control.sta->addr)) { + if (current_queue) { + current_queue->len--; + current_queue->count--; + } + return NETDEV_TX_BUSY; + } + } + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); @@ -1295,6 +1402,88 @@ static int p54_init_stats(struct ieee80211_hw *dev) return 0; } +static int p54_beacon_tim(struct sk_buff *skb) +{ + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ + + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; + + if (skb->len <= sizeof(mgmt)) { + printk(KERN_ERR "p54: beacon is too short!\n"); + return -EINVAL; + } + + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) { + printk(KERN_ERR "p54: parsing beacon failed\n"); + return -EINVAL; + } + + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; + + if (dtim_len < 3) { + printk(KERN_ERR "p54: invalid dtim len!\n"); + return -EINVAL; + } + memmove(pos, next, end - next); + + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); + + pos = end - (dtim_len + 2); + + /* add the dummy at the end */ + pos[0] = WLAN_EID_TIM; + pos[1] = 3; + pos[2] = 0; + pos[3] = dtim_period; + pos[4] = 0; + return 0; + } + pos += 2 + pos[1]; + } + return 0; +} + +static int p54_beacon_update(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *beacon; + int ret; + + if (priv->cached_beacon) { + p54_tx_cancel(dev, priv->cached_beacon); + /* wait for the last beacon the be freed */ + msleep(10); + } + + beacon = ieee80211_beacon_get(dev, vif); + if (!beacon) + return -ENOMEM; + ret = p54_beacon_tim(beacon); + if (ret) + return ret; + ret = p54_tx(dev, beacon); + if (ret) + return ret; + priv->cached_beacon = beacon; + priv->tsf_high32 = 0; + priv->tsf_low32 = 0; + + return 0; +} + static int p54_start(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; @@ -1325,9 +1514,14 @@ static void p54_stop(struct ieee80211_hw *dev) del_timer(&priv->stats_timer); p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); + while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); + kfree(priv->cached_beacon); + priv->cached_beacon = NULL; priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -1347,6 +1541,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, switch (conf->type) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: priv->mode = conf->type; break; default: @@ -1362,6 +1558,12 @@ static int p54_add_interface(struct ieee80211_hw *dev, case NL80211_IFTYPE_STATION: p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); break; + case NL80211_IFTYPE_AP: + p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr); + break; + case NL80211_IFTYPE_ADHOC: + p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); + break; default: BUG(); /* impossible */ break; @@ -1379,6 +1581,8 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); @@ -1406,13 +1610,41 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct ieee80211_if_conf *conf) { struct p54_common *priv = dev->priv; + int ret = 0; mutex_lock(&priv->conf_mutex); - p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); - p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); - memcpy(priv->bssid, conf->bssid, ETH_ALEN); + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); + if (ret) + goto out; + ret = p54_set_leds(dev, 1, + !is_multicast_ether_addr(conf->bssid), 0); + if (ret) + goto out; + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_set_freq(dev, dev->conf.channel->center_freq); + if (ret) + goto out; + ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid); + if (ret) + goto out; + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + ret = p54_set_edcf(dev); + if (ret) + goto out; + } + } +out: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } static void p54_configure_filter(struct ieee80211_hw *dev, @@ -1541,6 +1773,7 @@ static const struct ieee80211_ops p54_ops = { .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, .config = p54_config, .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, @@ -1566,7 +1799,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION | + NL80211_IFTYPE_ADHOC | + NL80211_IFTYPE_AP); dev->channel_change_time = 1000; /* TODO: find actual value */ priv->tx_stats[0].limit = 1; /* Beacon queue */ -- cgit v1.1 From db4186cf15a5a7e8e8526f7c158f042ccc3ed576 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 31 Oct 2008 15:53:12 -0400 Subject: p54: eliminate warning for uninitialized variable 'tim_len' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/p54/p54common.c: In function ‘p54_tx’: drivers/net/wireless/p54/p54common.c:1058: warning: ‘tim_len’ may be used uninitialized in this function Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 8423c43..a2e2150 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1054,7 +1054,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_common *priv = dev->priv; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - size_t padding, len, tim_len; + size_t padding, len, tim_len = 0; int i, j, ridx; u16 hdr_flags = 0, aid = 0; u8 rate, queue; -- cgit v1.1 From e5704bf0ba4bb2ca54a1c74f6a6dca53dfccc33d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 16:59:57 +0100 Subject: ath9k: remove useless NULL initialisers When I added .set_frag_threshold I didn't realise it was already there which now generated a sparse warning. Therefore, remove the .set_frag_threshold NULL initialiser, and while at it all the other useless ones. Signed-off-by: Johannes Berg Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f6dc4c8..b25c8f9 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1648,20 +1648,12 @@ static struct ieee80211_ops ath9k_ops = { .config = ath9k_config, .config_interface = ath9k_config_interface, .configure_filter = ath9k_configure_filter, - .get_stats = NULL, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, - .get_tx_stats = NULL, .bss_info_changed = ath9k_bss_info_changed, - .set_tim = NULL, .set_key = ath9k_set_key, - .hw_scan = NULL, - .get_tkip_seq = NULL, - .set_rts_threshold = NULL, - .set_frag_threshold = NULL, .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, - .tx_last_beacon = NULL, .ampdu_action = ath9k_ampdu_action, .set_frag_threshold = ath9k_no_fragmentation, }; -- cgit v1.1 From 430cfe95a401baa0dc2022deaad02cb75d63c73c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 18:06:02 +0100 Subject: iwl3945: remove dead code Was wondering about this code since supposedly the firmware will add the SSID element. Turns out it's dead, so remove it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f675b29..431bebe 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1593,7 +1593,7 @@ static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate, */ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, struct ieee80211_mgmt *frame, - int left, int is_direct) + int left) { int len = 0; u8 *pos = NULL; @@ -1623,20 +1623,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, *pos++ = WLAN_EID_SSID; *pos++ = 0; - /* fill in our direct SSID IE... */ - if (is_direct) { - /* ...next IE... */ - left -= 2 + priv->essid_len; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_SSID; - *pos++ = priv->essid_len; - memcpy(pos, priv->essid, priv->essid_len); - pos += priv->essid_len; - len += 2 + priv->essid_len; - } - /* fill in supported rate */ /* ...next IE... */ left -= 2; @@ -6177,7 +6163,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) * that based on the direct_mask added to each channel entry */ scan->tx_cmd.len = cpu_to_le16( iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan), 0)); + IWL_MAX_SCAN_SIZE - sizeof(*scan))); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; -- cgit v1.1 From a57a59f247b651e8ed6d3eeb7e2f9d83b83134c9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 18:21:05 +0100 Subject: iwlwifi: remove implicit direct scan When an undirected scan is requested and iwlwifi is not associated but the user has set an SSID (and maybe was associated with that network at some point) then iwlwifi will assume the user wanted to scan for this SSID which seems wrong. Remove this code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 7 ------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 -------- 2 files changed, 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 6c5654f..c4b9030 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -743,13 +743,6 @@ static void iwl_bg_request_scan(struct work_struct *data) memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; - } else if (!iwl_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", - print_ssid(ssid, priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - n_probes++; } else { IWL_DEBUG_SCAN("Start indirect scan.\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 431bebe..bf37294 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6148,14 +6148,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data) memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; - } else if (!iwl3945_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN - ("Kicking off one direct scan for '%s' when not associated\n", - print_ssid(ssid, priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - n_probes++; } else IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); -- cgit v1.1 From 4607816f608b42a5379aca97ceed08378804c99f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 18:25:43 +0100 Subject: iwlwifi: remove unused essid variable Now the essid stuff is unused, so remove it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 -- drivers/net/wireless/iwlwifi/iwl-agn.c | 12 ------------ drivers/net/wireless/iwlwifi/iwl-dev.h | 2 -- drivers/net/wireless/iwlwifi/iwl3945-base.c | 12 ------------ 4 files changed, 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 592c595..7187925 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -828,8 +828,6 @@ struct iwl3945_priv { unsigned long last_statistics_time; /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; u16 rates_mask; u32 power_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2c35a01..ce3141f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2937,7 +2937,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; - unsigned long flags; int rc; if (conf == NULL) @@ -3031,15 +3030,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, } done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); @@ -3082,8 +3072,6 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b58fcde..358ea74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -926,8 +926,6 @@ struct iwl_priv { unsigned long last_statistics_time; /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; u16 rates_mask; u32 power_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bf37294..0c2d778 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6720,7 +6720,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct iwl3945_priv *priv = hw->priv; - unsigned long flags; int rc; if (conf == NULL) @@ -6817,15 +6816,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, } done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); @@ -6868,8 +6858,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); -- cgit v1.1 From 71c11fb57b924c160297ccd9e1761db598d00ac2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 18:29:48 +0100 Subject: b43/legacy: remove SSID code The SSID programmed into the device is used by the ucode only to reply to probe requests, a functionality we disable anyway because it doesn't fit with the mac80211/hostapd programming model. Therefore, it isn't useful to program the SSID into device. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 21 --------------------- drivers/net/wireless/b43legacy/main.c | 24 ------------------------ 2 files changed, 45 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2a599fb..9d1768d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1674,25 +1674,6 @@ static void b43_update_templates(struct b43_wl *wl) queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); } -static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) -{ - u32 tmp; - u16 i, len; - - len = min((u16) ssid_len, (u16) 0x100); - for (i = 0; i < len; i += sizeof(u32)) { - tmp = (u32) (ssid[i + 0]); - if (i + 1 < len) - tmp |= (u32) (ssid[i + 1]) << 8; - if (i + 2 < len) - tmp |= (u32) (ssid[i + 2]) << 16; - if (i + 3 < len) - tmp |= (u32) (ssid[i + 3]) << 24; - b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp); - } - b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len); -} - static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) { b43_time_lock(dev); @@ -3602,8 +3583,6 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, if (b43_is_mode(wl, NL80211_IFTYPE_AP) || b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) { B43_WARN_ON(vif->type != wl->if_type); - if (conf->changed & IEEE80211_IFCC_SSID) - b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43_update_templates(wl); } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 9edbdf9..6c8eb4d 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1160,29 +1160,6 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->beacon1_uploaded = 0; } -static void b43legacy_set_ssid(struct b43legacy_wldev *dev, - const u8 *ssid, u8 ssid_len) -{ - u32 tmp; - u16 i; - u16 len; - - len = min((u16)ssid_len, (u16)0x100); - for (i = 0; i < len; i += sizeof(u32)) { - tmp = (u32)(ssid[i + 0]); - if (i + 1 < len) - tmp |= (u32)(ssid[i + 1]) << 8; - if (i + 2 < len) - tmp |= (u32)(ssid[i + 2]) << 16; - if (i + 3 < len) - tmp |= (u32)(ssid[i + 3]) << 24; - b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, - 0x380 + i, tmp); - } - b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, - 0x48, len); -} - static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, u16 beacon_int) { @@ -2744,7 +2721,6 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); - b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43legacy_update_templates(wl); } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { -- cgit v1.1 From b23f99bcfa12c7b452f7ad201ea5921534d4e9ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 18:50:12 +0100 Subject: adm8211: remove SSID code Since adm8211 currently doesn't implement IBSS mode anyway, it can't be using the SSID. And if/when it does implement IBSS mode, we'll have to see how to make it beacon anyway. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 23 ----------------------- drivers/net/wireless/adm8211.h | 2 -- 2 files changed, 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index b96ebfe..fc0897f 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1297,22 +1297,6 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) ADM8211_CSR_WRITE(ABDA1, reg); } -static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) -{ - struct adm8211_priv *priv = dev->priv; - u8 buf[36]; - - if (ssid_len > 32) - return -EINVAL; - - memset(buf, 0, sizeof(buf)); - buf[0] = ssid_len; - memcpy(buf + 1, ssid, ssid_len); - adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33); - /* TODO: configure beacon for adhoc? */ - return 0; -} - static int adm8211_config(struct ieee80211_hw *dev, u32 changed) { struct adm8211_priv *priv = dev->priv; @@ -1338,13 +1322,6 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, memcpy(priv->bssid, conf->bssid, ETH_ALEN); } - if (conf->ssid_len != priv->ssid_len || - memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { - adm8211_set_ssid(dev, conf->ssid, conf->ssid_len); - priv->ssid_len = conf->ssid_len; - memcpy(priv->ssid, conf->ssid, conf->ssid_len); - } - return 0; } diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 9b190ee..4f6ab13 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -553,8 +553,6 @@ struct adm8211_priv { int channel; u8 bssid[ETH_ALEN]; - u8 ssid[32]; - size_t ssid_len; u8 soft_rx_crc; u8 retry_limit; -- cgit v1.1 From 41bb73eeac5ff5fb217257ba33b654747b3abf11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Oct 2008 01:09:37 +0100 Subject: mac80211: remove SSID driver code Remove the SSID from the driver API since now there is no driver that requires knowing the SSID and I think it's unlikely that any hardware design that does require the SSID will play well with mac80211. This also removes support for setting the SSID in master mode which will require a patch to hostapd to not try. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 7 ------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ------- 2 files changed, 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ce3141f..ad186e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2957,13 +2957,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return rc; } - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - if (!iwl_is_alive(priv)) return -EAGAIN; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0c2d778..47881be 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6743,13 +6743,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, /* XXX: this MUST use conf->mac_addr */ - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - if (!iwl3945_is_alive(priv)) return -EAGAIN; -- cgit v1.1 From 9b1fbae4b242cf86a878771eb59dc600dde72ec8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Oct 2008 01:02:27 +0100 Subject: iwl3945: remove bogus comment I added this comment myself, but it's clearly wrong. I had meant to place it in iwl_mac_add_interface, which at the time didn't honour the MAC address setting, but it does now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 47881be..9a4ffab 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6741,8 +6741,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, return rc; } - /* XXX: this MUST use conf->mac_addr */ - if (!iwl3945_is_alive(priv)) return -EAGAIN; -- cgit v1.1 From 2c706002fc147decdba2658ea48e4436faca3af2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Oct 2008 22:09:54 +0100 Subject: don't use net/ieee80211.h Convert all the drivers using net/ieee80211.h to use linux/ieee80211.h. Contains a bugfix in libertas where the SSID parsing could overrun the buffer when the AP sends invalid information. Signed-off-by: Johannes Berg Acked-by: Dan Williams [airo, libertas] Acked-by: Pavel Roskin [orinoco] Acked-by: David Kilroy [orinoco] Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 50 ++++++++++--------- drivers/net/wireless/atmel.c | 70 +++++++++++++-------------- drivers/net/wireless/libertas/assoc.c | 18 +++---- drivers/net/wireless/libertas/cmd.c | 5 +- drivers/net/wireless/libertas/dev.h | 7 ++- drivers/net/wireless/libertas/main.c | 3 +- drivers/net/wireless/libertas/persistcfg.c | 2 +- drivers/net/wireless/libertas/scan.c | 77 +++++++++++++++--------------- drivers/net/wireless/libertas/scan.h | 4 ++ drivers/net/wireless/libertas/types.h | 5 +- drivers/net/wireless/libertas/wext.c | 1 - drivers/net/wireless/orinoco.c | 30 ++++++------ drivers/net/wireless/rndis_wlan.c | 24 +++++----- drivers/net/wireless/wl3501.h | 4 +- drivers/net/wireless/zd1201.c | 4 +- 15 files changed, 156 insertions(+), 148 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c8dc656..67d504e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -47,10 +47,11 @@ #include #include #include -#include #include #include +#include + #include "airo.h" #define DRV_NAME "airo" @@ -7265,56 +7266,53 @@ static inline char *airo_translate_scan(struct net_device *dev, if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) { unsigned int num_null_ies = 0; u16 length = sizeof (bss->extra.iep); - struct ieee80211_info_element *info_element = - (struct ieee80211_info_element *) &bss->extra.iep; + u8 *ie = (void *)&bss->extra.iep; - while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) { - if (sizeof(*info_element) + info_element->len > length) { + while ((length >= 2) && (num_null_ies < 2)) { + if (2 + ie[1] > length) { /* Invalid element, don't continue parsing IE */ break; } - switch (info_element->id) { - case MFIE_TYPE_SSID: + switch (ie[0]) { + case WLAN_EID_SSID: /* Two zero-length SSID elements * mean we're done parsing elements */ - if (!info_element->len) + if (!ie[1]) num_null_ies++; break; - case MFIE_TYPE_GENERIC: - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x01) { + case WLAN_EID_GENERIC: + if (ie[1] >= 4 && + ie[2] == 0x00 && + ie[3] == 0x50 && + ie[4] == 0xf2 && + ie[5] == 0x01) { iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(info_element->len + 2, - MAX_WPA_IE_LEN); + /* 64 is an arbitrary cut-off */ + iwe.u.data.length = min(ie[1] + 2, + 64); current_ev = iwe_stream_add_point( info, current_ev, - end_buf, &iwe, - (char *) info_element); + end_buf, &iwe, ie); } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(info_element->len + 2, - MAX_WPA_IE_LEN); + /* 64 is an arbitrary cut-off */ + iwe.u.data.length = min(ie[1] + 2, 64); current_ev = iwe_stream_add_point( info, current_ev, end_buf, - &iwe, (char *) info_element); + &iwe, ie); break; default: break; } - length -= sizeof(*info_element) + info_element->len; - info_element = - (struct ieee80211_info_element *)&info_element-> - data[info_element->len]; + length -= 2 + ie[1]; + ie += 2 + ie[1]; } } return current_ev; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index d169315..3962b55 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -67,7 +67,7 @@ #include #include #include -#include +#include #include "atmel.h" #define DRIVER_MAJOR 0 @@ -569,7 +569,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); static void atmel_command_irq(struct atmel_private *priv); static int atmel_validate_channel(struct atmel_private *priv, int channel); static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 frame_len, u8 rssi); static void atmel_management_timer(u_long a); static void atmel_send_command(struct atmel_private *priv, int command, @@ -577,7 +577,7 @@ static void atmel_send_command(struct atmel_private *priv, int command, static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u8 *body, int body_len); static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); @@ -785,7 +785,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; @@ -823,7 +823,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) frame_ctl = IEEE80211_FTYPE_DATA; header.duration_id = 0; - header.seq_ctl = 0; + header.seq_ctrl = 0; if (priv->wep_is_on) frame_ctl |= IEEE80211_FCTL_PROTECTED; if (priv->operating_mode == IW_MODE_ADHOC) { @@ -840,7 +840,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) if (priv->use_wpa) memcpy(&header.addr4, SNAP_RFC1024, 6); - header.frame_ctl = cpu_to_le16(frame_ctl); + header.frame_control = cpu_to_le16(frame_ctl); /* Copy the wireless header into the card */ atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); /* Copy the packet sans its 802.3 header addresses which have been replaced */ @@ -860,7 +860,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u8 *body, int body_len) { u16 buff; @@ -876,7 +876,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, } static void fast_rx_path(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc) { /* fast path: unfragmented packet copy directly into skbuf */ @@ -914,7 +914,7 @@ static void fast_rx_path(struct atmel_private *priv, } memcpy(skbp, header->addr1, 6); /* destination address */ - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) memcpy(&skbp[6], header->addr3, 6); else memcpy(&skbp[6], header->addr2, 6); /* source address */ @@ -949,7 +949,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) } static void frag_rx_path(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) { @@ -957,7 +957,7 @@ static void frag_rx_path(struct atmel_private *priv, u8 source[6]; struct sk_buff *skb; - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) memcpy(source, header->addr3, 6); else memcpy(source, header->addr2, 6); @@ -1039,7 +1039,7 @@ static void frag_rx_path(struct atmel_private *priv, static void rx_done_irq(struct atmel_private *priv) { int i; - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && @@ -1066,10 +1066,10 @@ static void rx_done_irq(struct atmel_private *priv) goto next; } - /* Get header as far as end of seq_ctl */ + /* Get header as far as end of seq_ctrl */ atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); - frame_ctl = le16_to_cpu(header.frame_ctl); - seq_control = le16_to_cpu(header.seq_ctl); + frame_ctl = le16_to_cpu(header.frame_control); + seq_control = le16_to_cpu(header.seq_ctrl); /* probe for CRC use here if needed once five packets have arrived with the same crc status, we assume we know what's @@ -1819,7 +1819,7 @@ static int atmel_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > 4) return -EINVAL; idx--; } else @@ -1882,7 +1882,7 @@ static int atmel_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > 4) return -EINVAL; idx--; } else @@ -2797,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) { int rejoin = 0; - int new = capability & MFIE_TYPE_POWER_CONSTRAINT ? + int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? SHORT_PREAMBLE : LONG_PREAMBLE; if (priv->preamble != new) { @@ -2826,19 +2826,19 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len) { - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; struct auth_body auth; - header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); + header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); header.duration_id = cpu_to_le16(0x8000); - header.seq_ctl = 0; + header.seq_ctrl = 0; memcpy(header.addr1, priv->CurrentBSSID, 6); memcpy(header.addr2, priv->dev->dev_addr, 6); memcpy(header.addr3, priv->CurrentBSSID, 6); if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) /* no WEP for authentication frames with TrSeqNo 1 */ - header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); auth.alg = cpu_to_le16(system); @@ -2861,7 +2861,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) { u8 *ssid_el_p; int bodysize; - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; struct ass_req_format { __le16 capability; __le16 listen_interval; @@ -2874,10 +2874,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) u8 rates[4]; } body; - header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | + header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); header.duration_id = cpu_to_le16(0x8000); - header.seq_ctl = 0; + header.seq_ctrl = 0; memcpy(header.addr1, priv->CurrentBSSID, 6); memcpy(header.addr2, priv->dev->dev_addr, 6); @@ -2887,7 +2887,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) if (priv->wep_is_on) body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT); + body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); @@ -2901,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) bodysize = 12 + priv->SSID_size; } - ssid_el_p[0] = MFIE_TYPE_SSID; + ssid_el_p[0] = WLAN_EID_SSID; ssid_el_p[1] = priv->SSID_size; memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES; + ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); @@ -2912,9 +2912,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) } static int is_frame_from_current_bss(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header) + struct ieee80211_hdr *header) { - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; else return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; @@ -2962,7 +2962,7 @@ static int retrieve_bss(struct atmel_private *priv) } static void store_bss_info(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, u16 capability, + struct ieee80211_hdr *header, u16 capability, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { @@ -3001,7 +3001,7 @@ static void store_bss_info(struct atmel_private *priv, else if (capability & WLAN_CAPABILITY_ESS) priv->BSSinfo[index].BSStype =IW_MODE_INFRA; - priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ? + priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? SHORT_PREAMBLE : LONG_PREAMBLE; } @@ -3037,7 +3037,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len) } } else if (system == WLAN_AUTH_SHARED_KEY) { if (trans_seq_no == 0x0002 && - auth->el_id == MFIE_TYPE_CHALLENGE) { + auth->el_id == WLAN_EID_CHALLENGE) { send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); return; } else if (trans_seq_no == 0x0004) { @@ -3288,12 +3288,12 @@ static void atmel_smooth_qual(struct atmel_private *priv) /* deals with incoming managment frames. */ static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 frame_len, u8 rssi) { u16 subtype; - subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE; + subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; switch (subtype) { case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_PROBE_RESP: diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 9286378..a0e440c 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include "assoc.h" @@ -341,12 +343,12 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; 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.elementid = WLAN_EID_IBSS_PARAMS; cmd.ssparamset.ibssparamset.len = 2; cmd.ssparamset.ibssparamset.atimwindow = 0; @@ -430,8 +432,8 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, { if (!secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC - && match_bss->rsn_ie[0] != MFIE_TYPE_RSN + && match_bss->wpa_ie[0] != WLAN_EID_GENERIC + && match_bss->rsn_ie[0] != WLAN_EID_RSN && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else @@ -453,7 +455,7 @@ static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { if (!secinfo->wep_enabled && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) + && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -466,7 +468,7 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { if (!secinfo->wep_enabled && secinfo->WPA2enabled && - (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) + (match_bss->rsn_ie[0] == WLAN_EID_RSN) /* privacy bit may NOT be set in some APs like LinkSys WRT54G (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -480,8 +482,8 @@ static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, { if (!secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) - && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) + && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) + && (match_bss->rsn_ie[0] != WLAN_EID_RSN) && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 38843c8..957fd5a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -5,7 +5,6 @@ #include #include -#include #include #include "host.h" #include "hostcmd.h" @@ -1071,7 +1070,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) switch (action) { case CMD_ACT_MESH_CONFIG_START: - ie->hdr.id = MFIE_TYPE_GENERIC; + ie->id = WLAN_EID_GENERIC; ie->val.oui[0] = 0x00; ie->val.oui[1] = 0x50; ie->val.oui[2] = 0x43; @@ -1083,7 +1082,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; ie->val.mesh_id_len = priv->mesh_ssid_len; memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); - ie->hdr.len = sizeof(struct mrvl_meshie_val) - + ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f6f3753..dd682c4 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -10,7 +10,6 @@ #include #include #include -#include #include "defs.h" #include "hostcmd.h" @@ -278,6 +277,12 @@ struct lbs_private { struct enc_key wpa_mcast_key; struct enc_key wpa_unicast_key; +/* + * In theory, the IE is limited to the IE length, 255, + * but in practice 64 bytes are enough. + */ +#define MAX_WPA_IE_LEN 64 + /** WPA Information Elements*/ u8 wpa_ie[MAX_WPA_IE_LEN]; u8 wpa_ie_len; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 7a1e8b6..241af7f 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -12,9 +12,8 @@ #include #include #include - +#include #include -#include #include "host.h" #include "decl.h" diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 3309a9c..56e2401 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, /* SSID len */ ie->val.mesh_id_len = len; /* IE len */ - ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 5c34ac5..93f7476 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -6,8 +6,8 @@ */ #include #include +#include #include - #include #include "host.h" @@ -55,6 +55,8 @@ //! Scan time specified in the channel TLV for each channel for active scans #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) + static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, struct cmd_header *resp); @@ -591,38 +593,36 @@ static int lbs_process_bss(struct bss_descriptor *bss, /* process variable IE */ while (pos <= end - 2) { - struct ieee80211_info_element * elem = (void *)pos; - - if (pos + elem->len > end) { + if (pos + pos[1] > end) { lbs_deb_scan("process_bss: error in processing IE, " "bytes left < IE length\n"); break; } - switch (elem->id) { - case MFIE_TYPE_SSID: - bss->ssid_len = min_t(int, 32, elem->len); - memcpy(bss->ssid, elem->data, bss->ssid_len); + switch (pos[0]) { + case WLAN_EID_SSID: + bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]); + memcpy(bss->ssid, pos + 2, bss->ssid_len); lbs_deb_scan("got SSID IE: '%s', len %u\n", print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); break; - case MFIE_TYPE_RATES: - n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len); - memcpy(bss->rates, elem->data, n_basic_rates); + case WLAN_EID_SUPP_RATES: + n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]); + memcpy(bss->rates, pos + 2, n_basic_rates); got_basic_rates = 1; lbs_deb_scan("got RATES IE\n"); break; - case MFIE_TYPE_FH_SET: + case WLAN_EID_FH_PARAMS: pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset)); lbs_deb_scan("got FH IE\n"); break; - case MFIE_TYPE_DS_SET: + case WLAN_EID_DS_PARAMS: pDS = (struct ieeetypes_dsparamset *) pos; bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, @@ -630,14 +630,14 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; - case MFIE_TYPE_CF_SET: + case WLAN_EID_CF_PARAMS: pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); lbs_deb_scan("got CF IE\n"); break; - case MFIE_TYPE_IBSS_SET: + case WLAN_EID_IBSS_PARAMS: pibss = (struct ieeetypes_ibssparamset *) pos; bss->atimwindow = le16_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, @@ -645,7 +645,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got IBSS IE\n"); break; - case MFIE_TYPE_COUNTRY: + case WLAN_EID_COUNTRY: pcountryinfo = (struct ieeetypes_countryinfoset *) pos; lbs_deb_scan("got COUNTRY IE\n"); if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) @@ -662,7 +662,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, (int) (pcountryinfo->len + 2)); break; - case MFIE_TYPE_RATES_EX: + case WLAN_EID_EXT_SUPP_RATES: /* only process extended supported rate if data rate is * already found. Data rate IE should come before * extended supported rate IE @@ -673,50 +673,51 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; } - n_ex_rates = elem->len; + n_ex_rates = pos[1]; if (n_basic_rates + n_ex_rates > MAX_RATES) n_ex_rates = MAX_RATES - n_basic_rates; p = bss->rates + n_basic_rates; - memcpy(p, elem->data, n_ex_rates); + memcpy(p, pos + 2, n_ex_rates); break; - case MFIE_TYPE_GENERIC: - if (elem->len >= 4 && - elem->data[0] == 0x00 && elem->data[1] == 0x50 && - elem->data[2] == 0xf2 && elem->data[3] == 0x01) { - bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); - memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); + case WLAN_EID_GENERIC: + if (pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0xf2 && pos[5] == 0x01) { + bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + memcpy(bss->wpa_ie, pos, bss->wpa_ie_len); lbs_deb_scan("got WPA IE\n"); - lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len); - } else if (elem->len >= MARVELL_MESH_IE_LENGTH && - elem->data[0] == 0x00 && elem->data[1] == 0x50 && - elem->data[2] == 0x43 && elem->data[3] == 0x04) { + lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, + bss->wpa_ie_len); + } else if (pos[1] >= MARVELL_MESH_IE_LENGTH && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0x43 && pos[4] == 0x04) { lbs_deb_scan("got mesh IE\n"); bss->mesh = 1; } else { lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n", - elem->data[0], elem->data[1], - elem->data[2], elem->data[3], - elem->len); + pos[2], pos[3], + pos[4], pos[5], + pos[1]); } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: lbs_deb_scan("got RSN IE\n"); - bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); - memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); + bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + memcpy(bss->rsn_ie, pos, bss->rsn_ie_len); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", - bss->rsn_ie, elem->len); + bss->rsn_ie, bss->rsn_ie_len); break; default: lbs_deb_scan("got IE 0x%04x, len %d\n", - elem->id, elem->len); + pos[0], pos[1]); break; } - pos += elem->len + 2; + pos += pos[1] + 2; } /* Timestamp */ diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 9e07b04..fab7d5d 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -7,6 +7,10 @@ #ifndef _LBS_SCAN_H #define _LBS_SCAN_H +#include + +#define MAX_NETWORK_COUNT 128 + /** * @brief Maximum number of channels that can be sent in a setuserscan ioctl */ diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index e0c2599..fb7a2d1 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,7 +7,6 @@ #include #include #include -#include struct ieeetypes_cfparamset { u8 elementid; @@ -258,7 +257,7 @@ struct mrvlietypes_ledbhv { * Note that the len member of the ieee80211_info_element varies depending on * the mesh_id_len */ struct mrvl_meshie_val { - uint8_t oui[P80211_OUI_LEN]; + uint8_t oui[3]; uint8_t type; uint8_t subtype; uint8_t version; @@ -270,7 +269,7 @@ struct mrvl_meshie_val { } __attribute__ ((packed)); struct mrvl_meshie { - struct ieee80211_info_element hdr; + u8 id, len; struct mrvl_meshie_val val; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index d4c6a65..fe7498f 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -9,7 +9,6 @@ #include #include -#include #include #include "host.h" diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index b657a91..f4ea08f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -86,8 +86,8 @@ #include #include #include +#include #include -#include #include #include @@ -143,7 +143,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) #define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD) +#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) #define SYMBOL_MAX_VER_LEN (14) #define USER_BAP 0 @@ -392,7 +392,7 @@ static void orinoco_bss_data_init(struct orinoco_private *priv) } static inline u8 *orinoco_get_ie(u8 *data, size_t len, - enum ieee80211_mfie eid) + enum ieee80211_eid eid) { u8 *p = data; while ((p + 2) < (data + len)) { @@ -409,7 +409,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) { u8 *p = data; while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == MFIE_TYPE_GENERIC) && + if ((p[0] == WLAN_EID_GENERIC) && (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) return p; p += p[1] + 2; @@ -839,7 +839,8 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; - if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) > + /* MTU + encapsulation + header length */ + if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > (priv->nicbuf_size - ETH_HLEN) ) return -EINVAL; @@ -1254,7 +1255,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, } /* sanity check the length */ - if (datalen > IEEE80211_DATA_LEN + 12) { + if (datalen > IEEE80211_MAX_DATA_LEN + 12) { printk(KERN_DEBUG "%s: oversized monitor frame, " "data length = %d\n", dev->name, datalen); stats->rx_length_errors++; @@ -1382,7 +1383,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) data. */ goto out; } - if (length > IEEE80211_DATA_LEN) { + if (length > IEEE80211_MAX_DATA_LEN) { printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", dev->name, length); stats->rx_length_errors++; @@ -3285,7 +3286,7 @@ static int orinoco_init(struct net_device *dev) /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; + priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; /* Initialize the firmware */ err = hermes_init(hw); @@ -4681,7 +4682,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if ((idx < 1) || (idx > WEP_KEYS)) + if ((idx < 1) || (idx > 4)) goto out; idx--; } else @@ -4786,7 +4787,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if ((idx < 1) || (idx > WEP_KEYS)) + if ((idx < 1) || (idx > 4)) goto out; idx--; } else @@ -4949,7 +4950,8 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, unsigned long flags; int err = 0; - if ((wrqu->data.length > MAX_WPA_IE_LEN) || + /* cut off at IEEE80211_MAX_DATA_LEN */ + if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || (wrqu->data.length && (extra == NULL))) return -EINVAL; @@ -5632,7 +5634,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, &iwe, IW_EV_UINT_LEN); } - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); channel = ie ? ie[2] : 0; if ((channel >= 1) && (channel <= NUM_CHANNELS)) { /* Add channel and frequency */ @@ -5682,7 +5684,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, } /* RSN IE */ - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); if (ie) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie[1] + 2; @@ -5690,7 +5692,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, &iwe, ie); } - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); if (ie) { char *p = current_ev + iwe_stream_lcp_len(info); int i; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index bd059e3..a1eeb48 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -37,11 +37,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include @@ -1652,7 +1652,7 @@ static char *rndis_translate_scan(struct net_device *dev, #ifdef DEBUG struct usbnet *usbdev = dev->priv; #endif - struct ieee80211_info_element *ie; + u8 *ie; char *current_val; int bssid_len, ie_len, i; u32 beacon, atim; @@ -1750,20 +1750,20 @@ static char *rndis_translate_scan(struct net_device *dev, ie_len = min(bssid_len - (int)sizeof(*bssid), (int)le32_to_cpu(bssid->ie_length)); ie_len -= sizeof(struct ndis_80211_fixed_ies); - while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) { - if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 && - memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) || - ie->id == MFIE_TYPE_RSN) { + while (ie_len >= 2 && 2 + ie[1] <= ie_len) { + if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 && + memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) || + ie[0] == WLAN_EID_RSN) { devdbg(usbdev, "IE: WPA%d", - (ie->id == MFIE_TYPE_RSN) ? 2 : 1); + (ie[0] == WLAN_EID_RSN) ? 2 : 1); iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, - (u8 *)ie); + /* arbitrary cut-off at 64 */ + iwe.u.data.length = min(ie[1] + 2, 64); + cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie); } - ie_len -= sizeof(*ie) + ie->len; - ie = (struct ieee80211_info_element *)&ie->data[ie->len]; + ie_len -= 2 + ie[1]; + ie += 2 + ie[1]; } return cev; diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 65ceb08..59bb3a5 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -2,7 +2,7 @@ #define __WL3501_H__ #include -#include +#include /* define for WLA 2.0 */ #define WL3501_BLKSZ 256 @@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { struct wl3501_80211_tx_hdr { struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr_4addr mac_hdr; + struct ieee80211_hdr mac_hdr; } __attribute__ ((packed)); /* diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index bf744c1..1134e2f 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include #include -#include #include "zd1201.h" static struct usb_device_id zd1201_table[] = { @@ -345,7 +345,7 @@ static void zd1201_usbrx(struct urb *urb) frag = kmalloc(sizeof(*frag), GFP_ATOMIC); if (!frag) goto resubmit; - skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2); + skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); if (!skb) { kfree(frag); goto resubmit; -- cgit v1.1 From f07a6c495e88ae0143e3c20b1ed666314197277f Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Wed, 29 Oct 2008 04:28:28 +0200 Subject: ath5k: Update PCU code * In set_opmode don't handle antenna settings and preserve other STA_ID1 settings (shouldn't matter because we call it during reset but it makes things cleaner) Also set properly AP/ADHOC indicator flag on CFG while setting AP/ADHOC modes and always enable key search mode. * Properly set BSSID Mask during reset (cache it and reuse it durring set_associd) * Update beacon_init to flush pending BMISS interrupts and handle setting of adhoc beacon ATIM policy flag for ad-hoc mode. Also set TSF to 0 to start TSF increment on AP mode. We need to handle sleep timers for AR5212 there + add support for PCF. * Properly clean MIC key from keytable when TKIP is used (Bob is working on set_key function etc so i leave it for now). Tested on AR5212 (Hainan) and AR5413 and works fine v2 Set PISR on AR5211+ and ISR on AR5210, got to sleep more ;-) Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 3 +- drivers/net/wireless/ath5k/pcu.c | 111 ++++++++++++++++++++++++++++++------- drivers/net/wireless/ath5k/reg.h | 12 +++- 3 files changed, 102 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index b117920..a725bb9 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -1093,10 +1093,11 @@ struct ath5k_hw { u8 ah_sta_id[ETH_ALEN]; - /* Current BSSID we are trying to assoc to / creating. + /* Current BSSID we are trying to assoc to / create. * This is passed by mac80211 on config_interface() and cached here for * use in resets */ u8 ah_bssid[ETH_ALEN]; + u8 ah_bssid_mask[ETH_ALEN]; u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index a47df9a..5674639 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) { u32 pcu_reg, beacon_reg, low_id, high_id; - pcu_reg = 0; + + /* Preserve rest settings */ + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP + | AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? + (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); + beacon_reg = 0; ATH5K_TRACE(ah->ah_sc); switch (ah->ah_op_mode) { case NL80211_IFTYPE_ADHOC: - pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); + pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_ADHOC; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); + pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_AP; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC); break; case NL80211_IFTYPE_STATION: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); case NL80211_IFTYPE_MONITOR: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_NO_PSPOLL : 0); break; @@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); } + + /* TODO: Handle ANI stats */ } /** @@ -254,6 +267,10 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) * @mac: The card's mac address * * Set station id on hw using the provided mac address + * + * NOTE: This is only called during attach, don't call it + * on reset because it overwrites all AR5K_STA_ID1 settings. + * We have set_opmode (above) for reset. */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { @@ -290,8 +307,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set simple BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); + ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM1); } /* @@ -415,6 +434,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) u32 low_id, high_id; ATH5K_TRACE(ah->ah_sc); + /* Cache bssid mask so that we can restore it + * on reset */ + memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); if (ah->ah_version == AR5K_AR5212) { low_id = AR5K_LOW_ID(mask); high_id = AR5K_HIGH_ID(mask); @@ -576,7 +598,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) filter |= AR5K_RX_FILTER_PROM; } - /*Zero length DMA*/ + /*Zero length DMA (phy error reporting) */ if (data) AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); else @@ -661,7 +683,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) * Set the additional timers by mode */ switch (ah->ah_op_mode) { + case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_STATION: + /* In STA mode timer1 is used as next wakeup + * timer and timer2 as next CFP duration start + * timer. Both in 1/8TUs. */ + /* TODO: PCF handling */ if (ah->ah_version == AR5K_AR5210) { timer1 = 0xffffffff; timer2 = 0xffffffff; @@ -669,27 +696,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) timer1 = 0x0000ffff; timer2 = 0x0007ffff; } + /* Mark associated AP as PCF incapable for now */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); break; - + case NL80211_IFTYPE_ADHOC: + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); default: + /* On non-STA modes timer1 is used as next DMA + * beacon alert (DBA) timer and timer2 as next + * software beacon alert. Both in 1/8TUs. */ timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + break; } + /* Timer3 marks the end of our ATIM window + * a zero length window is not allowed because + * we 'll get no beacons */ timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); /* * Set the beacon register and enable all timers. - * (next beacon, DMA beacon, software beacon, ATIM window time) */ - ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + /* When in AP mode zero timer0 to start TSF */ + if (ah->ah_op_mode == NL80211_IFTYPE_AP) + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + else + ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); + /* Force a TSF reset if requested and enable beacons */ + if (interval & AR5K_BEACON_RESET_TSF) + ath5k_hw_reset_tsf(ah); + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | - AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), - AR5K_BEACON); + AR5K_BEACON_ENABLE), + AR5K_BEACON); + + /* Flush any pending BMISS interrupts on ISR by + * performing a clear-on-write operation on PISR + * register for the BMISS bit (writing a bit on + * ISR togles a reset for that bit and leaves + * the rest bits intact) */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); + else + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); + + /* TODO: Set enchanced sleep registers on AR5212 + * based on vif->bss_conf params, until then + * disable power save reporting.*/ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); + } #if 0 @@ -899,14 +959,25 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) */ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) { - unsigned int i; + unsigned int i, type; ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + /* Reset associated MIC entry if TKIP + * is enabled located at offset (entry + 64) */ + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + entry = entry + AR5K_KEYTABLE_MIC_OFFSET; + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + } + /* * Set NULL encryption on AR5212+ * diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 0dae54d..69755fc 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -1114,14 +1114,16 @@ #define AR5K_PCU_MAX 0x8fff /* - * First station id register (MAC address in lower 32 bits) + * First station id register (Lower 32 bits of MAC address) */ -#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0_ARRD_L32 0xffffffff /* - * Second station id register (MAC address in upper 16 bits) + * Second station id register (Upper 16 bits of MAC address + PCU settings) */ #define AR5K_STA_ID1 0x8004 /* Register Address */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ @@ -1811,6 +1813,10 @@ #define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) #define AR5K_KEYTABLE_VALID 0x00008000 +/* If key type is TKIP and MIC is enabled + * MIC key goes in offset entry + 64 */ +#define AR5K_KEYTABLE_MIC_OFFSET 64 + /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit -- cgit v1.1 From 17683c65c8a5f3f29f5408334992986b996d8205 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Oct 2008 23:24:26 -0400 Subject: ath5k: fix keytable type buglet in ath5k_hw_reset_key Be sure we clear out both the mic (if applicable) and the encryption key type. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/pcu.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index 5674639..9c66985 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -960,6 +960,7 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) { unsigned int i, type; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); @@ -972,10 +973,10 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) /* Reset associated MIC entry if TKIP * is enabled located at offset (entry + 64) */ if (type == AR5K_KEYTABLE_TYPE_TKIP) { - entry = entry + AR5K_KEYTABLE_MIC_OFFSET; - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + ath5k_hw_reg_write(ah, 0, + AR5K_KEYTABLE_OFF(micentry, i)); } /* @@ -987,10 +988,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) * Note2: Windows driver (ndiswrapper) sets this to * 0x00000714 instead of 0x00000007 */ - if (ah->ah_version > AR5K_AR5211) + if (ah->ah_version > AR5K_AR5211) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(entry)); + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + } + } + return 0; } -- cgit v1.1 From b5aa9bf9460f9e97f2c10940b029d75c6557ad7c Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:13:31 +0530 Subject: ath9k: Node cleanup Start removing the internal node list in ath9k, in preparation for using mac80211's STA list. Remove lists, locks, routines, flags, functions managing nodes in ath9k. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 116 +++++++++++++++----------------------- drivers/net/wireless/ath9k/core.h | 46 ++++----------- drivers/net/wireless/ath9k/main.c | 94 +++--------------------------- drivers/net/wireless/ath9k/rc.c | 15 +---- drivers/net/wireless/ath9k/recv.c | 42 ++------------ drivers/net/wireless/ath9k/xmit.c | 107 +++++++---------------------------- 6 files changed, 94 insertions(+), 326 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 0089e02..49fc264 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -47,6 +47,41 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz) *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ } +static u8 parse_mpdudensity(u8 mpdudensity) +{ + /* + * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": + * 0 for no restriction + * 1 for 1/4 us + * 2 for 1/2 us + * 3 for 1 us + * 4 for 2 us + * 5 for 4 us + * 6 for 8 us + * 7 for 16 us + */ + switch (mpdudensity) { + case 0: + return 0; + case 1: + case 2: + case 3: + /* Our lower layer calculations limit our precision to + 1 microsecond */ + return 1; + case 4: + return 2; + case 5: + return 4; + case 6: + return 8; + case 7: + return 16; + default: + return 0; + } +} + /* * Set current operating mode * @@ -1321,7 +1356,7 @@ void ath_deinit(struct ath_softc *sc) /* Node Management */ /*******************/ -struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) +void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, int if_id) { struct ath_vap *avp; struct ath_node *an; @@ -1329,90 +1364,30 @@ struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) avp = sc->sc_vaps[if_id]; ASSERT(avp != NULL); - /* mac80211 sta_notify callback is from an IRQ context, so no sleep */ - an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC); - if (an == NULL) - return NULL; - memset(an, 0, sizeof(*an)); - - an->an_sc = sc; - memcpy(an->an_addr, addr, ETH_ALEN); - atomic_set(&an->an_refcnt, 1); + an = (struct ath_node *)sta->drv_priv; /* set up per-node tx/rx state */ ath_tx_node_init(sc, an); ath_rx_node_init(sc, an); + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + ath_chainmask_sel_init(sc, an); ath_chainmask_sel_timerstart(&an->an_chainmask_sel); - list_add(&an->list, &sc->node_list); - - return an; } -void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag) +void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { - unsigned long flags; + struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_chainmask_sel_timerstop(&an->an_chainmask_sel); - an->an_flags |= ATH_NODE_CLEAN; - ath_tx_node_cleanup(sc, an, bh_flag); - ath_rx_node_cleanup(sc, an); + + ath_tx_node_cleanup(sc, an); ath_tx_node_free(sc, an); ath_rx_node_free(sc, an); - - spin_lock_irqsave(&sc->node_lock, flags); - - list_del(&an->list); - - spin_unlock_irqrestore(&sc->node_lock, flags); - - kfree(an); -} - -/* Finds a node and increases the refcnt if found */ - -struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr) -{ - struct ath_node *an = NULL, *an_found = NULL; - - if (list_empty(&sc->node_list)) /* FIXME */ - goto out; - list_for_each_entry(an, &sc->node_list, list) { - if (!compare_ether_addr(an->an_addr, addr)) { - atomic_inc(&an->an_refcnt); - an_found = an; - break; - } - } -out: - return an_found; -} - -/* Decrements the refcnt and if it drops to zero, detach the node */ - -void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag) -{ - if (atomic_dec_and_test(&an->an_refcnt)) - ath_node_detach(sc, an, bh_flag); -} - -/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */ -struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr) -{ - struct ath_node *an = NULL, *an_found = NULL; - - if (list_empty(&sc->node_list)) - return NULL; - - list_for_each_entry(an, &sc->node_list, list) - if (!compare_ether_addr(an->an_addr, addr)) { - an_found = an; - break; - } - - return an_found; } /* @@ -1437,7 +1412,6 @@ void ath_newassoc(struct ath_softc *sc, ath_rx_aggr_teardown(sc, an, tidno); } } - an->an_flags = 0; } /**************/ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index fbff9aa..d7228ec 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -373,7 +373,6 @@ void ath_flushrecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an); -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_handle_rx_intr(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); void ath_rx_cleanup(struct ath_softc *sc); @@ -546,8 +545,7 @@ 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); 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); +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); 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); @@ -568,11 +566,6 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /* Node / Aggregation */ /**********************/ -/* indicates the node is clened up */ -#define ATH_NODE_CLEAN 0x1 -/* indicates the node is 80211 power save */ -#define ATH_NODE_PWRSAVE 0x2 - #define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -584,6 +577,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 #define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 /* return whether a bit at index _n in bitmap _bm is set * _sz is the size of the bitmap */ @@ -638,15 +632,10 @@ struct ath_node_aggr { /* driver-specific node state */ struct ath_node { - struct list_head list; struct ath_softc *an_sc; - atomic_t an_refcnt; struct ath_chainmask_sel an_chainmask_sel; struct ath_node_aggr an_aggr; u8 an_smmode; /* SM Power save mode */ - u8 an_flags; - u8 an_addr[ETH_ALEN]; - u16 maxampdu; u8 mpdudensity; }; @@ -659,28 +648,17 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); void ath_rx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn); -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid); -int ath_tx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid); +int ath_rx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int ath_rx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_newassoc(struct ath_softc *sc, struct ath_node *node, int isnew, int isuapsd); -struct ath_node *ath_node_attach(struct ath_softc *sc, - u8 addr[ETH_ALEN], int if_id); -void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag); -struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]); -void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag); -struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); +void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, + int if_id); +void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta); /*******************/ /* Beacon Handling */ @@ -975,7 +953,6 @@ struct ath_softc { u8 sc_rxotherant; /* rx's on non-default antenna */ struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ - struct list_head node_list; struct ath_ht_info sc_ht_info; enum ath9k_ht_extprotspacing sc_ht_extprotspacing; @@ -1036,7 +1013,6 @@ struct ath_softc { spinlock_t sc_rxbuflock; spinlock_t sc_txbuflock; spinlock_t sc_resetlock; - spinlock_t node_lock; /* LEDs */ struct ath_led radio_led; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index b25c8f9..b1b1e7f 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -21,8 +21,6 @@ #define ATH_PCI_VERSION "0.1" -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); @@ -297,41 +295,6 @@ static void ath9k_rx_prepare(struct ath_softc *sc, rx_status->flag |= RX_FLAG_TSFT; } -static u8 parse_mpdudensity(u8 mpdudensity) -{ - /* - * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": - * 0 for no restriction - * 1 for 1/4 us - * 2 for 1/2 us - * 3 for 1 us - * 4 for 2 us - * 5 for 4 us - * 6 for 8 us - * 7 for 16 us - */ - switch (mpdudensity) { - case 0: - return 0; - case 1: - case 2: - case 3: - /* Our lower layer calculations limit our precision to - 1 microsecond */ - return 1; - case 4: - return 2; - case 5: - return 4; - case 6: - return 8; - case 7: - return 16; - default: - return 0; - } -} - static void ath9k_ht_conf(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { @@ -479,8 +442,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_info->status.rates[0].count = tx_status->retries + 1; ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); } int _ath_rx_indicate(struct ath_softc *sc, @@ -518,10 +479,6 @@ int _ath_rx_indicate(struct ath_softc *sc, rx_status.flag |= RX_FLAG_DECRYPTED; } - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr2); - spin_unlock_bh(&sc->node_lock); - if (an) { ath_rx_input(sc, an, skb, status, &st); @@ -913,11 +870,6 @@ static int ath_attach(u16 devid, if (error != 0) return error; - /* Init nodes */ - - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); - /* get mac address from hardware and set in mac80211 */ SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); @@ -1404,50 +1356,22 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, __func__, sc->rx_filter); } +/* Only a single interface is currently supported, + so pass 0 as the interface id to ath_node_attach */ + static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; - struct ath_node *an; - unsigned long flags; - - spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, sta->addr); - spin_unlock_irqrestore(&sc->node_lock, flags); switch (cmd) { case STA_NOTIFY_ADD: - spin_lock_irqsave(&sc->node_lock, flags); - if (!an) { - ath_node_attach(sc, sta->addr, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %pM\n", - __func__, sta->addr); - } else { - ath_node_get(sc, sta->addr); - } - - /* XXX: Is this right? Can the capabilities change? */ - an = ath_node_find(sc, sta->addr); - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = - parse_mpdudensity(sta->ht_cap.ampdu_density); - - spin_unlock_irqrestore(&sc->node_lock, flags); + ath_node_attach(sc, sta, 0); break; case STA_NOTIFY_REMOVE: - if (!an) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Removal of a non-existent node\n", - __func__); - else { - ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %pM\n", - __func__, - sta->addr); - } + ath_node_detach(sc, sta); break; default: break; @@ -1595,21 +1519,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn); + ret = ath_rx_aggr_start(sc, sta, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to start RX aggregation\n", __func__); break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, sta->addr, tid); + ret = ath_rx_aggr_stop(sc, sta, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to stop RX aggregation\n", __func__); break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); + ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to start TX aggregation\n", @@ -1618,7 +1542,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta->addr, tid); + ret = ath_tx_aggr_stop(sc, sta, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to stop TX aggregation\n", diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index ecffd6f..1305873 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1867,9 +1867,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, /* XXX: UGLY HACK!! */ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); + an = (struct ath_node *)sta->drv_priv; if (tx_info_priv == NULL) return; @@ -1984,16 +1982,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to " - "init/chk TX aggr\n", __func__); - return; - } + an = (struct ath_node *)sta->drv_priv; chk = ath_tx_aggr_check(sc, an, tid); if (chk == AGGR_REQUIRED) { diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 8283228..6b4006e 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -1095,7 +1095,7 @@ rx_next: /* Process ADDBA request in per-TID data structure */ int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) { @@ -1105,17 +1105,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, struct ieee80211_supported_band *sband; u16 buffersize = 0; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize RX aggregation\n", - __func__); - return -1; - } - + an = (struct ath_node *)sta->drv_priv; sband = hw->wiphy->bands[hw->conf.channel->band]; buffersize = IEEE80211_MIN_AMPDU_BUF << sband->ht_cap.ampdu_factor; /* FIXME */ @@ -1172,21 +1162,9 @@ int ath_rx_aggr_start(struct ath_softc *sc, /* Process DELBA */ -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) +int ath_rx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { - struct ath_node *an; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: RX aggr stop for non-existent node\n", __func__); - return -1; - } + struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_rx_aggr_teardown(sc, an, tid); return 0; @@ -1194,8 +1172,7 @@ int ath_rx_aggr_stop(struct ath_softc *sc, /* Rx aggregation tear down */ -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) +void ath_rx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) { struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid]; @@ -1253,7 +1230,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) +void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) { if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; @@ -1281,10 +1258,3 @@ void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } } - -/* Cleanup per-node receive state */ - -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - ath_rx_node_cleanup(sc, an); -} diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 7cfab5a..6455713 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -214,15 +214,6 @@ static int ath_tx_prepare(struct ath_softc *sc, rt = sc->sc_currates; BUG_ON(!rt); - /* Fill misc fields */ - - spin_lock_bh(&sc->node_lock); - txctl->an = ath_node_get(sc, hdr->addr1); - /* create a temp node, if the node is not there already */ - if (!txctl->an) - txctl->an = ath_node_attach(sc, hdr->addr1, 0); - spin_unlock_bh(&sc->node_lock); - if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); txctl->tidno = qc[0] & 0xf; @@ -496,11 +487,9 @@ unlock: /* Compute the number of bad frames */ -static int ath_tx_num_badfrms(struct ath_softc *sc, - struct ath_buf *bf, int txok) +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok) { - struct ath_node *an = bf->bf_node; - int isnodegone = (an->an_flags & ATH_NODE_CLEAN); struct ath_buf *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; u16 seq_st = 0; @@ -509,7 +498,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, int nbad = 0; int isaggr = 0; - if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) return 0; isaggr = bf_isaggr(bf); @@ -908,7 +897,6 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0; - int isnodegone = (an->an_flags & ATH_NODE_CLEAN); isaggr = bf_isaggr(bf); if (isaggr) { @@ -954,7 +942,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, /* transmit completion */ } else { - if (!tid->cleanup_inprogress && !isnodegone && + if (!tid->cleanup_inprogress && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, bf); @@ -1083,15 +1071,6 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, bf = bf_next; } - /* - * node is already gone. no more assocication - * with the node. the node might have been freed - * any node acces can result in panic.note tid - * is part of the node. - */ - if (isnodegone) - return; - if (tid->cleanup_inprogress) { /* check to see if we're done with cleaning the h/w queue */ spin_lock_bh(&txq->axq_lock); @@ -1795,8 +1774,8 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - bool bh_flag) + struct ath_atx_tid *tid) + { struct ath_buf *bf; struct list_head bf_head; @@ -1817,18 +1796,12 @@ static void ath_tid_drain(struct ath_softc *sc, * do not indicate packets while holding txq spinlock. * unlock is intentional here */ - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); + spin_unlock(&txq->axq_lock); /* complete this sub-frame */ ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); - if (likely(bh_flag)) - spin_lock_bh(&txq->axq_lock); - else - spin_lock(&txq->axq_lock); + spin_lock(&txq->axq_lock); } /* @@ -1847,8 +1820,7 @@ static void ath_tid_drain(struct ath_softc *sc, */ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, - struct ath_txq *txq, - bool bh_flag) + struct ath_txq *txq) { struct ath_atx_ac *ac, *ac_tmp; struct ath_atx_tid *tid, *tid_tmp; @@ -1859,7 +1831,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { list_del(&tid->list); tid->sched = false; - ath_tid_drain(sc, txq, tid, bh_flag); + ath_tid_drain(sc, txq, tid); } } } @@ -2294,8 +2266,6 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) * or asynchrounsly once DMA is complete. */ xmit_map_sg(sc, skb, &txctl); - else - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); /* failed packets will be dropped by the caller */ return error; @@ -2374,8 +2344,7 @@ void ath_tx_draintxq(struct ath_softc *sc, if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq, - ATH9K_BH_STATUS_CHANGE); + ath_txq_drain_pending_buffers(sc, txq); spin_unlock_bh(&txq->axq_lock); } } @@ -2441,24 +2410,13 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, /* Start TX aggregation */ -int ath_tx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn) +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_atx_tid *txtid; struct ath_node *an; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize " - "TX aggregation\n", __func__); - return -1; - } + an = (struct ath_node *)sta->drv_priv; if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); @@ -2471,21 +2429,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, /* Stop tx aggregation */ -int ath_tx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { - struct ath_node *an; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: TX aggr stop for non-existent node\n", __func__); - return -1; - } + struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_tx_aggr_teardown(sc, an, tid); return 0; @@ -2498,8 +2444,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, * - Discard all retry frames from the s/w queue. */ -void ath_tx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) +void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) { struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum]; @@ -2625,8 +2570,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) struct ath_atx_ac *ac; int tidno, acno; - an->maxampdu = ATH_AMPDU_LIMIT_DEFAULT; - /* * Init per tid tx state */ @@ -2684,8 +2627,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) /* Cleanupthe pending buffers for the node. */ -void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag) +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { int i; struct ath_atx_ac *ac, *ac_tmp; @@ -2695,10 +2637,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, if (ATH_TXQ_SETUP(sc, i)) { txq = &sc->sc_txq[i]; - if (likely(bh_flag)) - spin_lock_bh(&txq->axq_lock); - else - spin_lock(&txq->axq_lock); + spin_lock(&txq->axq_lock); list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { @@ -2713,17 +2652,14 @@ void ath_tx_node_cleanup(struct ath_softc *sc, tid_tmp, &ac->tid_q, list) { list_del(&tid->list); tid->sched = false; - ath_tid_drain(sc, txq, tid, bh_flag); + ath_tid_drain(sc, txq, tid); tid->addba_exchangecomplete = 0; tid->addba_exchangeattempts = 0; tid->cleanup_inprogress = false; } } - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); + spin_unlock(&txq->axq_lock); } } } @@ -2794,7 +2730,6 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) */ 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 v1.1 From c51701632c8becdf0ffedb96d9cedc1149f2183a Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:13:59 +0530 Subject: ath9k: Simplify node attach/detach routines Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 15 ++--- drivers/net/wireless/ath9k/core.h | 2 +- drivers/net/wireless/ath9k/recv.c | 81 ++++++++++++------------ drivers/net/wireless/ath9k/xmit.c | 125 ++++++++++++++++---------------------- 4 files changed, 99 insertions(+), 124 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 49fc264..689a280 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1366,9 +1366,10 @@ void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, int if_id) an = (struct ath_node *)sta->drv_priv; - /* set up per-node tx/rx state */ - ath_tx_node_init(sc, an); - ath_rx_node_init(sc, an); + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_init(sc, an); + if (sc->sc_flags & SC_OP_RXAGGR) + ath_rx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + sta->ht_cap.ampdu_factor); @@ -1384,10 +1385,10 @@ void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ath_chainmask_sel_timerstop(&an->an_chainmask_sel); - ath_tx_node_cleanup(sc, an); - - ath_tx_node_free(sc, an); - ath_rx_node_free(sc, an); + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_cleanup(sc, an); + if (sc->sc_flags & SC_OP_RXAGGR) + ath_rx_node_cleanup(sc, an); } /* diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index d7228ec..d8aafff 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -372,7 +372,7 @@ bool ath_stoprecv(struct ath_softc *sc); void ath_flushrecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an); -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an); +void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_handle_rx_intr(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); void ath_rx_cleanup(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 6b4006e..27d6a98 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -1200,61 +1200,56 @@ void ath_rx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - rxtid->an = an; - rxtid->seq_reset = 1; - rxtid->seq_next = 0; - rxtid->baw_size = WME_MAX_BA; - rxtid->baw_head = rxtid->baw_tail = 0; + struct ath_arx_tid *rxtid; + int tidno; + + /* Init per tid rx state */ + for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; + tidno < WME_NUM_TID; + tidno++, rxtid++) { + rxtid->an = an; + rxtid->seq_reset = 1; + rxtid->seq_next = 0; + rxtid->baw_size = WME_MAX_BA; + rxtid->baw_head = rxtid->baw_tail = 0; - /* - * Ensure the buffer pointer is null at this point - * (needs to be allocated when addba is received) - */ + /* + * Ensure the buffer pointer is null at this point + * (needs to be allocated when addba is received) + */ - rxtid->rxbuf = NULL; - setup_timer(&rxtid->timer, ath_rx_timer, - (unsigned long)rxtid); - spin_lock_init(&rxtid->tidlock); + rxtid->rxbuf = NULL; + setup_timer(&rxtid->timer, ath_rx_timer, + (unsigned long)rxtid); + spin_lock_init(&rxtid->tidlock); - /* ADDBA state */ - rxtid->addba_exchangecomplete = 0; - } + /* ADDBA state */ + rxtid->addba_exchangecomplete = 0; } } -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) +void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno, i; + struct ath_arx_tid *rxtid; + int tidno, i; - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { + /* Init per tid rx state */ + for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; + tidno < WME_NUM_TID; + tidno++, rxtid++) { - if (!rxtid->addba_exchangecomplete) - continue; + if (!rxtid->addba_exchangecomplete) + continue; - /* must cancel timer first */ - del_timer_sync(&rxtid->timer); + /* must cancel timer first */ + del_timer_sync(&rxtid->timer); - /* drop any pending sub-frames */ - ath_rx_flush_tid(sc, rxtid, 1); + /* drop any pending sub-frames */ + ath_rx_flush_tid(sc, rxtid, 1); - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); + for (i = 0; i < ATH_TID_MAX_BUFS; i++) + ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); - rxtid->addba_exchangecomplete = 0; - } + rxtid->addba_exchangecomplete = 0; } - } diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 6455713..bd78244 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2565,62 +2565,60 @@ 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_flags & SC_OP_TXAGGR) { - struct ath_atx_tid *tid; - struct ath_atx_ac *ac; - int tidno, acno; - - /* - * Init per tid tx state - */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - tid->an = an; - tid->tidno = tidno; - tid->seq_start = tid->seq_next = 0; - tid->baw_size = WME_MAX_BA; - tid->baw_head = tid->baw_tail = 0; - tid->sched = false; - tid->paused = false; - tid->cleanup_inprogress = false; - INIT_LIST_HEAD(&tid->buf_q); - - acno = TID_TO_WME_AC(tidno); - tid->ac = &an->an_aggr.tx.ac[acno]; + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + int tidno, acno; - /* ADDBA state */ - tid->addba_exchangecomplete = 0; - tid->addba_exchangeinprogress = 0; - tid->addba_exchangeattempts = 0; - } + /* + * Init per tid tx state + */ + for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; + tidno < WME_NUM_TID; + tidno++, tid++) { + tid->an = an; + tid->tidno = tidno; + tid->seq_start = tid->seq_next = 0; + tid->baw_size = WME_MAX_BA; + tid->baw_head = tid->baw_tail = 0; + tid->sched = false; + tid->paused = false; + tid->cleanup_inprogress = false; + INIT_LIST_HEAD(&tid->buf_q); + + acno = TID_TO_WME_AC(tidno); + tid->ac = &an->an_aggr.tx.ac[acno]; + + /* ADDBA state */ + tid->addba_exchangecomplete = 0; + tid->addba_exchangeinprogress = 0; + tid->addba_exchangeattempts = 0; + } - /* - * Init per ac tx state - */ - for (acno = 0, ac = &an->an_aggr.tx.ac[acno]; - acno < WME_NUM_AC; acno++, ac++) { - ac->sched = false; - INIT_LIST_HEAD(&ac->tid_q); - - switch (acno) { - case WME_AC_BE: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - break; - case WME_AC_BK: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); - break; - case WME_AC_VI: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); - break; - case WME_AC_VO: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); - break; - } + /* + * Init per ac tx state + */ + for (acno = 0, ac = &an->an_aggr.tx.ac[acno]; + acno < WME_NUM_AC; acno++, ac++) { + ac->sched = false; + INIT_LIST_HEAD(&ac->tid_q); + + switch (acno) { + case WME_AC_BE: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + break; + case WME_AC_BK: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); + break; + case WME_AC_VI: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); + break; + case WME_AC_VO: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); + break; } } } @@ -2664,25 +2662,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } } -/* Cleanup per node transmit state */ - -void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_TXAGGR) { - struct ath_atx_tid *tid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(tid->tx_buf[i] == NULL); - } - } -} - void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) { int hdrlen, padsize; -- cgit v1.1 From 528f0c6b3b6bbed1328ee49bfc906543daa00866 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:14:26 +0530 Subject: ath9k: Revamp transmit control block Use the ath_buf instance associated with each tx frame directly and remove all redundant information in ath_tx_control. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 2 +- drivers/net/wireless/ath9k/core.h | 30 +- drivers/net/wireless/ath9k/main.c | 23 +- drivers/net/wireless/ath9k/xmit.c | 611 ++++++++++++++++++------------------ 4 files changed, 324 insertions(+), 342 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 9e15c30..b36d3fb 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -114,7 +114,7 @@ static void ath_beacon_setup(struct ath_softc *sc, 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 */ + MAX_RATE_POWER, /* FIXME */ ATH9K_TXKEYIX_INVALID, /* no encryption */ ATH9K_KEY_TYPE_CLEAR, /* no encryption */ flags /* no ack, diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index d8aafff..21b572b 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -84,9 +84,6 @@ struct ath_node; #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -#define ATH9K_BH_STATUS_INTACT 0 -#define ATH9K_BH_STATUS_CHANGE 1 - #define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<bf_state.bf_type & BUF_DATA) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) @@ -244,7 +243,6 @@ struct ath_buf { struct ath_buf *bf_next; /* next subframe in the aggregate */ struct ath_buf *bf_rifslast; /* last buf for RIFS burst */ void *bf_mpdu; /* enclosing frame structure */ - void *bf_node; /* pointer to the node */ struct ath_desc *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ @@ -493,24 +491,8 @@ struct ath_atx { /* per-frame tx control block */ struct ath_tx_control { - struct ath_node *an; + struct ath_txq *txq; int if_id; - int qnum; - u32 ht:1; - u32 ps:1; - u32 use_minrate:1; - enum ath9k_pkt_type atype; - enum ath9k_key_type keytype; - u32 flags; - u16 seqno; - u16 tidno; - u16 txpower; - u16 frmlen; - u32 keyix; - int min_rate; - int mcast_rate; - struct ath_softc *dev; - dma_addr_t dmacontext; }; /* per frame tx status block */ @@ -551,15 +533,17 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_tx_cleanup(struct ath_softc *sc); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb); +int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl); void ath_tx_tasklet(struct ath_softc *sc); u32 ath_txq_depth(struct ath_softc *sc, int qnum); 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); + struct ath_xmit_status *tx_status); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /**********************/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index b1b1e7f..839db231 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -412,7 +412,7 @@ void ath_get_beaconconfig(struct ath_softc *sc, } void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an) + struct ath_xmit_status *tx_status) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -906,6 +906,7 @@ static int ath_attach(u16 devid, } hw->queues = 4; + hw->sta_data_size = sizeof(struct ath_node); /* Register rate control */ hw->rate_control_algorithm = "ath9k_rate_control"; @@ -1016,9 +1017,12 @@ static int ath9k_start(struct ieee80211_hw *hw) static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = hw->priv; + struct ath_tx_control txctl; int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* * As a temporary workaround, assign seq# here; this will likely need @@ -1043,18 +1047,25 @@ static int ath9k_tx(struct ieee80211_hw *hw, memmove(skb->data, skb->data + padsize, hdrlen); } + /* Check if a tx queue is available */ + + txctl.txq = ath_test_get_txq(sc, skb); + if (!txctl.txq) + goto exit; + DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", __func__, skb); - if (ath_tx_start(sc, skb) != 0) { + if (ath_tx_start(sc, skb, &txctl) != 0) { DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); - dev_kfree_skb_any(skb); - /* FIXME: Check for proper return value from ATH_DEV */ - return 0; + goto exit; } return 0; +exit: + dev_kfree_skb_any(skb); + return 0; } static void ath9k_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index bd78244..84219bc 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -136,15 +136,17 @@ static int ath_aggr_query(struct ath_softc *sc, return 0; } -static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) +/* Calculate Atheros packet type from IEEE80211 packet header */ + +static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) { + struct ieee80211_hdr *hdr; enum ath9k_pkt_type htype; __le16 fc; + hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - /* Calculate Atheros packet type from IEEE80211 packet header */ - if (ieee80211_is_beacon(fc)) htype = ATH9K_PKT_TYPE_BEACON; else if (ieee80211_is_probe_resp(fc)) @@ -159,214 +161,176 @@ static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) return htype; } -static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl) +static bool check_min_rate(struct sk_buff *skb) { struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; + bool use_minrate = false; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - /* XXX: HACK! */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; + use_minrate = true; } else if (ieee80211_is_data(fc)) { if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(ETH_P_PAE))) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; + /* Port Access Entity (IEEE 802.1X) */ + (skb->protocol == cpu_to_be16(ETH_P_PAE))) { + use_minrate = true; } - if (is_multicast_ether_addr(hdr->addr1)) - txctl->mcast_rate = tx_info_priv->min_rate; } + return use_minrate; } -/* This function will setup additional txctl information, mostly rate stuff */ -/* FIXME: seqno, ps */ -static int ath_tx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_tx_control *txctl) +static int get_hw_crypto_keytype(struct sk_buff *skb) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; - struct ath_rc_series *rcs; - struct ath_txq *txq = NULL; - const struct ath9k_rate_table *rt; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; - int hdrlen; - u8 rix, antenna; - __le16 fc; - u8 *qc; - - txctl->dev = sc; - hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - rt = sc->sc_currates; - BUG_ON(!rt); - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - txctl->tidno = qc[0] & 0xf; - } - - txctl->if_id = 0; - txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); - - /* Always try at highest power possible unless the the device - * was configured by the user to use another power. */ - if (likely(sc->sc_config.txpowlimit == ATH_TXPOWER_MAX)) - txctl->txpower = ATH_TXPOWER_MAX; - else - txctl->txpower = sc->sc_config.txpowlimit; - - /* Fill Key related fields */ - - txctl->keytype = ATH9K_KEY_TYPE_CLEAR; - txctl->keyix = ATH9K_TXKEYIX_INVALID; if (tx_info->control.hw_key) { - txctl->keyix = tx_info->control.hw_key->hw_key_idx; - txctl->frmlen += tx_info->control.hw_key->icv_len; - if (tx_info->control.hw_key->alg == ALG_WEP) - txctl->keytype = ATH9K_KEY_TYPE_WEP; + return ATH9K_KEY_TYPE_WEP; else if (tx_info->control.hw_key->alg == ALG_TKIP) - txctl->keytype = ATH9K_KEY_TYPE_TKIP; + return ATH9K_KEY_TYPE_TKIP; else if (tx_info->control.hw_key->alg == ALG_CCMP) - txctl->keytype = ATH9K_KEY_TYPE_AES; + return ATH9K_KEY_TYPE_AES; } - /* Fill packet type */ - - txctl->atype = get_hal_packet_type(hdr); - - /* Fill qnum */ + return ATH9K_KEY_TYPE_CLEAR; +} - 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); +static void setup_rate_retries(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv; + struct ath_rc_series *rcs; + struct ieee80211_hdr *hdr; + const struct ath9k_rate_table *rt; + bool use_minrate; + __le16 fc; + u8 rix; - /* Try to avoid running out of descriptors */ - 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__, - txctl->qnum, - txq->axq_depth); - ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); - txq->stopped = 1; - spin_unlock_bh(&txq->axq_lock); - return -1; - } + rt = sc->sc_currates; + BUG_ON(!rt); - spin_unlock_bh(&txq->axq_lock); + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; /* HACK */ + rcs = tx_info_priv->rcs; - /* Fill rate */ + /* Check if min rates have to be used */ + use_minrate = check_min_rate(skb); - fill_min_rates(skb, txctl); + if (ieee80211_is_data(fc) && !use_minrate) { + if (is_multicast_ether_addr(hdr->addr1)) { + rcs[0].rix = + ath_tx_findindex(rt, tx_info_priv->min_rate); + /* mcast packets are not re-tried */ + rcs[0].tries = 1; + } + } else { + /* for management and control frames, + or for NULL and EAPOL frames */ + if (use_minrate) + rcs[0].rix = ath_rate_findrateix(sc, tx_info_priv->min_rate); + else + rcs[0].rix = 0; + rcs[0].tries = ATH_MGT_TXMAXTRY; + } - /* Fill flags */ + rix = rcs[0].rix; - txctl->flags |= ATH9K_TXDESC_CLRDMASK /* needed for crypto errors */ - | ATH9K_TXDESC_INTREQ; /* Generate an interrupt */ + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { + 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; + } +} - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - txctl->flags |= ATH9K_TXDESC_NOACK; +/* Called only when tx aggregation is enabled and HT is supported */ - if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - txctl->flags |= ATH9K_TXDESC_RTSENA; +static void assign_aggr_tid_seqno(struct sk_buff *skb, + struct ath_buf *bf) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + struct ath_node *an; + struct ath_atx_tid *tid; + __le16 fc; + u8 *qc; - /* - * Setup for rate calculations. - */ + if (!tx_info->control.sta) + return; - /* XXX: HACK! */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - rcs = tx_info_priv->rcs; + an = (struct ath_node *)tx_info->control.sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; - if (ieee80211_is_data(fc) && !txctl->use_minrate) { + /* Get tidno */ - /* Enable HT only for DATA frames and not for EAPOL */ - /* XXX why AMPDU only?? */ - txctl->ht = (hw->conf.ht.enabled && - (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + bf->bf_tidno = qc[0] & 0xf; + } - if (is_multicast_ether_addr(hdr->addr1)) { - rcs[0].rix = (u8) - ath_tx_findindex(rt, txctl->mcast_rate); + /* Get seqno */ - /* - * mcast packets are not re-tried. - */ - rcs[0].tries = 1; - } + if (ieee80211_is_data(fc) && !check_min_rate(skb)) { /* For HT capable stations, we save tidno for later use. * We also override seqno set by upper layer with the one * in tx aggregation state. * - * First, the fragmentation stat is determined. * If fragmentation is on, the sequence number is * not overridden, since it has been * incremented by the fragmentation routine. + * + * FIXME: check if the fragmentation threshold exceeds + * IEEE80211 max. */ - if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) && - txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - struct ath_atx_tid *tid; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << + IEEE80211_SEQ_SEQ_SHIFT); + bf->bf_seqno = tid->seq_next; + INCR(tid->seq_next, IEEE80211_SEQ_MAX); + } +} - tid = ATH_AN_2_TID(txctl->an, txctl->tidno); +static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, + struct ath_txq *txq) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + int flags = 0; - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << - IEEE80211_SEQ_SEQ_SHIFT); - txctl->seqno = tid->seq_next; - INCR(tid->seq_next, IEEE80211_SEQ_MAX); - } - } else { - /* for management and control frames, - * or for NULL and EAPOL frames */ - if (txctl->min_rate) - rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate); - else - rcs[0].rix = 0; - rcs[0].tries = ATH_MGT_TXMAXTRY; - } - rix = rcs[0].rix; + flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + flags |= ATH9K_TXDESC_INTREQ; - 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; - } + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= ATH9K_TXDESC_NOACK; + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + flags |= ATH9K_TXDESC_RTSENA; + + return flags; +} - if (is_multicast_ether_addr(hdr->addr1)) { - antenna = sc->sc_mcastantenna + 1; - sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) +{ + struct ath_buf *bf = NULL; + + spin_lock_bh(&sc->sc_txbuflock); + + if (unlikely(list_empty(&sc->sc_txbuf))) { + spin_unlock_bh(&sc->sc_txbuflock); + return NULL; } - return 0; + bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list); + list_del(&bf->list); + + spin_unlock_bh(&sc->sc_txbuflock); + + return bf; } /* To complete a chain of buffers associated a frame */ @@ -402,7 +366,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, skb->len, PCI_DMA_TODEVICE); /* complete this frame */ - ath_tx_complete(sc, skb, &tx_status, bf->bf_node); + ath_tx_complete(sc, skb, &tx_status); /* * Return the list of ath_buf of this mpdu to free queue @@ -615,7 +579,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; - struct ath_node *an = (struct ath_node *) bf->bf_node; + struct ath_node *an = NULL; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + + skb = (struct sk_buff *)bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->control.sta) + an = (struct ath_node *)tx_info->control.sta->drv_priv; /* * get the cix for the lowest valid rix. @@ -654,7 +626,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * use RTS. */ 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 */ @@ -664,7 +635,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * For dynamic MIMO PS, RTS needs to precede the first aggregate * and the second aggregate should have any protection at all. */ - if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { + if (an && an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { if (!bf_isaggrburst(bf)) { flags = ATH9K_TXDESC_RTSENA; dynamic_mimops = 1; @@ -736,7 +707,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), bf_isshpreamble(bf)); - if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) && + if (an && (an->an_smmode == ATH_SM_PWRSAV_STATIC) && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { /* * When sending to an HT node that has enabled static @@ -888,8 +859,10 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, struct list_head *bf_q, int txok) { - struct ath_node *an = bf->bf_node; - struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno); + struct ath_node *an = NULL; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ath_atx_tid *tid = NULL; struct ath_buf *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; struct ath_buf *bf_next, *bf_lastq = NULL; @@ -898,6 +871,14 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0; + skb = (struct sk_buff *)bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + } + isaggr = bf_isaggr(bf); if (isaggr) { if (txok) { @@ -1030,7 +1011,6 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, /* copy descriptor content */ tbf->bf_mpdu = bf_last->bf_mpdu; - tbf->bf_node = bf_last->bf_node; tbf->bf_buf_addr = bf_last->bf_buf_addr; *(tbf->bf_desc) = *(bf_last->bf_desc); @@ -1364,7 +1344,6 @@ static void ath_tx_addto_baw(struct ath_softc *sc, */ static int ath_tx_send_ampdu(struct ath_softc *sc, - struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head, struct ath_tx_control *txctl) @@ -1378,8 +1357,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; - bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */ - bf->bf_tidno = txctl->tidno; /* * Do not queue to h/w when any of the following conditions is true: @@ -1390,13 +1367,13 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, */ if (!list_empty(&tid->buf_q) || tid->paused || !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || - txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { + txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later * for aggregation. */ list_splice_tail_init(bf_head, &tid->buf_q); - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(txctl->txq, tid); return 0; } @@ -1413,7 +1390,7 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, bf->bf_nframes = 1; bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */ ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); + ath_tx_txqaddbuf(sc, txctl->txq, bf_head); return 0; } @@ -1836,46 +1813,27 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, } } -static int ath_tx_start_dma(struct ath_softc *sc, - struct sk_buff *skb, - struct scatterlist *sg, - u32 n_sg, - struct ath_tx_control *txctl) +static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, + struct sk_buff *skb, struct scatterlist *sg, + struct ath_tx_control *txctl) { - struct ath_node *an = txctl->an; - struct ath_buf *bf = NULL; - struct list_head bf_head; - struct ath_desc *ds; - struct ath_hal *ah = sc->sc_ah; - struct ath_txq *txq; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 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]; + int hdrlen; + __le16 fc; - /* For each sglist entry, allocate an ath_buf for DMA */ - INIT_LIST_HEAD(&bf_head); - spin_lock_bh(&sc->sc_txbuflock); - if (unlikely(list_empty(&sc->sc_txbuf))) { - spin_unlock_bh(&sc->sc_txbuflock); - return -ENOMEM; - } + tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + rcs = tx_info_priv->rcs; - bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list); - list_del(&bf->list); - spin_unlock_bh(&sc->sc_txbuflock); + ATH_TXBUF_RESET(bf); - list_add_tail(&bf->list, &bf_head); + /* Frame type */ - /* set up this buffer */ - ATH_TXBUF_RESET(bf); - bf->bf_frmlen = txctl->frmlen; + bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); ieee80211_is_data(fc) ? (bf->bf_state.bf_type |= BUF_DATA) : @@ -1889,121 +1847,143 @@ static int ath_tx_start_dma(struct ath_softc *sc, (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); + (sc->hw->conf.ht.enabled && + (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ? + (bf->bf_state.bf_type |= BUF_HT) : + (bf->bf_state.bf_type &= ~BUF_HT); + + bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); + + /* Crypto */ + + bf->bf_keytype = get_hw_crypto_keytype(skb); + + if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { + bf->bf_frmlen += tx_info->control.hw_key->icv_len; + bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; + } else { + bf->bf_keyix = ATH9K_TXKEYIX_INVALID; + } + + /* Rate series */ + + setup_rate_retries(sc, skb); - bf->bf_flags = txctl->flags; - bf->bf_keytype = txctl->keytype; - /* XXX: HACK! */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - rcs = tx_info_priv->rcs; bf->bf_rcs[0] = rcs[0]; bf->bf_rcs[1] = rcs[1]; bf->bf_rcs[2] = rcs[2]; bf->bf_rcs[3] = rcs[3]; - bf->bf_node = an; + + /* Assign seqno, tidno */ + + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb, bf); + + /* DMA setup */ + bf->bf_mpdu = skb; - bf->bf_buf_addr = sg_dma_address(sg); + bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + bf->bf_buf_addr = bf->bf_dmacontext; +} + +/* FIXME: tx power */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + struct scatterlist *sg, u32 n_sg, + struct ath_tx_control *txctl) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_node *an = NULL; + struct list_head bf_head; + struct ath_desc *ds; + struct ath_atx_tid *tid; + struct ath_hal *ah = sc->sc_ah; + int frm_type; + + if (tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + } + + frm_type = get_hw_packet_type(skb); + + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); /* setup descriptor */ + ds = bf->bf_desc; ds->ds_link = 0; ds->ds_data = bf->bf_buf_addr; - /* - * Save the DMA context in the first ath_buf - */ - bf->bf_dmacontext = txctl->dmacontext; + /* Formulate first tx descriptor with tx controls */ - /* - * Formulate first tx descriptor with tx controls. - */ - ath9k_hw_set11n_txdesc(ah, - ds, - bf->bf_frmlen, /* frame length */ - txctl->atype, /* Atheros packet type */ - min(txctl->txpower, (u16)60), /* txpower */ - txctl->keyix, /* key cache index */ - txctl->keytype, /* key type */ - txctl->flags); /* flags */ - ath9k_hw_filltxdesc(ah, - ds, - sg_dma_len(sg), /* segment length */ - true, /* first segment */ - (n_sg == 1) ? true : false, /* last segment */ - ds); /* first descriptor */ + ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, + bf->bf_keyix, bf->bf_keytype, bf->bf_flags); + + ath9k_hw_filltxdesc(ah, ds, + sg_dma_len(sg), /* segment length */ + true, /* first segment */ + (n_sg == 1) ? true : false, /* last segment */ + ds); /* first descriptor */ bf->bf_lastfrm = bf; - (txctl->ht) ? - (bf->bf_state.bf_type |= BUF_HT) : - (bf->bf_state.bf_type &= ~BUF_HT); - spin_lock_bh(&txq->axq_lock); + spin_lock_bh(&txctl->txq->axq_lock); - 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)) { + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) { + if (ath_aggr_query(sc, an, bf->bf_tidno)) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. */ - ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl); + ath_tx_send_ampdu(sc, tid, &bf_head, txctl); } else { /* - * Send this frame as regular when ADDBA exchange - * is neither complete nor pending. + * Send this frame as regular when ADDBA + * exchange is neither complete nor pending. */ - ath_tx_send_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txctl->txq, + tid, &bf_head); } } else { bf->bf_lastbf = bf; bf->bf_nframes = 1; - ath_buf_set_rate(sc, bf); - - if (ieee80211_is_back_req(fc)) { - /* This is required for resuming tid - * during BAR completion */ - bf->bf_tidno = txctl->tidno; - } - ath_tx_txqaddbuf(sc, txq, &bf_head); + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); } - spin_unlock_bh(&txq->axq_lock); - return 0; + + spin_unlock_bh(&txctl->txq->axq_lock); } -static void xmit_map_sg(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_tx_control *txctl) +int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl) { - struct ath_xmit_status tx_status; - struct ath_atx_tid *tid; + struct ath_buf *bf; struct scatterlist sg; - txctl->dmacontext = pci_map_single(sc->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); + /* Check if a tx buffer is available */ + + bf = ath_tx_get_buffer(sc); + if (!bf) { + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX buffers are full\n", + __func__); + return -1; + } + + ath_tx_setup_buffer(sc, bf, skb, &sg, txctl); + + /* Setup S/G */ - /* setup S/G list */ memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = txctl->dmacontext; + sg_dma_address(&sg) = bf->bf_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, txctl->dmacontext, - skb->len, PCI_DMA_TODEVICE); - - tx_status.retries = 0; - tx_status.flags = ATH_TX_ERROR; + ath_tx_start_dma(sc, bf, &sg, 1, txctl); - if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - /* Reclaim the seqno. */ - tid = ATH_AN_2_TID((struct ath_node *) - txctl->an, txctl->tidno); - DECR(tid->seq_next, IEEE80211_SEQ_MAX); - } - ath_tx_complete(sc, skb, &tx_status, txctl->an); - } + return 0; } /* Initialize TX queue and h/w */ @@ -2189,6 +2169,34 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) return qnum; } +/* Get a transmit queue, if available */ + +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_txq *txq = NULL; + int qnum; + + qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->sc_txq[qnum]; + + spin_lock_bh(&txq->axq_lock); + + /* Try to avoid running out of descriptors */ + if (txq->axq_depth >= (ATH_TXBUF - 20)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: TX queue: %d is full, depth: %d\n", + __func__, qnum, txq->axq_depth); + ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); + txq->stopped = 1; + spin_unlock_bh(&txq->axq_lock); + return NULL; + } + + spin_unlock_bh(&txq->axq_lock); + + return txq; +} + /* Update parameters for a transmit queue */ int ath_txq_update(struct ath_softc *sc, int qnum, @@ -2252,25 +2260,6 @@ int ath_cabq_update(struct ath_softc *sc) return 0; } -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) - /* - * Start DMA mapping. - * ath_tx_start_dma() will be called either synchronously - * or asynchrounsly once DMA is complete. - */ - xmit_map_sg(sc, skb, &txctl); - - /* failed packets will be dropped by the caller */ - return error; -} - /* Deferred processing of transmit interrupt */ void ath_tx_tasklet(struct ath_softc *sc) @@ -2668,6 +2657,8 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_tx_control txctl; + memset(&txctl, 0, sizeof(struct ath_tx_control)); + /* * As a temporary workaround, assign seq# here; this will likely need * to be cleaned up to work better with Beacon transmission and virtual @@ -2695,22 +2686,18 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, hdrlen); } + txctl.txq = sc->sc_cabq; + 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 { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); - dev_kfree_skb_any(skb); + if (ath_tx_start(sc, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); + goto exit; } -} + return; +exit: + dev_kfree_skb_any(skb); +} -- cgit v1.1 From 43453b3392c1ecfdd1471383ad42ba926533a722 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:14:52 +0530 Subject: ath9k: Remove SM Power Save as it is not supported now Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 7 ------ drivers/net/wireless/ath9k/xmit.c | 45 ++++++--------------------------------- 2 files changed, 6 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 21b572b..27ed084 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -415,12 +415,6 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, #define WME_AC_VO 3 /* voice */ #define WME_NUM_AC 4 -enum ATH_SM_PWRSAV{ - ATH_SM_ENABLE, - ATH_SM_PWRSAV_STATIC, - ATH_SM_PWRSAV_DYNAMIC, -}; - /* * Data transmit queue state. One of these exists for each * hardware transmit queue. Packets sent to us from above @@ -619,7 +613,6 @@ struct ath_node { struct ath_softc *an_sc; struct ath_chainmask_sel an_chainmask_sel; struct ath_node_aggr an_aggr; - u8 an_smmode; /* SM Power save mode */ u16 maxampdu; u8 mpdudensity; }; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 84219bc..4e7108a 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -575,7 +575,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) struct ath_desc *ds = bf->bf_desc; struct ath_desc *lastds = bf->bf_lastbf->bf_desc; struct ath9k_11n_rate_series series[4]; - int i, flags, rtsctsena = 0, dynamic_mimops = 0; + int i, flags, rtsctsena = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; @@ -631,18 +631,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) */ if (!rtsctsena) flags = ATH9K_TXDESC_RTSENA; - /* - * For dynamic MIMO PS, RTS needs to precede the first aggregate - * and the second aggregate should have any protection at all. - */ - if (an && an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf_isaggrburst(bf)) { - flags = ATH9K_TXDESC_RTSENA; - dynamic_mimops = 1; - } else { - flags = 0; - } - } } /* @@ -707,33 +695,14 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), bf_isshpreamble(bf)); - if (an && (an->an_smmode == ATH_SM_PWRSAV_STATIC) && - (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { - /* - * When sending to an HT node that has enabled static - * SM/MIMO power save, send at single stream rates but - * use maximum allowed transmit chains per user, - * hardware, regulatory, or country limits for - * better range. - */ + if (bf_isht(bf)) + series[i].ChSel = + ath_chainmask_sel_logic(sc, an); + else series[i].ChSel = sc->sc_tx_chainmask; - } else { - if (bf_isht(bf)) - series[i].ChSel = - ath_chainmask_sel_logic(sc, an); - else - series[i].ChSel = sc->sc_tx_chainmask; - } if (rtsctsena) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - - /* - * Set RTS for all rates if node is in dynamic powersave - * mode and we are using dual stream rates. - */ - if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG)) - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; } /* @@ -2520,10 +2489,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (tid->paused) /* check next tid to keep h/w busy */ continue; - if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) || - ((txq->axq_depth % 2) == 0)) { + if ((txq->axq_depth % 2) == 0) ath_tx_sched_aggr(sc, txq, tid); - } /* * add tid to round-robin queue if more frames -- cgit v1.1 From 102e0572d330e6cdb89a8f8fbd3999e3c67a1f9e Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:15:16 +0530 Subject: ath9k: Ensure ath_node is not NULL when updating tx chainmask Also, random indentation and whitespace cleanup. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 3 +-- drivers/net/wireless/ath9k/rc.c | 2 +- drivers/net/wireless/ath9k/recv.c | 6 ++--- drivers/net/wireless/ath9k/xmit.c | 57 ++++++++++++++++----------------------- 4 files changed, 28 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 839db231..0a0eb7c 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -489,8 +489,7 @@ int _ath_rx_indicate(struct ath_softc *sc, return 0; } -int ath_rx_subframe(struct ath_node *an, - struct sk_buff *skb, +int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, struct ath_recv_status *status) { struct ath_softc *sc = an->an_sc; diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1305873..02931a1 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -816,7 +816,7 @@ void ath_rate_detach(struct ath_rate_softc *asc) } u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11rate) + u8 dot11rate) { const struct ath_rate_table *ratetable; struct ath_rate_softc *rsc = sc->sc_rc; diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 27d6a98..80f26b4 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -356,8 +356,8 @@ static void ath_rx_timer(unsigned long data) /* Free all pending sub-frames in the re-ordering buffer */ -static void ath_rx_flush_tid(struct ath_softc *sc, - struct ath_arx_tid *rxtid, int drop) +static void ath_rx_flush_tid(struct ath_softc *sc, struct ath_arx_tid *rxtid, + int drop) { struct ath_rxbuf *rxbuf; unsigned long flag; @@ -1218,7 +1218,7 @@ void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) * (needs to be allocated when addba is received) */ - rxtid->rxbuf = NULL; + rxtid->rxbuf = NULL; setup_timer(&rxtid->timer, ath_rx_timer, (unsigned long)rxtid); spin_lock_init(&rxtid->tidlock); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 4e7108a..bd90246 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -65,11 +65,12 @@ static u32 bits_per_symbol[][2] = { * NB: must be called with txq lock held */ -static void ath_tx_txqaddbuf(struct ath_softc *sc, - struct ath_txq *txq, struct list_head *head) +static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *head) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; + /* * Insert the frame on the outbound list and * pass it on to the hardware. @@ -360,6 +361,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, if (bf_isxretried(bf)) tx_status.flags |= ATH_TX_XRETRY; } + /* Unmap this frame */ pci_unmap_single(sc->pdev, bf->bf_dmacontext, @@ -497,8 +499,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) /* Update block ack window */ -static void ath_tx_update_baw(struct ath_softc *sc, - struct ath_atx_tid *tid, int seqno) +static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + int seqno) { int index, cindex; @@ -522,12 +524,8 @@ static void ath_tx_update_baw(struct ath_softc *sc, * half_gi - to use 4us v/s 3.6 us for symbol time */ -static u32 ath_pkt_duration(struct ath_softc *sc, - u8 rix, - struct ath_buf *bf, - int width, - int half_gi, - bool shortPreamble) +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, + int width, int half_gi, bool shortPreamble) { const struct ath9k_rate_table *rt = sc->sc_currates; u32 nbits, nsymbits, duration, nsymbols; @@ -541,11 +539,8 @@ static u32 ath_pkt_duration(struct ath_softc *sc, * for legacy rates, use old function to compute packet duration */ if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, - rt, - pktlen, - rix, - shortPreamble); + return ath9k_hw_computetxtime(sc->sc_ah, rt, pktlen, rix, + shortPreamble); /* * find number of symbols: PLCP + data */ @@ -563,6 +558,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, */ streams = HT_RC_2_STREAMS(rc); duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + return duration; } @@ -578,7 +574,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) int i, flags, rtsctsena = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; - u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; @@ -646,7 +641,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_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) { + if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) { /* * Ensure that in the case of SM Dynamic power save * while we are bursting the second aggregate the @@ -659,8 +654,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * CTS transmit rate is derived from the transmit rate * by looking in the h/w rate table. We must also factor * in whether or not a short preamble is to be used. + * NB: cix is set above where RTS/CTS is enabled */ - /* NB: cix is set above where RTS/CTS is enabled */ BUG_ON(cix == 0xff); ctsrate = rt->info[cix].rateCode | (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); @@ -689,15 +684,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ? ATH9K_RATESERIES_HALFGI : 0); - series[i].PktDuration = ath_pkt_duration( - sc, rix, bf, - (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, - (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), - bf_isshpreamble(bf)); + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, + (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), + bf_isshpreamble(bf)); - if (bf_isht(bf)) - series[i].ChSel = - ath_chainmask_sel_logic(sc, an); + if (bf_isht(bf) && an) + series[i].ChSel = ath_chainmask_sel_logic(sc, an); else series[i].ChSel = sc->sc_tx_chainmask; @@ -748,6 +741,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) ctsrate, ctsduration, series, 4, flags); + if (sc->sc_config.ath_aggr_prot && flags) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -1238,26 +1232,21 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; - int i; - int npend = 0; + int i, status, npend = 0; - /* XXX return value */ 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]); - /* The TxDMA may not really be stopped. * Double check the hal tx pending count */ npend += ath9k_hw_numtxpending(ah, - sc->sc_txq[i].axq_qnum); + sc->sc_txq[i].axq_qnum); } } } if (npend) { - int status; - /* TxDMA not stopped, reset the hal */ DPRINTF(sc, ATH_DBG_XMIT, "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); @@ -1360,6 +1349,7 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */ ath_buf_set_rate(sc, bf); ath_tx_txqaddbuf(sc, txctl->txq, bf_head); + return 0; } @@ -1380,7 +1370,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, u16 aggr_limit, legacy = 0, maxampdu; int i; - skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); tx_info_priv = (struct ath_tx_info_priv *) -- cgit v1.1 From a37c2c79404940dfc5e88c851c3de5328975b1a9 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:15:40 +0530 Subject: ath9k: Use bitfields to store tid's state in a single variable Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 8 ++++--- drivers/net/wireless/ath9k/rc.c | 4 ++-- drivers/net/wireless/ath9k/xmit.c | 49 ++++++++++++++++----------------------- 3 files changed, 27 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 27ed084..d89dd03 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -447,6 +447,10 @@ struct ath_txq { struct list_head axq_acq; }; +#define AGGR_CLEANUP BIT(1) +#define AGGR_ADDBA_COMPLETE BIT(2) +#define AGGR_ADDBA_PROGRESS BIT(3) + /* per TID aggregate tx state for a destination */ struct ath_atx_tid { struct list_head list; /* round-robin tid entry */ @@ -462,9 +466,7 @@ struct ath_atx_tid { int baw_tail; /* next unused tx buffer slot */ int sched; int paused; - int cleanup_inprogress; - u32 addba_exchangecomplete:1; - int32_t addba_exchangeinprogress; + u8 state; int addba_exchangeattempts; }; diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 02931a1..ff283dc 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1909,8 +1909,8 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, state = si->ampdu_mlme.tid_state_tx[tidno]; if (state & HT_ADDBA_RECEIVED_MSK) { - txtid->addba_exchangecomplete = 1; - txtid->addba_exchangeinprogress = 0; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->baw_size = buffersize; DPRINTF(sc, ATH_DBG_AGGR, diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index bd90246..f41030d 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -125,13 +125,13 @@ static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate) /* Check if it's okay to send out aggregates */ -static int ath_aggr_query(struct ath_softc *sc, - struct ath_node *an, u8 tidno) +static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) { struct ath_atx_tid *tid; tid = ATH_AN_2_TID(an, tidno); - if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress) + if (tid->state & AGGR_ADDBA_COMPLETE || + tid->state & AGGR_ADDBA_PROGRESS) return 1; else return 0; @@ -886,7 +886,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, /* transmit completion */ } else { - if (!tid->cleanup_inprogress && + if (!(tid->state & AGGR_CLEANUP) && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, bf); @@ -1014,16 +1014,16 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, bf = bf_next; } - if (tid->cleanup_inprogress) { + if (tid->state & AGGR_CLEANUP) { /* check to see if we're done with cleaning the h/w queue */ spin_lock_bh(&txq->axq_lock); if (tid->baw_head == tid->baw_tail) { - tid->addba_exchangecomplete = 0; + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; spin_unlock_bh(&txq->axq_lock); - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; /* send buffered frames as singles */ ath_tx_flush_tid(sc, tid); @@ -2335,17 +2335,8 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, /* ADDBA exchange must be completed before sending aggregates */ txtid = ATH_AN_2_TID(an, tidno); - if (txtid->addba_exchangecomplete) - return AGGR_EXCHANGE_DONE; - - if (txtid->cleanup_inprogress) - return AGGR_CLEANUP_PROGRESS; - - if (txtid->addba_exchangeinprogress) - return AGGR_EXCHANGE_PROGRESS; - - if (!txtid->addba_exchangecomplete) { - if (!txtid->addba_exchangeinprogress && + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + if (!(txtid->state & AGGR_ADDBA_PROGRESS) && (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { txtid->addba_exchangeattempts++; return AGGR_REQUIRED; @@ -2367,7 +2358,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); - txtid->addba_exchangeinprogress = 1; + txtid->state |= AGGR_ADDBA_PROGRESS; ath_tx_pause_tid(sc, txtid); } @@ -2401,10 +2392,10 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__); - if (txtid->cleanup_inprogress) /* cleanup is in progress */ + if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */ return; - if (!txtid->addba_exchangecomplete) { + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->addba_exchangeattempts = 0; return; } @@ -2434,9 +2425,9 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) if (txtid->baw_head != txtid->baw_tail) { spin_unlock_bh(&txq->axq_lock); - txtid->cleanup_inprogress = true; + txtid->state |= AGGR_CLEANUP; } else { - txtid->addba_exchangecomplete = 0; + txtid->state &= ~AGGR_ADDBA_COMPLETE; txtid->addba_exchangeattempts = 0; spin_unlock_bh(&txq->axq_lock); ath_tx_flush_tid(sc, txtid); @@ -2527,16 +2518,16 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->baw_head = tid->baw_tail = 0; tid->sched = false; tid->paused = false; - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; INIT_LIST_HEAD(&tid->buf_q); acno = TID_TO_WME_AC(tidno); tid->ac = &an->an_aggr.tx.ac[acno]; /* ADDBA state */ - tid->addba_exchangecomplete = 0; - tid->addba_exchangeinprogress = 0; - tid->addba_exchangeattempts = 0; + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_ADDBA_PROGRESS; + tid->addba_exchangeattempts = 0; } /* @@ -2596,9 +2587,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) list_del(&tid->list); tid->sched = false; ath_tid_drain(sc, txq, tid); - tid->addba_exchangecomplete = 0; + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; } } -- cgit v1.1 From 5640b08ef7e88b606c740e746cb77bc97d78508e Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:16:06 +0530 Subject: ath9k: Revamp VAP management Remove the internal VAP management routines and embed ath_vap in mac80211's driver private area provided in ieee80211_vif. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 40 +++++++++---- drivers/net/wireless/ath9k/core.c | 116 +----------------------------------- drivers/net/wireless/ath9k/core.h | 16 +---- drivers/net/wireless/ath9k/main.c | 80 +++++++++---------------- drivers/net/wireless/ath9k/rc.c | 8 ++- 5 files changed, 67 insertions(+), 193 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index b36d3fb..d186cd4 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -152,12 +152,14 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) struct ath_vap *avp; struct sk_buff *skb; struct ath_txq *cabq; + struct ieee80211_vif *vif; struct ieee80211_tx_info *info; int cabq_depth; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + avp = (void *)vif->drv_priv; cabq = sc->sc_cabq; if (avp->av_bcbuf == NULL) { @@ -174,7 +176,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) PCI_DMA_TODEVICE); } - skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); bf->bf_mpdu = skb; if (skb == NULL) return NULL; @@ -196,7 +198,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) skb_end_pointer(skb) - skb->head, PCI_DMA_TODEVICE); - skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); /* * if the CABQ traffic from previous DTIM is pending and the current @@ -232,7 +234,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) */ while (skb) { ath_tx_cabq(sc, skb); - skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); } return bf; @@ -244,13 +246,16 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) */ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; if (avp->av_bcbuf == NULL) { DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", @@ -300,14 +305,17 @@ int ath_beaconq_setup(struct ath_hal *ah) */ int ath_beacon_alloc(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_vap *avp; struct ieee80211_hdr *hdr; struct ath_buf *bf; struct sk_buff *skb; __le64 tstamp; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; /* Allocate a beacon descriptor if we haven't done so. */ if (!avp->av_bcbuf) { @@ -363,7 +371,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ - skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n", __func__); @@ -652,15 +660,21 @@ void ath_bstuck_process(struct ath_softc *sc) */ void ath_beacon_config(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_hal *ah = sc->sc_ah; struct ath_beacon_config conf; + struct ath_vap *avp; enum ath9k_opmode av_opmode; u32 nexttbtt, intval; - if (if_id != ATH_IF_ID_ANY) - av_opmode = sc->sc_vaps[if_id]->av_opmode; - else + if (if_id != ATH_IF_ID_ANY) { + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + avp = (void *)vif->drv_priv; + av_opmode = avp->av_opmode; + } else { av_opmode = sc->sc_ah->ah_opmode; + } memset(&conf, 0, sizeof(struct ath_beacon_config)); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 689a280..aa1f1fc 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -14,8 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - /* Implementation of the main "ATH" layer. */ - #include "core.h" #include "regd.h" @@ -641,114 +639,6 @@ static void ath_ani_calibrate(unsigned long data) mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } -/******************/ -/* VAP management */ -/******************/ - -int ath_vap_attach(struct ath_softc *sc, - int if_id, - struct ieee80211_vif *if_data, - enum ath9k_opmode opmode) -{ - struct ath_vap *avp; - - if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid interface id = %u\n", __func__, if_id); - return -EINVAL; - } - - switch (opmode) { - case ATH9K_M_STA: - case ATH9K_M_IBSS: - case ATH9K_M_MONITOR: - break; - case ATH9K_M_HOSTAP: - /* XXX not right, beacon buffer is allocated on RUN trans */ - if (list_empty(&sc->sc_bbuf)) - return -ENOMEM; - break; - default: - return -EINVAL; - } - - /* create ath_vap */ - avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL); - if (avp == NULL) - return -ENOMEM; - - memset(avp, 0, sizeof(struct ath_vap)); - avp->av_if_data = if_data; - /* Set the VAP opmode */ - avp->av_opmode = opmode; - avp->av_bslot = -1; - - if (opmode == ATH9K_M_HOSTAP) - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); - - sc->sc_vaps[if_id] = avp; - sc->sc_nvaps++; - /* Set the device opmode */ - sc->sc_ah->ah_opmode = opmode; - - /* default VAP configuration */ - avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; - avp->av_config.av_fixed_retryset = 0x03030303; - - return 0; -} - -int ath_vap_detach(struct ath_softc *sc, int if_id) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - - 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; - } - - /* - * Quiesce the hardware while we remove the vap. In - * particular we need to reclaim all references to the - * vap state by any frames pending on the tx queues. - * - * XXX can we do this w/o affecting other vap's? - */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* stop xmit side */ - ath_stoprecv(sc); /* stop recv side */ - ath_flushrecv(sc); /* flush recv queue */ - - kfree(avp); - sc->sc_vaps[if_id] = NULL; - sc->sc_nvaps--; - - return 0; -} - -int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config) -{ - struct ath_vap *avp; - - if (if_id >= ATH_BCBUF) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid interface id = %u\n", __func__, if_id); - return -EINVAL; - } - - avp = sc->sc_vaps[if_id]; - ASSERT(avp != NULL); - - if (avp) - memcpy(&avp->av_config, if_config, sizeof(avp->av_config)); - - return 0; -} - /********/ /* Core */ /********/ @@ -1356,14 +1246,10 @@ void ath_deinit(struct ath_softc *sc) /* Node Management */ /*******************/ -void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, int if_id) +void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) { - struct ath_vap *avp; struct ath_node *an; - avp = sc->sc_vaps[if_id]; - ASSERT(avp != NULL); - an = (struct ath_node *)sta->drv_priv; if (sc->sc_flags & SC_OP_TXAGGR) diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index d89dd03..c03acf7 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -635,8 +635,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_newassoc(struct ath_softc *sc, struct ath_node *node, int isnew, int isuapsd); -void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, - int if_id); +void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta); void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta); /*******************/ @@ -701,23 +700,14 @@ struct ath_vap_config { /* driver-specific vap state */ struct ath_vap { - struct ieee80211_vif *av_if_data; + int av_bslot; /* beacon slot index */ enum ath9k_opmode av_opmode; /* VAP operational mode */ struct ath_buf *av_bcbuf; /* beacon buffer */ struct ath_tx_control av_btxctl; /* txctl information for beacon */ - int av_bslot; /* beacon slot index */ struct ath_vap_config av_config;/* vap configuration parameters*/ struct ath_rate_node *rc_node; }; -int ath_vap_attach(struct ath_softc *sc, - int if_id, - struct ieee80211_vif *if_data, - 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); - /*********************/ /* Antenna diversity */ /*********************/ @@ -925,7 +915,7 @@ struct ath_softc { u8 sc_nbcnvaps; /* # of vaps sending beacons */ u16 sc_nvaps; /* # of active virtual ap's */ - struct ath_vap *sc_vaps[ATH_BCBUF]; + struct ieee80211_vif *sc_vaps[ATH_BCBUF]; u8 sc_mcastantenna; u8 sc_defant; /* current default antenna */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0a0eb7c..0194e44 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -162,7 +162,7 @@ static int ath_key_config(struct ath_softc *sc, if (!sc->sc_vaps[0]) return -EIO; - vif = sc->sc_vaps[0]->av_if_data; + vif = sc->sc_vaps[0]; opmode = vif->type; /* @@ -313,11 +313,12 @@ static void ath9k_ht_conf(struct ath_softc *sc, } static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_channel *curchan = hw->conf.channel; - struct ath_vap *avp; + struct ath_vap *avp = (void *)vif->drv_priv; int pos; if (bss_conf->assoc) { @@ -325,13 +326,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, __func__, bss_conf->aid); - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } - /* New association, store aid */ if (avp->av_opmode == ATH9K_M_STA) { sc->sc_curaid = bss_conf->aid; @@ -906,6 +900,7 @@ static int ath_attach(u16 devid, hw->queues = 4; hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vap); /* Register rate control */ hw->rate_control_algorithm = "ath9k_rate_control"; @@ -1091,7 +1086,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - int error, ic_opmode = 0; + struct ath_vap *avp = (void *)conf->vif->drv_priv; + int ic_opmode = 0; /* Support only vap for now */ @@ -1119,13 +1115,22 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, __func__, ic_opmode); - error = ath_vap_attach(sc, 0, conf->vif, ic_opmode); - if (error) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to attach vap, error: %d\n", - __func__, error); - return error; - } + /* Set the VAP opmode */ + avp->av_opmode = ic_opmode; + avp->av_bslot = -1; + + if (ic_opmode == ATH9K_M_HOSTAP) + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + + sc->sc_vaps[0] = conf->vif; + sc->sc_nvaps++; + + /* Set the device opmode */ + sc->sc_ah->ah_opmode = ic_opmode; + + /* default VAP configuration */ + avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; + avp->av_config.av_fixed_retryset = 0x03030303; if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ @@ -1141,27 +1146,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - struct ath_vap *avp; - int error; + struct ath_vap *avp = (void *)conf->vif->drv_priv; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } - #ifdef CONFIG_SLOW_ANT_DIV ath_slow_ant_div_stop(&sc->sc_antdiv); #endif /* Stop ANI */ del_timer_sync(&sc->sc_ani.timer); - /* Update ratectrl */ - ath_rate_newstate(sc, avp); - /* Reclaim beacon resources */ if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { @@ -1169,16 +1163,10 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_beacon_return(sc, avp); } - /* 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_flags &= ~SC_OP_BEACONS; - error = ath_vap_detach(sc, 0); - if (error) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to detach vap, error: %d\n", - __func__, error); + sc->sc_vaps[0] = NULL; + sc->sc_nvaps--; } static int ath9k_config(struct ieee80211_hw *hw, u32 changed) @@ -1226,17 +1214,10 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; + struct ath_vap *avp = (void *)vif->drv_priv; u32 rfilt = 0; int error, i; - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return -EINVAL; - } - /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ if (vif->type == NL80211_IFTYPE_AP && @@ -1317,7 +1298,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { + if ((avp->av_opmode != ATH9K_M_STA)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, @@ -1366,9 +1347,6 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, __func__, sc->rx_filter); } -/* Only a single interface is currently supported, - so pass 0 as the interface id to ath_node_attach */ - static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, @@ -1378,7 +1356,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, switch (cmd) { case STA_NOTIFY_ADD: - ath_node_attach(sc, sta, 0); + ath_node_attach(sc, sta); break; case STA_NOTIFY_REMOVE: ath_node_detach(sc, sta); @@ -1496,7 +1474,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", __func__, bss_conf->assoc); - ath9k_bss_assoc_info(sc, bss_conf); + ath9k_bss_assoc_info(sc, vif, bss_conf); } } diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index ff283dc..fecc839 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -2042,12 +2042,18 @@ static void ath_rate_free(void *priv) static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { + struct ieee80211_vif *vif; struct ath_softc *sc = priv; - struct ath_vap *avp = sc->sc_vaps[0]; + struct ath_vap *avp; struct ath_rate_node *rate_priv; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + vif = sc->sc_vaps[0]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; + rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, -- cgit v1.1 From f1dc56003b23d2d5bb5a756de6b1633a76c9e697 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:16:30 +0530 Subject: ath9k: Refactor hw.c Split hw.c into more manageable files: ani.c calib.c eeprom.c mac.c Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/Makefile | 4 + drivers/net/wireless/ath9k/ani.c | 854 ++++ drivers/net/wireless/ath9k/ath9k.h | 376 +- drivers/net/wireless/ath9k/calib.c | 930 ++++ drivers/net/wireless/ath9k/eeprom.c | 1605 ++++++ drivers/net/wireless/ath9k/hw.c | 9644 +++++++++-------------------------- drivers/net/wireless/ath9k/hw.h | 2 +- drivers/net/wireless/ath9k/mac.c | 1031 ++++ drivers/net/wireless/ath9k/phy.c | 10 +- 9 files changed, 7179 insertions(+), 7277 deletions(-) create mode 100644 drivers/net/wireless/ath9k/ani.c create mode 100644 drivers/net/wireless/ath9k/calib.c create mode 100644 drivers/net/wireless/ath9k/eeprom.c create mode 100644 drivers/net/wireless/ath9k/mac.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index a641151..c58cfde 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -1,4 +1,8 @@ ath9k-y += hw.o \ + eeprom.o \ + mac.o \ + calib.o \ + ani.o \ phy.o \ regd.o \ beacon.o \ diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c new file mode 100644 index 0000000..ada12e9 --- /dev/null +++ b/drivers/net/wireless/ath9k/ani.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { + if (ahp->ah_ani[i].c.channel == chan->channel) + return i; + if (ahp->ah_ani[i].c.channel == 0) { + ahp->ah_ani[i].c.channel = chan->channel; + ahp->ah_ani[i].c.channelFlags = chan->channelFlags; + return i; + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "No more channel states left. Using channel 0\n"); + + return 0; +} + +static bool ath9k_hw_ani_control(struct ath_hal *ah, + enum ath9k_ani_cmd cmd, int param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState = ahp->ah_curani; + + switch (cmd & ahp->ah_ani_function) { + case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ + u32 level = param; + + if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: level out of range (%u > %u)\n", + __func__, level, + (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)); + return false; + } + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, + ahp->ah_totalSizeDesired[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_LOW, + ahp->ah_coarseLow[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_HIGH, + ahp->ah_coarseHigh[level]); + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, + ahp->ah_firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ + const int m1ThreshLow[] = { 127, 50 }; + const int m2ThreshLow[] = { 127, 40 }; + const int m1Thresh[] = { 127, 0x4d }; + const int m2Thresh[] = { 127, 0x40 }; + const int m2CountThr[] = { 31, 16 }; + const int m2CountThrLow[] = { 63, 48 }; + u32 on = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, + m2Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, + m2CountThr[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, + m2CountThrLow[on]); + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, + m2Thresh[on]); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + else + REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + + if (!on != aniState->ofdmWeakSigDetectOff) { + if (on) + ahp->ah_stats.ast_ani_ofdmon++; + else + ahp->ah_stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + } + break; + } + case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ + const int weakSigThrCck[] = { 8, 6 }; + u32 high = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, + weakSigThrCck[high]); + if (high != aniState->cckWeakSigThreshold) { + if (high) + ahp->ah_stats.ast_ani_cckhigh++; + else + ahp->ah_stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + } + break; + } + case ATH9K_ANI_FIRSTEP_LEVEL:{ + const int firstep[] = { 0, 4, 8 }; + u32 level = param; + + if (level >= ARRAY_SIZE(firstep)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: level out of range (%u > %u)\n", + __func__, level, + (unsigned) ARRAY_SIZE(firstep)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, + firstep[level]); + if (level > aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ + const int cycpwrThr1[] = + { 2, 4, 6, 8, 10, 12, 14, 16 }; + u32 level = param; + + if (level >= ARRAY_SIZE(cycpwrThr1)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: level out of range (%u > %u)\n", + __func__, level, + (unsigned) + ARRAY_SIZE(cycpwrThr1)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, + cycpwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case ATH9K_ANI_PRESENT: + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: invalid cmd %u\n", __func__, cmd); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, aniState->firstepLevel, + aniState->listenTime); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + aniState->cycleCount, aniState->ofdmPhyErrCount, + aniState->cckPhyErrCount); + + return true; +} + +static void ath9k_hw_update_mibstats(struct ath_hal *ah, + struct ath9k_mib_stats *stats) +{ + stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += REG_READ(ah, AR_RTS_OK); + stats->beacons += REG_READ(ah, AR_BEACON_CNT); +} + +static void ath9k_ani_restart(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + + aniState->listenTime = 0; + if (ahp->ah_hasHwPhyCounters) { + if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { + aniState->ofdmPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "OFDM Trigger is too high for hw counters\n"); + } else { + aniState->ofdmPhyErrBase = + AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + } + if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { + aniState->cckPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); + } else { + aniState->cckPhyErrBase = + AR_PHY_COUNTMAX - aniState->cckTrigHigh; + } + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: Writing ofdmbase=%u cckbase=%u\n", + __func__, aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + } + aniState->ofdmPhyErrCount = 0; + aniState->cckPhyErrCount = 0; +} + +static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; + struct ar5416AniState *aniState; + enum wireless_mode mode; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + + if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel + 1)) { + return; + } + } + + if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrHigh) { + if (!aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false)) { + ath9k_hw_ani_control(ah, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + return; + } + } + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true); + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } else { + mode = ath9k_hw_chan2wmode(ah, chan); + if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (!aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false); + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + return; + } + } +} + +static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; + struct ar5416AniState *aniState; + enum wireless_mode mode; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrLow) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } else { + mode = ath9k_hw_chan2wmode(ah, chan); + if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + } + } +} + +static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + int32_t rssi; + + aniState = ahp->ah_curani; + + if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1)) + return; + } + } else { + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrHigh) { + /* XXX: Handle me */ + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true) == true) + return; + } + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } else { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } + } + + if (aniState->spurImmunityLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel - 1)) + return; + } + + if (aniState->noiseImmunityLevel > 0) { + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel - 1); + return; + } +} + +static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + u32 txFrameCount, rxFrameCount, cycleCount; + int32_t listenTime; + + txFrameCount = REG_READ(ah, AR_TFCNT); + rxFrameCount = REG_READ(ah, AR_RFCNT); + cycleCount = REG_READ(ah, AR_CCCNT); + + aniState = ahp->ah_curani; + if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { + + listenTime = 0; + ahp->ah_stats.ast_ani_lzero++; + } else { + int32_t ccdelta = cycleCount - aniState->cycleCount; + int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; + int32_t tfdelta = txFrameCount - aniState->txFrameCount; + listenTime = (ccdelta - rfdelta - tfdelta) / 44000; + } + aniState->cycleCount = cycleCount; + aniState->txFrameCount = txFrameCount; + aniState->rxFrameCount = rxFrameCount; + + return listenTime; +} + +void ath9k_ani_reset(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + struct ath9k_channel *chan = ah->ah_curchan; + int index; + + if (!DO_ANI(ah)) + return; + + index = ath9k_hw_get_ani_channel_idx(ah, chan); + aniState = &ahp->ah_ani[index]; + ahp->ah_curani = aniState; + + if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA + && ah->ah_opmode != ATH9K_M_IBSS) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: Reset ANI state opmode %u\n", __func__, + ah->ah_opmode); + ahp->ah_stats.ast_ani_reset++; + + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !ATH9K_ANI_USE_OFDM_WEAK_SIG); + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + ATH9K_ANI_CCK_WEAK_SIG_THR); + + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + + if (ah->ah_opmode == ATH9K_M_HOSTAP) { + ahp->ah_curani->ofdmTrigHigh = + ah->ah_config.ofdm_trig_high; + ahp->ah_curani->ofdmTrigLow = + ah->ah_config.ofdm_trig_low; + ahp->ah_curani->cckTrigHigh = + ah->ah_config.cck_trig_high; + ahp->ah_curani->cckTrigLow = + ah->ah_config.cck_trig_low; + } + ath9k_ani_restart(ah); + return; + } + + if (aniState->noiseImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + if (aniState->spurImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + if (aniState->cckWeakSigThreshold) + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + if (aniState->firstepLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + if (ahp->ah_hasHwPhyCounters) { + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & + ~ATH9K_RX_FILTER_PHYERR); + ath9k_ani_restart(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + } else { + ath9k_ani_restart(ah); + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + } +} + +void ath9k_hw_ani_monitor(struct ath_hal *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + int32_t listenTime; + + aniState = ahp->ah_curani; + ahp->ah_stats.ast_nodestats = *stats; + + listenTime = ath9k_hw_ani_get_listen_time(ah); + if (listenTime < 0) { + ahp->ah_stats.ast_ani_lneg++; + ath9k_ani_restart(ah); + return; + } + + aniState->listenTime += listenTime; + + if (ahp->ah_hasHwPhyCounters) { + u32 phyCnt1, phyCnt2; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + + if (phyCnt1 < aniState->ofdmPhyErrBase || + phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt1 < aniState->ofdmPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + __func__, phyCnt1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, + AR_PHY_ERR_OFDM_TIMING); + } + if (phyCnt2 < aniState->cckPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "%s: phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + __func__, phyCnt2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, + AR_PHY_ERR_CCK_TIMING); + } + return; + } + + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + } + + if (!DO_ANI(ah)) + return; + + if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + aniState->ofdmTrigLow / 1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + aniState->cckTrigLow / 1000) + ath9k_hw_ani_lower_immunity(ah); + ath9k_ani_restart(ah); + } else if (aniState->listenTime > ahp->ah_aniPeriod) { + if (aniState->ofdmPhyErrCount > aniState->listenTime * + aniState->ofdmTrigHigh / 1000) { + ath9k_hw_ani_ofdm_err_trigger(ah); + ath9k_ani_restart(ah); + } else if (aniState->cckPhyErrCount > + aniState->listenTime * aniState->cckTrigHigh / + 1000) { + ath9k_hw_ani_cck_err_trigger(ah); + ath9k_ani_restart(ah); + } + } +} + +bool ath9k_hw_phycounters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ahp->ah_hasHwPhyCounters ? true : false; +} + +void ath9k_enable_mib_counters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + REG_WRITE(ah, AR_MIBC, + ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) + & 0x0f); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); +} + +void ath9k_hw_disable_mib_counters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); + + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); +} + +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt) +{ + static u32 cycles, rx_clear, rx_frame, tx_frame; + u32 good = 1; + + u32 rc = REG_READ(ah, AR_RCCNT); + u32 rf = REG_READ(ah, AR_RFCNT); + u32 tf = REG_READ(ah, AR_TFCNT); + u32 cc = REG_READ(ah, AR_CCCNT); + + if (cycles == 0 || cycles > cc) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "%s: cycle counter wrap. ExtBusy = 0\n", + __func__); + good = 0; + } else { + u32 cc_d = cc - cycles; + u32 rc_d = rc - rx_clear; + u32 rf_d = rf - rx_frame; + u32 tf_d = tf - tx_frame; + + if (cc_d != 0) { + *rxc_pcnt = rc_d * 100 / cc_d; + *rxf_pcnt = rf_d * 100 / cc_d; + *txf_pcnt = tf_d * 100 / cc_d; + } else { + good = 0; + } + } + + cycles = cc; + rx_frame = rf; + rx_clear = rc; + tx_frame = tf; + + return good; +} + +/* + * Process a MIB interrupt. We may potentially be invoked because + * any of the MIB counters overflow/trigger so don't assume we're + * here because a PHY error counter triggered. + */ +void ath9k_hw_procmibevent(struct ath_hal *ah, + const struct ath9k_node_stats *stats) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 phyCnt1, phyCnt2; + + /* Reset these counters regardless */ + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) + REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); + + /* Clear the mib counters and save them in the stats */ + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + ahp->ah_stats.ast_nodestats = *stats; + + if (!DO_ANI(ah)) + return; + + /* NB: these are not reset-on-read */ + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || + ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { + struct ar5416AniState *aniState = ahp->ah_curani; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + + /* + * NB: figure out which counter triggered. If both + * trigger we'll only deal with one as the processing + * clobbers the error counter so the trigger threshold + * check will never be true. + */ + if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) + ath9k_hw_ani_ofdm_err_trigger(ah); + if (aniState->cckPhyErrCount > aniState->cckTrigHigh) + ath9k_hw_ani_cck_err_trigger(ah); + /* NB: always restart to insure the h/w counters are reset */ + ath9k_ani_restart(ah); + } +} + +void ath9k_hw_ani_setup(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; + const int coarseHigh[] = { -14, -14, -14, -14, -12 }; + const int coarseLow[] = { -64, -64, -64, -64, -70 }; + const int firpwr[] = { -78, -78, -78, -78, -80 }; + + for (i = 0; i < 5; i++) { + ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; + ahp->ah_coarseHigh[i] = coarseHigh[i]; + ahp->ah_coarseLow[i] = coarseLow[i]; + ahp->ah_firpwr[i] = firpwr[i]; + } +} + +void ath9k_hw_ani_attach(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); + + ahp->ah_hasHwPhyCounters = 1; + + memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); + for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { + ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; + ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; + ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; + ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; + ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; + ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; + ahp->ah_ani[i].ofdmWeakSigDetectOff = + !ATH9K_ANI_USE_OFDM_WEAK_SIG; + ahp->ah_ani[i].cckWeakSigThreshold = + ATH9K_ANI_CCK_WEAK_SIG_THR; + ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + if (ahp->ah_hasHwPhyCounters) { + ahp->ah_ani[i].ofdmPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; + ahp->ah_ani[i].cckPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; + } + } + if (ahp->ah_hasHwPhyCounters) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ahp->ah_ani[0].ofdmPhyErrBase); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ahp->ah_ani[0].cckPhyErrBase); + + REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); + ath9k_enable_mib_counters(ah); + } + ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; + if (ah->ah_config.enable_ani) + ahp->ah_procPhyErr |= HAL_PROCESS_ANI; +} + +void ath9k_hw_ani_detach(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); + + if (ahp->ah_hasHwPhyCounters) { + ath9k_hw_disable_mib_counters(ah); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); + } +} diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index a6063de..3a180ce 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -828,195 +828,251 @@ struct chan_centers { u16 ext_center; }; -int ath_hal_getcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 *result); -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode); -void ath9k_hw_detach(struct ath_hal *ah); -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error); -bool ath9k_regd_init_channels(struct ath_hal *ah, - u32 maxchans, u32 *nchans, - u8 *regclassids, - u32 maxregids, u32 *nregids, - u16 cc, - bool enableOutdoor, - bool enableExtendedChannels); +/* Helpers */ + +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan); +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val); +u32 ath9k_hw_reverse_bits(u32 val, u32 n); +bool ath9k_get_channel_edges(struct ath_hal *ah, + u16 flags, u16 *low, + u16 *high); +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + const struct ath9k_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble); 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, - struct ath9k_channel *chan, +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers); + +/* Attach, Detach */ + +const char *ath9k_hw_probe(u16 vendorid, u16 devid); +void ath9k_hw_detach(struct ath_hal *ah); +struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *error); +void ath9k_hw_rfdetach(struct ath_hal *ah); + + +/* HW Reset */ + +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, - int *status); -bool ath9k_hw_phy_disable(struct ath_hal *ah); -void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone); -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan); -bool ath9k_hw_calibrate(struct ath_hal *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal, - bool *isCalDone); -s16 ath9k_hw_getchan_noise(struct ath_hal *ah, - struct ath9k_channel *chan); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId); -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId); -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); -void ath9k_hw_reset_tsf(struct ath_hal *ah); -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, - const u8 *mac); -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, - u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, - int xorKey); -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, - u32 setting); -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); -bool ath9k_hw_intrpend(struct ath_hal *ah); -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); -bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, - bool bIncTrigLevel); -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats); -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); -bool ath9k_hw_phycounters(struct ath_hal *ah); + bool bChannelChange, int *status); + +/* Key Cache Management */ + bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry); -bool ath9k_hw_getcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 *result); -bool ath9k_hw_setcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 setting, - int *status); -u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); -bool ath9k_hw_setbssidmask(struct ath_hal *ah, - const u8 *mask); +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac); +bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac, int xorKey); +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); + +/* Power Management */ + bool ath9k_hw_setpower(struct ath_hal *ah, enum ath9k_power_mode mode); -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); -u64 ath9k_hw_gettsf64(struct ath_hal *ah); +void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); + +/* Beacon timers */ + +void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period); +void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, + const struct ath9k_beacon_state *bs); + +/* Rate table */ + +const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, + u32 mode); + +/* HW Capabilities */ + +bool ath9k_hw_fill_cap_info(struct ath_hal *ah); +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result); +bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status); + +/* GPIO / RFKILL / Antennae */ + +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); +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 val); +#ifdef CONFIG_RFKILL +void ath9k_enable_rfkill(struct ath_hal *ah); +#endif +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg); u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); bool ath9k_hw_setantennaswitch(struct ath_hal *ah, enum ath9k_ant_setting settings, struct ath9k_channel *chan, u8 *tx_chainmask, u8 *rx_chainmask, u8 *antenna_cfgd); -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); -int ath9k_hw_select_antconfig(struct ath_hal *ah, - u32 cfg); -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp); + +/* General Operation */ + +u32 ath9k_hw_getrxfilter(struct ath_hal *ah); +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); +bool ath9k_hw_phy_disable(struct ath_hal *ah); +bool ath9k_hw_disable(struct ath_hal *ah); +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); +void ath9k_hw_setopmode(struct ath_hal *ah); +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1); +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask); +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId); +u64 ath9k_hw_gettsf64(struct ath_hal *ah); +void ath9k_hw_reset_tsf(struct ath_hal *ah); +bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting); +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); + +/* Regulatory */ + +bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); +struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah, + const struct ath9k_channel *c); +u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); +u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, + struct ath9k_channel *chan); +bool ath9k_regd_init_channels(struct ath_hal *ah, + u32 maxchans, u32 *nchans, u8 *regclassids, + u32 maxregids, u32 *nregids, u16 cc, + bool enableOutdoor, bool enableExtendedChannels); + +/* ANI */ + +void ath9k_ani_reset(struct ath_hal *ah); +void ath9k_hw_ani_monitor(struct ath_hal *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan); +bool ath9k_hw_phycounters(struct ath_hal *ah); +void ath9k_enable_mib_counters(struct ath_hal *ah); +void ath9k_hw_disable_mib_counters(struct ath_hal *ah); +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt); +void ath9k_hw_procmibevent(struct ath_hal *ah, + const struct ath9k_node_stats *stats); +void ath9k_hw_ani_setup(struct ath_hal *ah); +void ath9k_hw_ani_attach(struct ath_hal *ah); +void ath9k_hw_ani_detach(struct ath_hal *ah); + +/* Calibration */ + +void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, + bool *isCalDone); +void ath9k_hw_start_nfcal(struct ath_hal *ah); +void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan); +int16_t ath9k_hw_getnf(struct ath_hal *ah, + struct ath9k_channel *chan); +void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah); +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan); +bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone); +bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan); + + +/* EEPROM */ + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit); +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan); +bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u8 AntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit); +bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset); +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan); +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config); +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band); +u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz); +int ath9k_hw_eeprom_attach(struct ath_hal *ah); + +/* Interrupt Handling */ + +bool ath9k_hw_intrpend(struct ath_hal *ah); +bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); +enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); + +/* MAC (PCU/QCU) */ + +void ath9k_hw_dmaRegDump(struct ath_hal *ah); +u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); +bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp); bool ath9k_hw_txstart(struct ath_hal *ah, u32 q); -u16 ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble); +u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); +bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel); +bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); +bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0); +void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); +int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags); void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, struct ath_desc *lastds, u32 durUpdateEn, u32 rtsctsRate, u32 rtsctsDuration, struct ath9k_11n_rate_series series[], u32 nseries, u32 flags); -void ath9k_hw_set11n_burstduration(struct ath_hal *ah, - struct ath_desc *ds, +void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, + u32 aggrLen); +void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, + u32 numDelims); +void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, u32 burstDuration); -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); -u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); -u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, - struct ath9k_channel *chan); -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo); +void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, + u32 vmf); +void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, const struct ath9k_tx_queue_info *qinfo); -struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah, - const struct ath9k_channel *c); -void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, - enum ath9k_key_type keyType, u32 flags); -bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, - const struct ath_desc *ds0); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt); -void ath9k_hw_dmaRegDump(struct ath_hal *ah); -void ath9k_hw_beaconinit(struct ath_hal *ah, - u32 next_beacon, u32 beacon_period); -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs); +bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, + struct ath9k_tx_queue_info *qinfo); +int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); +bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); +int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf); bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, u32 size, u32 flags); +bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp); void ath9k_hw_rxena(struct ath_hal *ah); -void ath9k_hw_setopmode(struct ath_hal *ah); -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, - u32 filter1); -u32 ath9k_hw_getrxfilter(struct ath_hal *ah); void ath9k_hw_startpcureceive(struct ath_hal *ah); void ath9k_hw_stoppcurecv(struct ath_hal *ah); bool ath9k_hw_stopdmarecv(struct ath_hal *ah); -int ath9k_hw_rxprocdesc(struct ath_hal *ah, - struct ath_desc *ds, u32 pa, - struct ath_desc *nds, u64 tsf); -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); -int ath9k_hw_txprocdesc(struct ath_hal *ah, - struct ath_desc *ds); -void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims); -void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen); -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); -void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, - struct ath_desc *ds, u32 vmf); -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); -int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo); -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); -const char *ath9k_hw_probe(u16 vendorid, u16 devid); -bool ath9k_hw_disable(struct ath_hal *ah); -void ath9k_hw_rfdetach(struct ath_hal *ah); -void ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers); -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); -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); + #endif diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c new file mode 100644 index 0000000..1690759 --- /dev/null +++ b/drivers/net/wireless/ath9k/calib.c @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; + +/* We can tune this as we go by monitoring really low values */ +#define ATH9K_NF_TOO_LOW -60 + +/* AR5416 may return very high value (like -31 dBm), in those cases the nf + * is incorrect and we should use the static NF value. Later we can try to + * find out why they are reporting these values */ + +static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) +{ + if (nf > ATH9K_NF_TOO_LOW) { + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "%s: noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + __func__, nf, ATH9K_NF_TOO_LOW); + return false; + } + return true; +} + +static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) +{ + int16_t nfval; + int16_t sort[ATH9K_NF_CAL_HIST_MAX]; + int i, j; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) + sort[i] = nfCalBuffer[i]; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { + for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { + if (sort[j] > sort[j - 1]) { + nfval = sort[j]; + sort[j] = sort[j - 1]; + sort[j - 1] = nfval; + } + } + } + nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; + + return nfval; +} + +static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, + int16_t *nfarray) +{ + int i; + + for (i = 0; i < NUM_NF_READINGS; i++) { + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; + + if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) + h[i].currIndex = 0; + + if (h[i].invalidNFcount > 0) { + if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || + nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { + h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; + } else { + h[i].invalidNFcount--; + h[i].privNF = nfarray[i]; + } + } else { + h[i].privNF = + ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); + } + } + return; +} + +static void ath9k_hw_do_getnf(struct ath_hal *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + int16_t nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR9280_PHY_CH1_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR_PHY_CH1_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), + AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR9280_PHY_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR_PHY_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[3] = nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR9280_PHY_CH1_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR_PHY_CH1_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), + AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + } +} + +static bool getNoiseFloorThresh(struct ath_hal *ah, + const struct ath9k_channel *chan, + int16_t *nft) +{ + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); + break; + case CHANNEL_B: + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "%s: invalid channel flags 0x%x\n", __func__, + chan->channelFlags); + return false; + } + + return true; +} + +static void ath9k_hw_setup_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) +{ + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + currCal->calData->calCountMax); + + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: starting IQ Mismatch Calibration\n", + __func__); + break; + case ADC_GAIN_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: starting ADC Gain Calibration\n", __func__); + break; + case ADC_DC_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: starting ADC DC Calibration\n", __func__); + break; + case ADC_DC_INIT_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: starting Init ADC DC Calibration\n", + __func__); + break; + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_DO_CAL); +} + +static void ath9k_hw_reset_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + ath9k_hw_setup_calibration(ah, currCal); + + currCal->calState = CAL_RUNNING; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_Meas0.sign[i] = 0; + ahp->ah_Meas1.sign[i] = 0; + ahp->ah_Meas2.sign[i] = 0; + ahp->ah_Meas3.sign[i] = 0; + } + + ahp->ah_CalSamples = 0; +} + +static void ath9k_hw_per_calibration(struct ath_hal *ah, + struct ath9k_channel *ichan, + u8 rxchainmask, + struct hal_cal_list *currCal, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *isCalDone = false; + + if (currCal->calState == CAL_RUNNING) { + if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & + AR_PHY_TIMING_CTRL4_DO_CAL)) { + + currCal->calData->calCollect(ah); + ahp->ah_CalSamples++; + + if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + + currCal->calData->calPostProc(ah, numChains); + ichan->CalValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + *isCalDone = true; + } else { + ath9k_hw_setup_calibration(ah, currCal); + } + } + } else if (!(ichan->CalValid & currCal->calData->calType)) { + ath9k_hw_reset_calibration(ah, currCal); + } +} + +static bool ath9k_hw_iscal_supported(struct ath_hal *ah, + struct ath9k_channel *chan, + enum hal_cal_types calType) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + bool retval = false; + + switch (calType & ahp->ah_suppCals) { + case IQ_MISMATCH_CAL: + if (!IS_CHAN_B(chan)) + retval = true; + break; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + if (!IS_CHAN_B(chan) + && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + retval = true; + break; + } + + return retval; +} + +static void ath9k_hw_iqcal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], + ahp->ah_totalPowerMeasQ[i], + ahp->ah_totalIqCorrMeas[i]); + } +} + +static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalAdcIOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalAdcIEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalAdcQOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ahp->ah_totalAdcQEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ahp->ah_CalSamples, i, + ahp->ah_totalAdcIOddPhase[i], + ahp->ah_totalAdcIEvenPhase[i], + ahp->ah_totalAdcQOddPhase[i], + ahp->ah_totalAdcQEvenPhase[i]); + } +} + +static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalAdcDcOffsetIOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalAdcDcOffsetIEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalAdcDcOffsetQOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ahp->ah_totalAdcDcOffsetQEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ahp->ah_CalSamples, i, + ahp->ah_totalAdcDcOffsetIOddPhase[i], + ahp->ah_totalAdcDcOffsetIEvenPhase[i], + ahp->ah_totalAdcDcOffsetQOddPhase[i], + ahp->ah_totalAdcDcOffsetQEvenPhase[i]); + } +} + +static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 powerMeasQ, powerMeasI, iqCorrMeas; + u32 qCoffDenom, iCoffDenom; + int32_t qCoff, iCoff; + int iqCorrNeg, i; + + for (i = 0; i < numChains; i++) { + powerMeasI = ahp->ah_totalPowerMeasI[i]; + powerMeasQ = ahp->ah_totalPowerMeasQ[i]; + iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ahp->ah_totalIqCorrMeas[i]); + + iqCorrNeg = 0; + + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + if (powerMeasQ != 0) { + iCoff = iqCorrMeas / iCoffDenom; + qCoff = powerMeasI / qCoffDenom - 64; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); + + iCoff = iCoff & 0x3f; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "New: Chn %d iCoff = 0x%08x\n", i, iCoff); + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); + + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, + iCoff); + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, + qCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); + } + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} + +static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; + u32 qGainMismatch, iGainMismatch, val, i; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; + iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; + qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; + qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC Gain Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + iGainMismatch = + ((iEvenMeasOffset * 32) / + iOddMeasOffset) & 0x3f; + qGainMismatch = + ((qOddMeasOffset * 32) / + qEvenMeasOffset) & 0x3f; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC Gain Cal done for Chain %d\n", i); + } + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} + +static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 iOddMeasOffset, iEvenMeasOffset, val, i; + int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; + const struct hal_percal_data *calData = + ahp->ah_cal_list_curr->calData; + u32 numSamples = + (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; + iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; + qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; + qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC DC Offset Cal done for Chain %d\n", i); + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} + +void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *ichan = + ath9k_regd_check_channel(ah, chan); + struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + + *isCalDone = true; + + if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) + return; + + if (currCal == NULL) + return; + + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + return; + } + + + if (currCal->calState != CAL_DONE) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: Calibration state incorrect, %d\n", + __func__, currCal->calState); + return; + } + + + if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) + return; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: Resetting Cal %d state for channel %u/0x%x\n", + __func__, currCal->calData->calType, chan->channel, + chan->channelFlags); + + ichan->CalValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; + + *isCalDone = false; +} + +void ath9k_hw_start_nfcal(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); +} + +void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath9k_nfcal_hist *h; + int i, j; + int32_t val; + const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + u8 chainmask; + + if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + +#ifdef ATH_NF_PER_CHAN + h = chan->nfCalHist; +#else + h = ah->nfCalHist; +#endif + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (h[i].privNF) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + for (j = 0; j < 1000; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_NF) == 0) + break; + udelay(10); + } + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (-50) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } +} + +int16_t ath9k_hw_getnf(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + int16_t nf, nfThresh; + int16_t nfarray[NUM_NF_READINGS] = { 0 }; + struct ath9k_nfcal_hist *h; + u8 chainmask; + + if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + + chan->channelFlags &= (~CHANNEL_CW_INT); + if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: NF did not complete in calibration window\n", + __func__); + nf = 0; + chan->rawNoiseFloor = nf; + return chan->rawNoiseFloor; + } else { + ath9k_hw_do_getnf(ah, nfarray); + nf = nfarray[0]; + if (getNoiseFloorThresh(ah, chan, &nfThresh) + && nf > nfThresh) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: noise floor failed detected; " + "detected %d, threshold %d\n", __func__, + nf, nfThresh); + chan->channelFlags |= CHANNEL_CW_INT; + } + } + +#ifdef ATH_NF_PER_CHAN + h = chan->nfCalHist; +#else + h = ah->nfCalHist; +#endif + + ath9k_hw_update_nfcal_hist_buffer(h, nfarray); + chan->rawNoiseFloor = h[0].privNF; + + return chan->rawNoiseFloor; +} + +void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) +{ + int i, j; + + for (i = 0; i < NUM_NF_READINGS; i++) { + ah->nfCalHist[i].currIndex = 0; + ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].invalidNFcount = + AR_PHY_CCA_FILTERWINDOW_LENGTH; + for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { + ah->nfCalHist[i].nfCalBuffer[j] = + AR_PHY_CCA_MAX_GOOD_VALUE; + } + } + return; +} + +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath9k_channel *ichan; + s16 nf; + + ichan = ath9k_regd_check_channel(ah, chan); + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + return ATH_DEFAULT_NOISE_FLOOR; + } + if (ichan->rawNoiseFloor == 0) { + enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); + nf = NOISE_FLOOR[mode]; + } else + nf = ichan->rawNoiseFloor; + + if (!ath9k_hw_nf_in_range(ah, nf)) + nf = ATH_DEFAULT_NOISE_FLOOR; + + return nf; +} + +bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + + *isCalDone = true; + + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); + return false; + } + + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, + isCalDone); + if (*isCalDone) { + ahp->ah_cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + *isCalDone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + if (longcal) { + ath9k_hw_getnf(ah, ichan); + ath9k_hw_loadnf(ah, ah->ah_curchan); + ath9k_hw_start_nfcal(ah); + + if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + } + } + + return true; +} + +bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: offset calibration failed to complete in 1ms; " + "noisy environment?\n", __func__); + return false; + } + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); + + ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; + + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { + if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { + INIT_CAL(&ahp->ah_adcGainCalData); + INSERT_CAL(ahp, &ahp->ah_adcGainCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: enabling ADC Gain Calibration.\n", + __func__); + } + if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { + INIT_CAL(&ahp->ah_adcDcCalData); + INSERT_CAL(ahp, &ahp->ah_adcDcCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: enabling ADC DC Calibration.\n", + __func__); + } + if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&ahp->ah_iqCalData); + INSERT_CAL(ahp, &ahp->ah_iqCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%s: enabling IQ Calibration.\n", + __func__); + } + + ahp->ah_cal_list_curr = ahp->ah_cal_list; + + if (ahp->ah_cal_list_curr) + ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); + } + + ichan->CalValid = 0; + + return true; +} + +const struct hal_percal_data iq_cal_multi_sample = { + IQ_MISMATCH_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data iq_cal_single_sample = { + IQ_MISMATCH_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data adc_gain_cal_multi_sample = { + ADC_GAIN_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_gain_cal_single_sample = { + ADC_GAIN_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_dc_cal_multi_sample = { + ADC_DC_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_dc_cal_single_sample = { + ADC_DC_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_init_dc_cal = { + ADC_DC_INIT_CAL, + MIN_CAL_SAMPLES, + INIT_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c new file mode 100644 index 0000000..f5fd03c --- /dev/null +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -0,0 +1,1605 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, + u32 reg, u32 mask, + u32 shift, u32 val) +{ + u32 regVal; + + regVal = REG_READ(ah, reg) & ~mask; + regVal |= (val << shift) & mask; + + REG_WRITE(ah, reg, regVal); + + if (ah->ah_config.analog_shiftreg) + udelay(100); + + return; +} + +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +static inline int16_t ath9k_hw_interpolate(u16 target, + u16 srcLeft, u16 srcRight, + int16_t targetLeft, + int16_t targetRight) +{ + int16_t rv; + + if (srcRight == srcLeft) { + rv = targetLeft; + } else { + rv = (int16_t) (((target - srcLeft) * targetRight + + (srcRight - target) * targetLeft) / + (srcRight - srcLeft)); + } + return rv; +} + +static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, + u16 listSize, u16 *indexL, + u16 *indexR) +{ + u16 i; + + if (target <= pList[0]) { + *indexL = *indexR = 0; + return true; + } + if (target >= pList[listSize - 1]) { + *indexL = *indexR = (u16) (listSize - 1); + return true; + } + + for (i = 0; i < listSize - 1; i++) { + if (pList[i] == target) { + *indexL = *indexR = i; + return true; + } + if (target < pList[i + 1]) { + *indexL = i; + *indexR = (u16) (i + 1); + return false; + } + } + return false; +} + +static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data) +{ + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { + return false; + } + + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + + return true; +} + +static int ath9k_hw_flash_map(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + + if (!ahp->ah_cal_mem) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "%s: cannot remap eeprom region \n", __func__); + return -EIO; + } + + return 0; +} + +static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *data = ioread16(ahp->ah_cal_mem + off); + + return true; +} + +static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data) +{ + if (ath9k_hw_use_flash(ah)) + return ath9k_hw_flash_read(ah, off, data); + else + return ath9k_hw_eeprom_read(ah, off, data); +} + +static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = &ahp->ah_eeprom; + u16 *eep_data; + int addr, ar5416_eep_start_loc = 0; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "%s: Reading from EEPROM, not flash\n", __func__); + ar5416_eep_start_loc = 256; + } + + if (AR_SREV_9100(ah)) + ar5416_eep_start_loc = 256; + + eep_data = (u16 *)eep; + + for (addr = 0; addr < sizeof(struct ar5416_eeprom) / sizeof(u16); addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "%s: Unable to read eeprom region \n", + __func__); + return false; + } + eep_data++; + } + return true; +} + +static int ath9k_hw_check_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = + (struct ar5416_eeprom *) &ahp->ah_eeprom; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "%s: Reading Magic # failed\n", __func__); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n", + __func__, magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom); + need_swap = true; + eepdata = (u16 *) (&ahp->ah_eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "0x%04X ", *eepdata); + + if (((addr + 1) % 6) == 0) + DPRINTF(ah->ah_sc, + ATH_DBG_EEPROM, "\n"); + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ahp->ah_eeprom.baseEepHeader.length); + else + el = ahp->ah_eeprom.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom)) + el = sizeof(struct ar5416_eeprom) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ahp->ah_eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing \n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || + ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ar5416_get_eep_ver(ahp)); + return -EINVAL; + } + + return 0; +} + +static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) +{ + u16 i, k; + u8 currPwr = pwrMin; + u16 idxL = 0, idxR = 0; + + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + ath9k_hw_get_lower_upper_index(currPwr, pPwrList, + numIntercepts, &(idxL), + &(idxR)); + if (idxR < 1) + idxR = 1; + if (idxL == numIntercepts - 1) + idxL = (u16) (numIntercepts - 2); + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL])); + pRetVpdList[i] = (u8) k; + currPwr += 2; + } + + return true; +} + +static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = + (u8)ath9k_hw_interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static void ath9k_hw_get_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else + if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, + clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static u16 ath9k_hw_get_max_edge_power(u16 freq, + struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz) +{ + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + for (i = 0; (i < AR5416_NUM_BAND_EDGES) && + (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = pRdEdgesPower[i].tPower; + break; + } else if ((i > 0) && + (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, + is2GHz))) { + if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, + is2GHz) < freq && + pRdEdgesPower[i - 1].flag) { + twiceMaxEdgePower = + pRdEdgesPower[i - 1].tPower; + } + break; + } + } + + return twiceMaxEdgePower; +} + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = &ahp->ah_eeprom; + u8 biaslevel; + + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + resetFreqBin = FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)); + freqBin = pModal->xpaBiasLvlFreq[0] & 0xff; + biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14); + + freqCount++; + + while (freqCount < 3) { + if (pModal->xpaBiasLvlFreq[freqCount] == 0x0) + break; + + freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff; + if (resetFreqBin >= freqBin) { + biaslevel = (u8)(pModal->xpaBiasLvlFreq[freqCount] >> 14); + } else { + break; + } + freqCount++; + } + } + + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ahp->ah_iniAddac, 7, 1) = + (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ahp->ah_iniAddac, 6, 1) = + (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel << 6; + } +} + +bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u8 AntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; + u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int8_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u8 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u8 twiceMinEdgePower; + + tx_chainmask = ahp->ah_txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int8_t)min(AntennaReduction - twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain; + break; + case 3: + scaledPower -= + pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain; + break; + } + + scaledPower = max(0, (int32_t) scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan)); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min(targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min(targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min(targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = + min(targetPowerCckExt.tPow2x[0], minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = + min(targetPowerOfdmExt.tPow2x[0], minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min(targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + ; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } + return true; +} + +bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16) | + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, + "PDADC: Chain %d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +/* XXX: Clean me up, make me more legible */ +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = &ahp->ah_eeprom; + int i, regChainOffset; + u8 txRxAttenLocal; + u16 ant_config; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_9280(ah)) { + if (i >= 2) + break; + } + + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) + && (i != 0)) + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + else + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, + AR_PHY_TIMING_CTRL4(0) + + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + if ((eep->baseEepHeader.version & + AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal-> + bswMargin[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal-> + bswAtten[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal-> + xatten2Margin[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal-> + xatten2Db[i]); + } else { + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> + bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, + AR_PHY_RXGAIN + + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) | + SM(txRxAttenLocal, + AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], + AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (IS_CHAN_2GHZ(chan)) { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_OB, + AR_AN_RF2G1_CH0_OB_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_DB, + AR_AN_RF2G1_CH0_DB_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_OB, + AR_AN_RF2G1_CH1_OB_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_DB, + AR_AN_RF2G1_CH1_DB_S, + pModal->db_ch1); + } else { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_OB5, + AR_AN_RF5G1_CH0_OB5_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_DB5, + AR_AN_RF5G1_CH0_DB5_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_OB5, + AR_AN_RF5G1_CH1_OB5_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_DB5, + AR_AN_RF5G1_CH1_DB5_S, + pModal->db_ch1); + } + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_XPABIAS_LVL, + AR_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_LOCALBIAS, + AR_AN_TOP2_LOCALBIAS_S, + pModal->local_bias); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n", + pModal->force_xpaon); + REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, + pModal->force_xpaon); + } + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + if (!AR_SREV_9280_10_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, + pModal->pgaDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, + AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + return true; +} + +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (index) { + case 0: + *config = pModal->antCtrlCommon & 0xFFFF; + return 0; + case 1: + if (pBase->version >= 0x0E0D) { + if (pModal->useAnt1) { + *config = + ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); + return 0; + } + } + break; + default: + break; + } + + return -EINVAL; +} + +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct modal_eep_header *pModal = + &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); + struct base_eep_header *pBase = &eep->baseEepHeader; + u8 num_ant_config; + + num_ant_config = 1; + + if (pBase->version >= 0x0E0D) + if (pModal->useAnt1) + num_ant_config += 1; + + return num_ant_config; +} + +u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = + (struct ar5416_eeprom *) &ahp->ah_eeprom; + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); + + switch (ah->ah_config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->ah_config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan; + break; + + } + + return spur_val; +} + +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_5: + return -pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return -pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + default: + return 0; + } +} + +int ath9k_hw_eeprom_attach(struct ath_hal *ah) +{ + int status; + + if (ath9k_hw_use_flash(ah)) + ath9k_hw_flash_map(ah); + + if (!ath9k_hw_fill_eeprom(ah)) + return -EIO; + + status = ath9k_hw_check_eeprom(ah); + + return status; +} diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 1417ba0..e05c9ef 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -23,183 +23,68 @@ #include "phy.h" #include "initvals.h" -static void ath9k_hw_iqcal_collect(struct ath_hal *ah); -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains); -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah); -static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, - u8 numChains); -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah); -static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, - u8 numChains); - static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 }; -static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; - -static const struct hal_percal_data iq_cal_multi_sample = { - IQ_MISMATCH_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -static const struct hal_percal_data iq_cal_single_sample = { - IQ_MISMATCH_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -static const struct hal_percal_data adc_gain_cal_multi_sample = { - ADC_GAIN_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -static const struct hal_percal_data adc_gain_cal_single_sample = { - ADC_GAIN_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -static const struct hal_percal_data adc_dc_cal_multi_sample = { - ADC_DC_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static const struct hal_percal_data adc_dc_cal_single_sample = { - ADC_DC_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static const struct hal_percal_data adc_init_dc_cal = { - ADC_DC_INIT_CAL, - MIN_CAL_SAMPLES, - INIT_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static struct ath9k_rate_table ar5416_11a_table = { - 8, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4} - }, -}; +extern struct hal_percal_data iq_cal_multi_sample; +extern struct hal_percal_data iq_cal_single_sample; +extern struct hal_percal_data adc_gain_cal_multi_sample; +extern struct hal_percal_data adc_gain_cal_single_sample; +extern struct hal_percal_data adc_dc_cal_multi_sample; +extern struct hal_percal_data adc_dc_cal_single_sample; +extern struct hal_percal_data adc_init_dc_cal; -static struct ath9k_rate_table ar5416_11b_table = { - 4, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1} - }, -}; +static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type); +static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode); +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom *pEepData, + u32 reg, u32 value); +static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); -static struct ath9k_rate_table ar5416_11g_table = { - 12, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, +/********************/ +/* Helper Functions */ +/********************/ - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8} - }, -}; +static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) +{ + if (ah->ah_curchan != NULL) + return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; + else + return clks / CLOCK_RATE[ATH9K_MODE_11B]; +} -static struct ath9k_rate_table ar5416_11ng_table = { - 28, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, +static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) +{ + struct ath9k_channel *chan = ah->ah_curchan; - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 4}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 6}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 6}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 8}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 8}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 8}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 8}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 8}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 4}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 6}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8}, - }, -}; + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_usec(ah, clks) / 2; + else + return ath9k_hw_mac_usec(ah, clks); +} -static struct ath9k_rate_table ar5416_11na_table = { - 24, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 0}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 2}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 2}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 4}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 4}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 4}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 4}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 4}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 0}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 2}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4}, - }, -}; +static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) +{ + if (ah->ah_curchan != NULL) + return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, + ah->ah_curchan)]; + else + return usecs * CLOCK_RATE[ATH9K_MODE_11B]; +} + +static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) +{ + struct ath9k_channel *chan = ah->ah_curchan; + + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_clks(ah, usecs) * 2; + else + return ath9k_hw_mac_clks(ah, usecs); +} -static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, - const struct ath9k_channel *chan) +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan) { if (IS_CHAN_CCK(chan)) return ATH9K_MODE_11A; @@ -208,10 +93,7 @@ static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, return ATH9K_MODE_11A; } -static bool ath9k_hw_wait(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 val) +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) { int i; @@ -222,78 +104,10 @@ static bool ath9k_hw_wait(struct ath_hal *ah, udelay(AH_TIME_QUANTUM); } DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - __func__, reg, REG_READ(ah, reg), mask, val); - return false; -} - -static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, - u16 *data) -{ - (void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); - - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { - return false; - } - - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); - - return true; -} - -static int ath9k_hw_flash_map(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); - - if (!ahp->ah_cal_mem) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: cannot remap eeprom region \n", __func__); - return -EIO; - } - - return 0; -} - -static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, - u16 *data) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - *data = ioread16(ahp->ah_cal_mem + off); - return true; -} - -static void ath9k_hw_read_revisions(struct ath_hal *ah) -{ - u32 val; - - val = REG_READ(ah, AR_SREV) & AR_SREV_ID; - - if (val == 0xFF) { - val = REG_READ(ah, AR_SREV); - - ah->ah_macVersion = - (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; - - ah->ah_macRev = MS(val, AR_SREV_REVISION2); - ah->ah_isPciExpress = - (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; - - } else { - if (!AR_SREV_9100(ah)) - ah->ah_macVersion = MS(val, AR_SREV_VERSION); - - ah->ah_macRev = val & AR_SREV_REVISION; + "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + __func__, reg, REG_READ(ah, reg), mask, val); - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) - ah->ah_isPciExpress = true; - } + return false; } u32 ath9k_hw_reverse_bits(u32 val, u32 n) @@ -308,850 +122,318 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n) return retval; } -static void ath9k_hw_set_defaults(struct ath_hal *ah) +bool ath9k_get_channel_edges(struct ath_hal *ah, + u16 flags, u16 *low, + u16 *high) { - int i; - - ah->ah_config.dma_beacon_response_time = 2; - ah->ah_config.sw_beacon_response_time = 10; - ah->ah_config.additional_swba_backoff = 0; - ah->ah_config.ack_6mb = 0x0; - ah->ah_config.cwm_ignore_extcca = 0; - ah->ah_config.pcie_powersave_enable = 0; - ah->ah_config.pcie_l1skp_enable = 0; - ah->ah_config.pcie_clock_req = 0; - ah->ah_config.pcie_power_reset = 0x100; - ah->ah_config.pcie_restore = 0; - ah->ah_config.pcie_waen = 0; - ah->ah_config.analog_shiftreg = 1; - ah->ah_config.ht_enable = 1; - ah->ah_config.ofdm_trig_low = 200; - ah->ah_config.ofdm_trig_high = 500; - ah->ah_config.cck_trig_high = 200; - ah->ah_config.cck_trig_low = 100; - ah->ah_config.enable_ani = 1; - ah->ah_config.noise_immunity_level = 4; - ah->ah_config.ofdm_weaksignal_det = 1; - ah->ah_config.cck_weaksignal_thr = 0; - ah->ah_config.spur_immunity_level = 2; - ah->ah_config.firstep_level = 0; - ah->ah_config.rssi_thr_high = 40; - ah->ah_config.rssi_thr_low = 7; - ah->ah_config.diversity_control = 0; - ah->ah_config.antenna_switch_swap = 0; + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - ah->ah_config.spurchans[i][0] = AR_NO_SPUR; - ah->ah_config.spurchans[i][1] = AR_NO_SPUR; + if (flags & CHANNEL_5GHZ) { + *low = pCap->low_5ghz_chan; + *high = pCap->high_5ghz_chan; + return true; } - - ah->ah_config.intr_mitigation = 1; + if ((flags & CHANNEL_2GHZ)) { + *low = pCap->low_2ghz_chan; + *high = pCap->high_2ghz_chan; + return true; + } + return false; } -static void ath9k_hw_override_ini(struct ath_hal *ah, - struct ath9k_channel *chan) +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + const struct ath9k_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble) { - if (!AR_SREV_5416_V20_OR_LATER(ah) - || AR_SREV_9280_10_OR_LATER(ah)) - return; + u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; + u32 kbps; - REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); -} + kbps = rates->info[rateix].rateKbps; -static void ath9k_hw_init_bb(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 synthDelay; + if (kbps == 0) + return 0; - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; + switch (rates->info[rateix].phy) { + case PHY_CCK: + phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; + if (shortPreamble && rates->info[rateix].shortPreamble) + phyTime >>= 1; + numBits = frameLen << 3; + txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); + break; + case PHY_OFDM: + if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_QUARTER + + OFDM_PREAMBLE_TIME_QUARTER + + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + } else if (ah->ah_curchan && + IS_CHAN_HALF_RATE(ah->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_HALF + + OFDM_PREAMBLE_TIME_HALF + + (numSymbols * OFDM_SYMBOL_TIME_HALF); + } else { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME + + (numSymbols * OFDM_SYMBOL_TIME); + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, + "%s: unknown phy %u (rate ix %u)\n", __func__, + rates->info[rateix].phy, rateix); + txTime = 0; + break; + } - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + return txTime; +} - udelay(synthDelay + BASE_ACTIVATE_DELAY); +u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +{ + if (flags & CHANNEL_2GHZ) { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + else + return 15 + ((freq - 2512) / 20); + } else if (flags & CHANNEL_5GHZ) { + if (ath9k_regd_is_public_safety_sku(ah) && + IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return ((freq * 10) + + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; + } else if ((flags & CHANNEL_A) && (freq <= 5000)) { + return (freq - 4000) / 5; + } else { + return (freq - 5000) / 5; + } + } else { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + if (freq < 5000) { + if (ath9k_regd_is_public_safety_sku(ah) + && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return ((freq * 10) + + (((freq % 5) == + 2) ? 5 : 0) - 49400) / 5; + } else if (freq > 4900) { + return (freq - 4000) / 5; + } else { + return 15 + ((freq - 2512) / 20); + } + } + return (freq - 5000) / 5; + } } -static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers) { + int8_t extoff; struct ath_hal_5416 *ahp = AH5416(ah); - ahp->ah_maskReg = AR_IMR_TXERR | - AR_IMR_TXURN | - AR_IMR_RXERR | - AR_IMR_RXORN | - AR_IMR_BCNMISC; - - if (ahp->ah_intrMitigation) - ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else - ahp->ah_maskReg |= AR_IMR_RXOK; - - ahp->ah_maskReg |= AR_IMR_TXOK; - - if (opmode == ATH9K_M_HOSTAP) - ahp->ah_maskReg |= AR_IMR_MIB; - - REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); - REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); - - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + if (!IS_CHAN_HT40(chan)) { + centers->ctl_center = centers->ext_center = + centers->synth_center = chan->channel; + return; } -} -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); + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) { + centers->synth_center = + chan->channel + HT40_CHANNEL_CENTER_SHIFT; + extoff = 1; + } else { + centers->synth_center = + chan->channel - HT40_CHANNEL_CENTER_SHIFT; + extoff = -1; + } - REG_WRITE(ah, AR_QOS_NO_ACK, - SM(2, AR_QOS_NO_ACK_TWO_BIT) | - SM(5, AR_QOS_NO_ACK_BIT_OFF) | - SM(0, AR_QOS_NO_ACK_BYTE_OFF)); + centers->ctl_center = + centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); + centers->ext_center = + centers->synth_center + (extoff * + ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? + HT40_CHANNEL_CENTER_SHIFT : 15)); - REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); - REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } -static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 shift, - u32 val) +/******************/ +/* Chip Revisions */ +/******************/ + +static void ath9k_hw_read_revisions(struct ath_hal *ah) { - u32 regVal; + u32 val; - regVal = REG_READ(ah, reg) & ~mask; - regVal |= (val << shift) & mask; + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; - REG_WRITE(ah, reg, regVal); + if (val == 0xFF) { + val = REG_READ(ah, AR_SREV); + ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; + ah->ah_macRev = MS(val, AR_SREV_REVISION2); + ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; + } else { + if (!AR_SREV_9100(ah)) + ah->ah_macVersion = MS(val, AR_SREV_VERSION); - if (ah->ah_config.analog_shiftreg) - udelay(100); + ah->ah_macRev = val & AR_SREV_REVISION; - return; + if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) + ah->ah_isPciExpress = true; + } } -static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp, - enum ieee80211_band freq_band) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); - struct base_eep_header *pBase = &eep->baseEepHeader; - u8 num_ant_config; + u32 val; + int i; - num_ant_config = 1; + REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; + for (i = 0; i < 8; i++) + REG_WRITE(ah, AR_PHY(0x20), 0x00010000); + val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - return num_ant_config; + return ath9k_hw_reverse_bits(val, 8); } -static int -ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp, - struct ath9k_channel *chan, - u8 index, - u16 *config) +/************************************/ +/* HW Attach, Detach, Init Routines */ +/************************************/ + +static void ath9k_hw_disablepcie(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - struct base_eep_header *pBase = &eep->baseEepHeader; + if (!AR_SREV_9100(ah)) + return; - switch (index) { - case 0: - *config = pModal->antCtrlCommon & 0xFFFF; - return 0; - case 1: - if (pBase->version >= 0x0E0D) { - if (pModal->useAnt1) { - *config = - ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); - return 0; - } - } - break; - default: - break; - } + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); + REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); - return -EINVAL; + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } -static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, - u32 off, - u16 *data) +static bool ath9k_hw_chip_test(struct ath_hal *ah) { - if (ath9k_hw_use_flash(ah)) - return ath9k_hw_flash_read(ah, off, data); - else - return ath9k_hw_eeprom_read(ah, off, data); -} + u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; + u32 regHold[2]; + u32 patternData[4] = { 0x55555555, + 0xaaaaaaaa, + 0x66666666, + 0x99999999 }; + int i, j; -static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u16 *eep_data; - int addr, ar5416_eep_start_loc = 0; + for (i = 0; i < 2; i++) { + u32 addr = regAddr[i]; + u32 wrData, rdData; - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading from EEPROM, not flash\n", __func__); - ar5416_eep_start_loc = 256; - } - if (AR_SREV_9100(ah)) - ar5416_eep_start_loc = 256; - - eep_data = (u16 *) eep; - for (addr = 0; - addr < sizeof(struct ar5416_eeprom) / sizeof(u16); - addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Unable to read eeprom region \n", - __func__); - return false; + regHold[i] = REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (rdData != wrData) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "%s: address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return false; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (wrData != rdData) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "%s: address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + __func__, addr, wrData, rdData); + return false; + } } - eep_data++; + REG_WRITE(ah, regAddr[i], regHold[i]); } + udelay(100); return true; } -/* XXX: Clean me up, make me more legible */ -static bool -ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, - struct ath9k_channel *chan) +static const char *ath9k_hw_devname(u16 devid) { - struct modal_eep_header *pModal; - int i, regChainOffset; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 txRxAttenLocal; - u16 ant_config; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; - - ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config); - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_9280(ah)) { - if (i >= 2) - break; - } - - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - else - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, - AR_PHY_TIMING_CTRL4(0) + - regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - if ((eep->baseEepHeader.version & - AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal-> - bswMargin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal-> - bswAtten[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal-> - xatten2Margin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal-> - xatten2Db[i]); - } else { - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> - bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, - txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, - pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, - AR_PHY_RXGAIN + - regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) | - SM(txRxAttenLocal, - AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], - AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } - } + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + return "Atheros 5416"; + case AR9160_DEVID_PCI: + return "Atheros 9160"; + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + return "Atheros 9280"; } - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (IS_CHAN_2GHZ(chan)) { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_OB, - AR_AN_RF2G1_CH0_OB_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_DB, - AR_AN_RF2G1_CH0_DB_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_OB, - AR_AN_RF2G1_CH1_OB_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_DB, - AR_AN_RF2G1_CH1_DB_S, - pModal->db_ch1); - } else { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_OB5, - AR_AN_RF5G1_CH0_OB5_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_DB5, - AR_AN_RF5G1_CH0_DB5_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_OB5, - AR_AN_RF5G1_CH1_OB5_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_DB5, - AR_AN_RF5G1_CH1_DB5_S, - pModal->db_ch1); - } - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_XPABIAS_LVL, - AR_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_LOCALBIAS, - AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); - DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n", - pModal->force_xpaon); - REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); - } + return NULL; +} - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); +static void ath9k_hw_set_defaults(struct ath_hal *ah) +{ + int i; - if (!AR_SREV_9280_10_OR_LATER(ah)) - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_PGA, - pModal->pgaDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, - AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - } else { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_CCA_THRESH62, - pModal->thresh62); - } - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } - - return true; -} - -static int ath9k_hw_check_eeprom(struct ath_hal *ah) -{ - u32 sum = 0, el; - u16 *eepdata; - int i; - struct ath_hal_5416 *ahp = AH5416(ah); - bool need_swap = false; - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; - - if (!ath9k_hw_use_flash(ah)) { - u16 magic, magic2; - int addr; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading Magic # failed\n", __func__); - return false; - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n", - __func__, magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ahp->ah_eeprom); - - for (addr = 0; - addr < - sizeof(struct ar5416_eeprom) / - sizeof(u16); addr++) { - u16 temp; - - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "0x%04X ", *eepdata); - if (((addr + 1) % 6) == 0) - DPRINTF(ah->ah_sc, - ATH_DBG_EEPROM, - "\n"); - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid EEPROM Magic. " - "endianness missmatch.\n"); - return -EINVAL; - } - } - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ahp->ah_eeprom.baseEepHeader.length); - else - el = ahp->ah_eeprom.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom)) - el = sizeof(struct ar5416_eeprom) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *) (&ahp->ah_eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer, j; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing \n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } - } - } - - if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || - ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ar5416_get_eep_ver(ahp)); - return -EINVAL; - } - - return 0; -} - -static bool ath9k_hw_chip_test(struct ath_hal *ah) -{ - u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; - u32 regHold[2]; - u32 patternData[4] = { 0x55555555, - 0xaaaaaaaa, - 0x66666666, - 0x99999999 }; - int i, j; - - for (i = 0; i < 2; i++) { - u32 addr = regAddr[i]; - u32 wrData, rdData; - - regHold[i] = REG_READ(ah, addr); - for (j = 0; j < 0x100; j++) { - wrData = (j << 16) | j; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); - return false; - } - } - for (j = 0; j < 4; j++) { - wrData = patternData[j]; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); - return false; - } - } - REG_WRITE(ah, regAddr[i], regHold[i]); - } - udelay(100); - return true; -} - -u32 ath9k_hw_getrxfilter(struct ath_hal *ah) -{ - u32 bits = REG_READ(ah, AR_RX_FILTER); - u32 phybits = REG_READ(ah, AR_PHY_ERR); - - if (phybits & AR_PHY_ERR_RADAR) - bits |= ATH9K_RX_FILTER_PHYRADAR; - if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) - bits |= ATH9K_RX_FILTER_PHYERR; - return bits; -} - -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) -{ - u32 phybits; - - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); - phybits = 0; - if (bits & ATH9K_RX_FILTER_PHYRADAR) - phybits |= AR_PHY_ERR_RADAR; - if (bits & ATH9K_RX_FILTER_PHYERR) - phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; - REG_WRITE(ah, AR_PHY_ERR, phybits); - - if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); - else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); -} - -bool ath9k_hw_setcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 setting, - int *status) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 v; - - switch (type) { - case ATH9K_CAP_TKIP_MIC: - if (setting) - ahp->ah_staId1Defaults |= - AR_STA_ID1_CRPT_MIC_ENABLE; - else - ahp->ah_staId1Defaults &= - ~AR_STA_ID1_CRPT_MIC_ENABLE; - return true; - case ATH9K_CAP_DIVERSITY: - v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (setting) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - if (setting) - ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; - else - ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; - return true; - case ATH9K_CAP_TSF_ADJUST: - if (setting) - ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; - else - ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - return true; - default: - return false; - } -} - -void ath9k_hw_dmaRegDump(struct ath_hal *ah) -{ - u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; - int qcuOffset = 0, dcuOffset = 0; - u32 *qcuBase = &val[0], *dcuBase = &val[4]; - int i; - - REG_WRITE(ah, AR_MACMISC, - ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | - (AR_MACMISC_MISC_OBS_BUS_1 << - AR_MACMISC_MISC_OBS_BUS_MSB_S))); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n"); - for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { - if (i % 4 == 0) - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - - val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); - - for (i = 0; i < ATH9K_NUM_QUEUES; - i++, qcuOffset += 4, dcuOffset += 5) { - if (i == 8) { - qcuOffset = 0; - qcuBase++; - } - - if (i == 6) { - dcuOffset = 0; - dcuBase++; - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%2d %2x %1x %2x %2x\n", - i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, - (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + - 3), - val[2] & (0x7 << (i * 3)) >> (i * 3), - (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_stitch state: %2x qcu_fetch state: %2x\n", - (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_complete state: %2x dcu_complete state: %2x\n", - (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "dcu_arb state: %2x dcu_fp state: %2x\n", - (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", - (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", - (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", - (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n", - REG_READ(ah, AR_OBS_BUS_1)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "AR_CR 0x%x \n", REG_READ(ah, AR_CR)); -} - -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt) -{ - static u32 cycles, rx_clear, rx_frame, tx_frame; - u32 good = 1; - - u32 rc = REG_READ(ah, AR_RCCNT); - u32 rf = REG_READ(ah, AR_RFCNT); - u32 tf = REG_READ(ah, AR_TFCNT); - u32 cc = REG_READ(ah, AR_CCCNT); + ah->ah_config.dma_beacon_response_time = 2; + ah->ah_config.sw_beacon_response_time = 10; + ah->ah_config.additional_swba_backoff = 0; + ah->ah_config.ack_6mb = 0x0; + ah->ah_config.cwm_ignore_extcca = 0; + ah->ah_config.pcie_powersave_enable = 0; + ah->ah_config.pcie_l1skp_enable = 0; + ah->ah_config.pcie_clock_req = 0; + ah->ah_config.pcie_power_reset = 0x100; + ah->ah_config.pcie_restore = 0; + ah->ah_config.pcie_waen = 0; + ah->ah_config.analog_shiftreg = 1; + ah->ah_config.ht_enable = 1; + ah->ah_config.ofdm_trig_low = 200; + ah->ah_config.ofdm_trig_high = 500; + ah->ah_config.cck_trig_high = 200; + ah->ah_config.cck_trig_low = 100; + ah->ah_config.enable_ani = 1; + ah->ah_config.noise_immunity_level = 4; + ah->ah_config.ofdm_weaksignal_det = 1; + ah->ah_config.cck_weaksignal_thr = 0; + ah->ah_config.spur_immunity_level = 2; + ah->ah_config.firstep_level = 0; + ah->ah_config.rssi_thr_high = 40; + ah->ah_config.rssi_thr_low = 7; + ah->ah_config.diversity_control = 0; + ah->ah_config.antenna_switch_swap = 0; - if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: cycle counter wrap. ExtBusy = 0\n", - __func__); - good = 0; - } else { - u32 cc_d = cc - cycles; - u32 rc_d = rc - rx_clear; - u32 rf_d = rf - rx_frame; - u32 tf_d = tf - tx_frame; - - if (cc_d != 0) { - *rxc_pcnt = rc_d * 100 / cc_d; - *rxf_pcnt = rf_d * 100 / cc_d; - *txf_pcnt = tf_d * 100 / cc_d; - } else { - good = 0; - } + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + ah->ah_config.spurchans[i][0] = AR_NO_SPUR; + ah->ah_config.spurchans[i][1] = AR_NO_SPUR; } - cycles = cc; - rx_frame = rf; - rx_clear = rc; - tx_frame = tf; - - return good; -} - -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) -{ - u32 macmode; - - if (mode == ATH9K_HT_MACMODE_2040 && - !ah->ah_config.cwm_ignore_extcca) - macmode = AR_2040_JOINED_RX_CLEAR; - else - macmode = 0; - - REG_WRITE(ah, AR_2040_MODE, macmode); -} - -static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + ah->ah_config.intr_mitigation = 1; } - static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, void __iomem *mem, @@ -1165,20 +447,17 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); if (ahp == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: cannot allocate memory for state block\n", - __func__); + "%s: cannot allocate memory for state block\n", + __func__); *status = -ENOMEM; return NULL; } ah = &ahp->ah; - 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; @@ -1190,12 +469,10 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, ah->ah_powerLimit = MAX_RATE_POWER; ah->ah_tpScale = ATH9K_TP_SCALE_MAX; - ahp->ah_atimWindow = 0; ahp->ah_diversityControl = ah->ah_config.diversity_control; ahp->ah_antennaSwitchSwap = ah->ah_config.antenna_switch_swap; - ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ahp->ah_beaconInterval = 100; ahp->ah_enable32kHzClock = DONT_USE_32KHZ; @@ -1210,79 +487,49 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, return ahp; } -static int ath9k_hw_eeprom_attach(struct ath_hal *ah) +static int ath9k_hw_rfattach(struct ath_hal *ah) { - int status; - - if (ath9k_hw_use_flash(ah)) - ath9k_hw_flash_map(ah); - - if (!ath9k_hw_fill_eeprom(ah)) - return -EIO; + bool rfStatus = false; + int ecode = 0; - status = ath9k_hw_check_eeprom(ah); + rfStatus = ath9k_hw_init_rf(ah, &ecode); + if (!rfStatus) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s: RF setup failed, status %u\n", __func__, + ecode); + return ecode; + } - return status; + return 0; } -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param) +static int ath9k_hw_rf_claim(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_5: - return -pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return -pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; + u32 val; + + REG_WRITE(ah, AR_PHY(0), 0x00000007); + + val = ath9k_hw_get_radiorev(ah); + switch (val & AR_RADIO_SREV_MAJOR) { + case 0: + val = AR_RAD5133_SREV_MAJOR; + break; + case AR_RAD5133_SREV_MAJOR: + case AR_RAD5122_SREV_MAJOR: + case AR_RAD2133_SREV_MAJOR: + case AR_RAD2122_SREV_MAJOR: + break; default: - return 0; + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "%s: 5G Radio Chip Rev 0x%02X is not " + "supported by this driver\n", + __func__, ah->ah_analog5GhzRev); + return -EOPNOTSUPP; } -} -static int ath9k_hw_get_radiorev(struct ath_hal *ah) -{ - u32 val; - int i; + ah->ah_analog5GhzRev = val; - REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - for (i = 0; i < 8; i++) - REG_WRITE(ah, AR_PHY(0x20), 0x00010000); - val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; - val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - return ath9k_hw_reverse_bits(val, 8); + return 0; } static int ath9k_hw_init_macaddr(struct ath_hal *ah) @@ -1294,3829 +541,410 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah) sum = 0; for (i = 0; i < 3; i++) { - eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i)); + eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i)); sum += eeval; ahp->ah_macaddr[2 * i] = eeval >> 8; ahp->ah_macaddr[2 * i + 1] = eeval & 0xff; } if (sum == 0 || sum == 0xffff * 3) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: mac address read failed: %pM\n", __func__, - ahp->ah_macaddr); + "%s: mac address read failed: %pM\n", __func__, + ahp->ah_macaddr); return -EADDRNOTAVAIL; } return 0; } -static inline int16_t ath9k_hw_interpolate(u16 target, - u16 srcLeft, - u16 srcRight, - int16_t targetLeft, - int16_t targetRight) -{ - int16_t rv; - - if (srcRight == srcLeft) { - rv = targetLeft; - } else { - rv = (int16_t) (((target - srcLeft) * targetRight + - (srcRight - target) * targetLeft) / - (srcRight - srcLeft)); - } - return rv; -} - -static inline u16 ath9k_hw_fbin2freq(u8 fbin, - bool is2GHz) -{ - - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - -static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, - u16 i, - bool is2GHz) +static int ath9k_hw_post_attach(struct ath_hal *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); - - switch (ah->ah_config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->ah_config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan; - break; + int ecode; + if (!ath9k_hw_chip_test(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "%s: hardware self-test failed\n", __func__); + return -ENODEV; } - return spur_val; -} - -static int ath9k_hw_rfattach(struct ath_hal *ah) -{ - bool rfStatus = false; - int ecode = 0; - rfStatus = ath9k_hw_init_rf(ah, &ecode); - if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RF setup failed, status %u\n", __func__, - ecode); + ecode = ath9k_hw_rf_claim(ah); + if (ecode != 0) return ecode; - } - - return 0; -} - -static int ath9k_hw_rf_claim(struct ath_hal *ah) -{ - u32 val; - REG_WRITE(ah, AR_PHY(0), 0x00000007); + ecode = ath9k_hw_eeprom_attach(ah); + if (ecode != 0) + return ecode; + ecode = ath9k_hw_rfattach(ah); + if (ecode != 0) + return ecode; - val = ath9k_hw_get_radiorev(ah); - switch (val & AR_RADIO_SREV_MAJOR) { - case 0: - val = AR_RAD5133_SREV_MAJOR; - break; - case AR_RAD5133_SREV_MAJOR: - case AR_RAD5122_SREV_MAJOR: - case AR_RAD2133_SREV_MAJOR: - case AR_RAD2122_SREV_MAJOR: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: 5G Radio Chip Rev 0x%02X is not " - "supported by this driver\n", - __func__, ah->ah_analog5GhzRev); - return -EOPNOTSUPP; + if (!AR_SREV_9100(ah)) { + ath9k_hw_ani_setup(ah); + ath9k_hw_ani_attach(ah); } - ah->ah_analog5GhzRev = val; - return 0; } -static void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) +static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *status) { - u32 pll; - - if (AR_SREV_9100(ah)) { - if (chan && IS_CHAN_5GHZ(chan)) - pll = 0x1450; - else - pll = 0x1458; - } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + struct ath_hal_5416 *ahp; + struct ath_hal *ah; + int ecode; +#ifndef CONFIG_SLOW_ANT_DIV + u32 i; + u32 j; +#endif - if (chan && IS_CHAN_5GHZ(chan)) { - pll |= SM(0x28, AR_RTC_9160_PLL_DIV); + ahp = ath9k_hw_newstate(devid, sc, mem, status); + if (ahp == NULL) + return NULL; + ah = &ahp->ah; - if (AR_SREV_9280_20(ah)) { - if (((chan->channel % 20) == 0) - || ((chan->channel % 10) == 0)) - pll = 0x2850; - else - pll = 0x142c; - } - } else { - pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); - } + ath9k_hw_set_defaults(ah); - } else if (AR_SREV_9160_10_OR_LATER(ah)) { + if (ah->ah_config.intr_mitigation != 0) + ahp->ah_intrMitigation = true; - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n", + __func__); + ecode = -EIO; + goto bad; + } - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n", + __func__); + ecode = -EIO; + goto bad; + } - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0x50, AR_RTC_9160_PLL_DIV); - else - pll |= SM(0x58, AR_RTC_9160_PLL_DIV); + if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { + ah->ah_config.serialize_regmode = + SER_REG_MODE_ON; } else { - pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0xa, AR_RTC_PLL_DIV); - else - pll |= SM(0xb, AR_RTC_PLL_DIV); + ah->ah_config.serialize_regmode = + SER_REG_MODE_OFF; } } - REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); - - udelay(RTC_PLL_SETTLE_DELAY); - - REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); -} -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) -{ - u32 phymode; - struct ath_hal_5416 *ahp = AH5416(ah); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s: serialize_regmode is %d\n", + __func__, ah->ah_config.serialize_regmode); - phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 - | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; + if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && + (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && + (ah->ah_macVersion != AR_SREV_VERSION_9160) && + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s: Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", __func__, + ah->ah_macVersion, ah->ah_macRev); + ecode = -EOPNOTSUPP; + goto bad; + } - if (IS_CHAN_HT40(chan)) { - phymode |= AR_PHY_FC_DYN2040_EN; + if (AR_SREV_9100(ah)) { + ahp->ah_iqCalData.calData = &iq_cal_multi_sample; + ahp->ah_suppCals = IQ_MISMATCH_CAL; + ah->ah_isPciExpress = false; + } + ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) - phymode |= AR_PHY_FC_DYN2040_PRI_CH; + if (AR_SREV_9160_10_OR_LATER(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) { + ahp->ah_iqCalData.calData = &iq_cal_single_sample; + ahp->ah_adcGainCalData.calData = + &adc_gain_cal_single_sample; + ahp->ah_adcDcCalData.calData = + &adc_dc_cal_single_sample; + ahp->ah_adcDcCalInitData.calData = + &adc_init_dc_cal; + } else { + ahp->ah_iqCalData.calData = &iq_cal_multi_sample; + ahp->ah_adcGainCalData.calData = + &adc_gain_cal_multi_sample; + ahp->ah_adcDcCalData.calData = + &adc_dc_cal_multi_sample; + ahp->ah_adcDcCalInitData.calData = + &adc_init_dc_cal; + } + ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + } - if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) - phymode |= AR_PHY_FC_DYN2040_EXT_CH; + if (AR_SREV_9160(ah)) { + ah->ah_config.enable_ani = 1; + ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | + ATH9K_ANI_FIRSTEP_LEVEL); + } else { + ahp->ah_ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) { + ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + } } - REG_WRITE(ah, AR_PHY_TURBO, phymode); - ath9k_hw_set11nmac2040(ah, macmode); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, + ah->ah_macVersion, ah->ah_macRev); - REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); - REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); -} + if (AR_SREV_9280_20_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, + ARRAY_SIZE(ar9280Modes_9280_2), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, + ARRAY_SIZE(ar9280Common_9280_2), 2); -static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) -{ - u32 val; - - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); - switch (opmode) { - case ATH9K_M_HOSTAP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case ATH9K_M_IBSS: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); - REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case ATH9K_M_STA: - case ATH9K_M_MONITOR: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); - break; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + } + INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, + ar9280Modes_fast_clock_9280_2, + ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, + ARRAY_SIZE(ar9280Modes_9280), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, + ARRAY_SIZE(ar9280Common_9280), 2); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, + ARRAY_SIZE(ar5416Modes_9160), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, + ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, + ARRAY_SIZE(ar5416Bank0_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, + ARRAY_SIZE(ar5416BB_RfGain_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, + ARRAY_SIZE(ar5416Bank1_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, + ARRAY_SIZE(ar5416Bank2_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, + ARRAY_SIZE(ar5416Bank3_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, + ARRAY_SIZE(ar5416Bank6_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, + ARRAY_SIZE(ar5416Bank6TPC_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, + ARRAY_SIZE(ar5416Bank7_9160), 2); + if (AR_SREV_9160_11(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniAddac, + ar5416Addac_91601_1, + ARRAY_SIZE(ar5416Addac_91601_1), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, + ARRAY_SIZE(ar5416Addac_9160), 2); + } + } else if (AR_SREV_9100_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, + ARRAY_SIZE(ar5416Modes_9100), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, + ARRAY_SIZE(ar5416Common_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, + ARRAY_SIZE(ar5416Bank0_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, + ARRAY_SIZE(ar5416BB_RfGain_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, + ARRAY_SIZE(ar5416Bank1_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, + ARRAY_SIZE(ar5416Bank2_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, + ARRAY_SIZE(ar5416Bank3_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, + ARRAY_SIZE(ar5416Bank6_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, + ARRAY_SIZE(ar5416Bank7_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, + ARRAY_SIZE(ar5416Addac_9100), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, + ARRAY_SIZE(ar5416Modes), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, + ARRAY_SIZE(ar5416Common), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, + ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, + ARRAY_SIZE(ar5416BB_RfGain), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, + ARRAY_SIZE(ar5416Bank1), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, + ARRAY_SIZE(ar5416Bank2), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, + ARRAY_SIZE(ar5416Bank3), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, + ARRAY_SIZE(ar5416Bank7), 2); + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); } -} - -static void -ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) -{ - u32 rfMode = 0; - - if (chan == NULL) - return; - - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - - if (!AR_SREV_9280_10_OR_LATER(ah)) - rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ : - AR_PHY_MODE_RF2GHZ; - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) - rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + if (ah->ah_isPciExpress) + ath9k_hw_configpcipowersave(ah, 0); + else + ath9k_hw_disablepcie(ah); - REG_WRITE(ah, AR_PHY_MODE, rfMode); -} + ecode = ath9k_hw_post_attach(ah); + if (ecode != 0) + goto bad; -static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) -{ - u32 rst_flags; - u32 tmpReg; +#ifndef CONFIG_SLOW_ANT_DIV + if (ah->ah_devid == AR9280_DEVID_PCI) { + for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); + for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { + u32 val = INI_RA(&ahp->ah_iniModes, i, j); - if (AR_SREV_9100(ah)) { - rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | - AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; - } else { - tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if (tmpReg & - (AR_INTR_SYNC_LOCAL_TIMEOUT | - AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - } else { - REG_WRITE(ah, AR_RC, AR_RC_AHB); + INI_RA(&ahp->ah_iniModes, i, j) = + ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, + reg, val); + } } - - rst_flags = AR_RTC_RC_MAC_WARM; - if (type == ATH9K_RESET_COLD) - rst_flags |= AR_RTC_RC_MAC_COLD; + } +#endif + if (!ath9k_hw_fill_cap_info(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s:failed ath9k_hw_fill_cap_info\n", __func__); + ecode = -EINVAL; + goto bad; } - REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); - udelay(50); - - REG_WRITE(ah, (u16) (AR_RTC_RC), 0); - if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { + ecode = ath9k_hw_init_macaddr(ah); + if (ecode != 0) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RTC stuck in MAC reset\n", + "%s: failed initializing mac address\n", __func__); - return false; + goto bad; } - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, 0); + if (AR_SREV_9285(ah)) + ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); + else + ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); - ath9k_hw_init_pll(ah, NULL); + ath9k_init_nfcal_hist_buffer(ah); - if (AR_SREV_9100(ah)) - udelay(50); + return ah; +bad: + if (ahp) + ath9k_hw_detach((struct ath_hal *) ahp); + if (status) + *status = ecode; - return true; + return NULL; } -static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); - REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); + u32 synthDelay; - if (!ath9k_hw_wait(ah, - AR_RTC_STATUS, - AR_RTC_STATUS_M, - AR_RTC_STATUS_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n", - __func__); - return false; - } + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_CCK(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; - ath9k_hw_read_revisions(ah); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); + udelay(synthDelay + BASE_ACTIVATE_DELAY); } -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, - u32 type) +static void ath9k_hw_init_qos(struct ath_hal *ah) { - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); + REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - switch (type) { - case ATH9K_RESET_POWER_ON: - return ath9k_hw_set_reset_power_on(ah); - break; - case ATH9K_RESET_WARM: - case ATH9K_RESET_COLD: - return ath9k_hw_set_reset(ah, type); - break; - default: - return false; - } + REG_WRITE(ah, AR_QOS_NO_ACK, + SM(2, AR_QOS_NO_ACK_TWO_BIT) | + SM(5, AR_QOS_NO_ACK_BIT_OFF) | + SM(0, AR_QOS_NO_ACK_BYTE_OFF)); + + REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); + REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } -static -struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { - if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "2GHz or 5GHz\n", __func__, chan->channel, - chan->channelFlags); - return NULL; - } + u32 pll; - if (!IS_CHAN_OFDM(chan) && - !IS_CHAN_CCK(chan) && - !IS_CHAN_HT20(chan) && - !IS_CHAN_HT40(chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", - __func__, chan->channel, chan->channelFlags); - return NULL; - } - - return ath9k_regd_check_channel(ah, chan); -} - -static inline bool -ath9k_hw_get_lower_upper_index(u8 target, - u8 *pList, - u16 listSize, - u16 *indexL, - u16 *indexR) -{ - u16 i; - - if (target <= pList[0]) { - *indexL = *indexR = 0; - return true; - } - if (target >= pList[listSize - 1]) { - *indexL = *indexR = (u16) (listSize - 1); - return true; - } - - for (i = 0; i < listSize - 1; i++) { - if (pList[i] == target) { - *indexL = *indexR = i; - return true; - } - if (target < pList[i + 1]) { - *indexL = i; - *indexR = (u16) (i + 1); - return false; - } - } - return false; -} - -static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) -{ - int16_t nfval; - int16_t sort[ATH9K_NF_CAL_HIST_MAX]; - int i, j; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) - sort[i] = nfCalBuffer[i]; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { - for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j - 1]) { - nfval = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = nfval; - } - } - } - nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; - - return nfval; -} - -static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, - int16_t *nfarray) -{ - int i; - - for (i = 0; i < NUM_NF_READINGS; i++) { - h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; - - if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) - h[i].currIndex = 0; - - if (h[i].invalidNFcount > 0) { - if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE - || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { - h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; - } else { - h[i].invalidNFcount--; - h[i].privNF = nfarray[i]; - } - } else { - h[i].privNF = - ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); - } - } - return; -} - -static void ar5416GetNoiseFloor(struct ath_hal *ah, - int16_t nfarray[NUM_NF_READINGS]) -{ - int16_t nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 0] is %d\n", nf); - nfarray[0] = nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR9280_PHY_CH1_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR_PHY_CH1_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ctl] [chain 1] is %d\n", nf); - nfarray[1] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), - AR_PHY_CH2_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ctl] [chain 2] is %d\n", nf); - nfarray[2] = nf; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR9280_PHY_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR_PHY_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ext] [chain 0] is %d\n", nf); - nfarray[3] = nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR9280_PHY_CH1_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR_PHY_CH1_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); - nfarray[4] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), - AR_PHY_CH2_EXT_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ext] [chain 2] is %d\n", nf); - nfarray[5] = nf; - } -} - -static bool -getNoiseFloorThresh(struct ath_hal *ah, - const struct ath9k_channel *chan, - int16_t *nft) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5); - break; - case CHANNEL_B: - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel flags 0x%x\n", __func__, - chan->channelFlags); - return false; - } - return true; -} - -static void ath9k_hw_start_nfcal(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); -} - -static void -ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) -{ - struct ath9k_nfcal_hist *h; - int i, j; - int32_t val; - const u32 ar5416_cca_regs[6] = { - AR_PHY_CCA, - AR_PHY_CH1_CCA, - AR_PHY_CH2_CCA, - AR_PHY_EXT_CCA, - AR_PHY_CH1_EXT_CCA, - AR_PHY_CH2_EXT_CCA - }; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else - h = ah->nfCalHist; -#endif - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (h[i].privNF) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } - - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); - - for (j = 0; j < 1000; j++) { - if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) - break; - udelay(10); - } - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } -} - -static int16_t ath9k_hw_getnf(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int16_t nf, nfThresh; - int16_t nfarray[NUM_NF_READINGS] = { 0 }; - struct ath9k_nfcal_hist *h; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - - chan->channelFlags &= (~CHANNEL_CW_INT); - if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: NF did not complete in calibration window\n", - __func__); - nf = 0; - chan->rawNoiseFloor = nf; - return chan->rawNoiseFloor; - } else { - ar5416GetNoiseFloor(ah, nfarray); - nf = nfarray[0]; - if (getNoiseFloorThresh(ah, chan, &nfThresh) - && nf > nfThresh) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: noise floor failed detected; " - "detected %d, threshold %d\n", __func__, - nf, nfThresh); - chan->channelFlags |= CHANNEL_CW_INT; - } - } - -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else - h = ah->nfCalHist; -#endif - - ath9k_hw_update_nfcal_hist_buffer(h, nfarray); - chan->rawNoiseFloor = h[0].privNF; - - return chan->rawNoiseFloor; -} - -static void ath9k_hw_update_mibstats(struct ath_hal *ah, - struct ath9k_mib_stats *stats) -{ - stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); - stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); - stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); - stats->rts_good += REG_READ(ah, AR_RTS_OK); - stats->beacons += REG_READ(ah, AR_BEACON_CNT); -} - -static void ath9k_enable_mib_counters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n"); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - REG_WRITE(ah, AR_MIBC, - ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) - & 0x0f); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); -} - -static void ath9k_hw_disable_mib_counters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n"); - - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); -} - -static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - if (ahp->ah_ani[i].c.channel == chan->channel) - return i; - if (ahp->ah_ani[i].c.channel == 0) { - ahp->ah_ani[i].c.channel = chan->channel; - ahp->ah_ani[i].c.channelFlags = chan->channelFlags; - return i; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "No more channel states left. Using channel 0\n"); - return 0; -} - -static void ath9k_hw_ani_attach(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - ahp->ah_hasHwPhyCounters = 1; - - memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; - ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; - ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; - ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; - ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ahp->ah_ani[i].ofdmWeakSigDetectOff = - !ATH9K_ANI_USE_OFDM_WEAK_SIG; - ahp->ah_ani[i].cckWeakSigThreshold = - ATH9K_ANI_CCK_WEAK_SIG_THR; - ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ahp->ah_hasHwPhyCounters) { - ahp->ah_ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; - } - } - if (ahp->ah_hasHwPhyCounters) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ahp->ah_ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ahp->ah_ani[0].cckPhyErrBase); - - REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); - ath9k_enable_mib_counters(ah); - } - ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; - if (ah->ah_config.enable_ani) - ahp->ah_procPhyErr |= HAL_PROCESS_ANI; -} - -static void ath9k_hw_ani_setup(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; - const int coarseHigh[] = { -14, -14, -14, -14, -12 }; - const int coarseLow[] = { -64, -64, -64, -64, -70 }; - const int firpwr[] = { -78, -78, -78, -78, -80 }; - - for (i = 0; i < 5; i++) { - ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; - ahp->ah_coarseHigh[i] = coarseHigh[i]; - ahp->ah_coarseLow[i] = coarseLow[i]; - ahp->ah_firpwr[i] = firpwr[i]; - } -} - -static void ath9k_hw_ani_detach(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n"); - if (ahp->ah_hasHwPhyCounters) { - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - } -} - - -static bool ath9k_hw_ani_control(struct ath_hal *ah, - enum ath9k_ani_cmd cmd, int param) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState = ahp->ah_curani; - - switch (cmd & ahp->ah_ani_function) { - case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ - u32 level = param; - - if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) ARRAY_SIZE(ahp-> - ah_totalSizeDesired)); - return false; - } - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_TOT_DES, - ahp->ah_totalSizeDesired[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_LOW, - ahp->ah_coarseLow[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_HIGH, - ahp->ah_coarseHigh[level]); - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRPWR, - ahp->ah_firpwr[level]); - - if (level > aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_niup++; - else if (level < aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_nidown++; - aniState->noiseImmunityLevel = level; - break; - } - case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - const int m1ThreshLow[] = { 127, 50 }; - const int m2ThreshLow[] = { 127, 40 }; - const int m1Thresh[] = { 127, 0x4d }; - const int m2Thresh[] = { 127, 0x40 }; - const int m2CountThr[] = { 31, 16 }; - const int m2CountThrLow[] = { 63, 48 }; - u32 on = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, - m2Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, - m2CountThr[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow[on]); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, - m2Thresh[on]); - - if (on) - REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + if (AR_SREV_9100(ah)) { + if (chan && IS_CHAN_5GHZ(chan)) + pll = 0x1450; else - REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - - if (!on != aniState->ofdmWeakSigDetectOff) { - if (on) - ahp->ah_stats.ast_ani_ofdmon++; - else - ahp->ah_stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; - } - break; - } - case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - const int weakSigThrCck[] = { 8, 6 }; - u32 high = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, - weakSigThrCck[high]); - if (high != aniState->cckWeakSigThreshold) { - if (high) - ahp->ah_stats.ast_ani_cckhigh++; - else - ahp->ah_stats.ast_ani_ccklow++; - aniState->cckWeakSigThreshold = high; - } - break; - } - case ATH9K_ANI_FIRSTEP_LEVEL:{ - const int firstep[] = { 0, 4, 8 }; - u32 level = param; - - if (level >= ARRAY_SIZE(firstep)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) ARRAY_SIZE(firstep)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - firstep[level]); - if (level > aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepup++; - else if (level < aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepdown++; - aniState->firstepLevel = level; - break; - } - case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - const int cycpwrThr1[] = - { 2, 4, 6, 8, 10, 12, 14, 16 }; - u32 level = param; - - if (level >= ARRAY_SIZE(cycpwrThr1)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) - ARRAY_SIZE(cycpwrThr1)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - cycpwrThr1[level]); - if (level > aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurup++; - else if (level < aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurdown++; - aniState->spurImmunityLevel = level; - break; - } - case ATH9K_ANI_PRESENT: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: invalid cmd %u\n", __func__, cmd); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, " - "ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cckWeakSigThreshold=%d, " - "firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, aniState->firstepLevel, - aniState->listenTime); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, aniState->ofdmPhyErrCount, - aniState->cckPhyErrCount); - return true; -} - -static void ath9k_ani_restart(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - - aniState->listenTime = 0; - if (ahp->ah_hasHwPhyCounters) { - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; - } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Writing ofdmbase=%u cckbase=%u\n", - __func__, aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - } - aniState->ofdmPhyErrCount = 0; - aniState->cckPhyErrCount = 0; -} - -static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - struct ar5416AniState *aniState; - enum wireless_mode mode; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; + pll = 0x1458; + } else { + if (AR_SREV_9280_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel + 1)) { - return; - } - } + if (chan && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrHigh) { - if (!aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false)) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - 0); - return; - } - } - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true); - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { - if (!aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false); - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - 0); - return; - } - } -} - -static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - struct ar5416AniState *aniState; - enum wireless_mode mode; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrLow) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - 0); - } - } -} - -static void ath9k_ani_reset(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - struct ath9k_channel *chan = ah->ah_curchan; - int index; - - if (!DO_ANI(ah)) - return; - - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ahp->ah_ani[index]; - ahp->ah_curani = aniState; - - if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA - && ah->ah_opmode != ATH9K_M_IBSS) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Reset ANI state opmode %u\n", __func__, - ah->ah_opmode); - ahp->ah_stats.ast_ani_reset++; - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !ATH9K_ANI_USE_OFDM_WEAK_SIG); - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - ATH9K_ANI_CCK_WEAK_SIG_THR); - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - ahp->ah_curani->ofdmTrigHigh = - ah->ah_config.ofdm_trig_high; - ahp->ah_curani->ofdmTrigLow = - ah->ah_config.ofdm_trig_low; - ahp->ah_curani->cckTrigHigh = - ah->ah_config.cck_trig_high; - ahp->ah_curani->cckTrigLow = - ah->ah_config.cck_trig_low; - } - ath9k_ani_restart(ah); - return; - } - - if (aniState->noiseImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel); - if (aniState->spurImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel); - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !aniState->ofdmWeakSigDetectOff); - if (aniState->cckWeakSigThreshold) - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - aniState->cckWeakSigThreshold); - if (aniState->firstepLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel); - if (ahp->ah_hasHwPhyCounters) { - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - } else { - ath9k_ani_restart(ah); - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - } -} - -/* - * Process a MIB interrupt. We may potentially be invoked because - * any of the MIB counters overflow/trigger so don't assume we're - * here because a PHY error counter triggered. - */ -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 phyCnt1, phyCnt2; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n"); - /* Reset these counters regardless */ - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) - REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); - - /* Clear the mib counters and save them in the stats */ - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - ahp->ah_stats.ast_nodestats = *stats; - - if (!DO_ANI(ah)) - return; - - /* NB: these are not reset-on-read */ - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || - ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = ahp->ah_curani; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - - /* - * NB: figure out which counter triggered. If both - * trigger we'll only deal with one as the processing - * clobbers the error counter so the trigger threshold - * check will never be true. - */ - if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) - ath9k_hw_ani_ofdm_err_trigger(ah); - if (aniState->cckPhyErrCount > aniState->cckTrigHigh) - ath9k_hw_ani_cck_err_trigger(ah); - /* NB: always restart to insure the h/w counters are reset */ - ath9k_ani_restart(ah); - } -} - -static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = ahp->ah_curani; - - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) { - return; - } - } - } else { - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrHigh) { - /* XXX: Handle me */ - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true) == - true) { - return; - } - } - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control - (ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == - true) { - return; - } - } - } else { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control - (ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == - true) { - return; - } - } - } - } - - if (aniState->spurImmunityLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel - 1)) { - return; - } - } - - if (aniState->noiseImmunityLevel > 0) { - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel - 1); - return; - } -} - -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - u32 txFrameCount, rxFrameCount, cycleCount; - int32_t listenTime; - - txFrameCount = REG_READ(ah, AR_TFCNT); - rxFrameCount = REG_READ(ah, AR_RFCNT); - cycleCount = REG_READ(ah, AR_CCCNT); - - aniState = ahp->ah_curani; - if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { - - listenTime = 0; - ahp->ah_stats.ast_ani_lzero++; - } else { - int32_t ccdelta = cycleCount - aniState->cycleCount; - int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; - int32_t tfdelta = txFrameCount - aniState->txFrameCount; - listenTime = (ccdelta - rfdelta - tfdelta) / 44000; - } - aniState->cycleCount = cycleCount; - aniState->txFrameCount = txFrameCount; - aniState->rxFrameCount = rxFrameCount; - - return listenTime; -} - -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - int32_t listenTime; - - aniState = ahp->ah_curani; - ahp->ah_stats.ast_nodestats = *stats; - - listenTime = ath9k_hw_ani_get_listen_time(ah); - if (listenTime < 0) { - ahp->ah_stats.ast_ani_lneg++; - ath9k_ani_restart(ah); - return; - } - - aniState->listenTime += listenTime; - - if (ahp->ah_hasHwPhyCounters) { - u32 phyCnt1, phyCnt2; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - __func__, phyCnt1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - __func__, phyCnt2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; - } - - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - } - - if (!DO_ANI(ah)) - return; - - if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { - if (aniState->ofdmPhyErrCount <= aniState->listenTime * - aniState->ofdmTrigLow / 1000 && - aniState->cckPhyErrCount <= aniState->listenTime * - aniState->cckTrigLow / 1000) - ath9k_hw_ani_lower_immunity(ah); - ath9k_ani_restart(ah); - } else if (aniState->listenTime > ahp->ah_aniPeriod) { - if (aniState->ofdmPhyErrCount > aniState->listenTime * - aniState->ofdmTrigHigh / 1000) { - ath9k_hw_ani_ofdm_err_trigger(ah); - ath9k_ani_restart(ah); - } else if (aniState->cckPhyErrCount > - aniState->listenTime * aniState->cckTrigHigh / - 1000) { - ath9k_hw_ani_cck_err_trigger(ah); - ath9k_ani_restart(ah); - } - } -} - -#ifndef ATH_NF_PER_CHAN -static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) -{ - int i, j; - - for (i = 0; i < NUM_NF_READINGS; i++) { - ah->nfCalHist[i].currIndex = 0; - ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; - ah->nfCalHist[i].invalidNFcount = - AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ah->nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; - } - } - return; -} -#endif - -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, - u32 gpio, u32 type) -{ - int addr; - u32 gpio_shift, tmp; - - if (gpio > 11) - addr = AR_GPIO_OUTPUT_MUX3; - else if (gpio > 5) - addr = AR_GPIO_OUTPUT_MUX2; - else - addr = AR_GPIO_OUTPUT_MUX1; - - gpio_shift = (gpio % 6) * 5; - - if (AR_SREV_9280_20_OR_LATER(ah) - || (addr != AR_GPIO_OUTPUT_MUX1)) { - REG_RMW(ah, addr, (type << gpio_shift), - (0x1f << gpio_shift)); - } else { - tmp = REG_READ(ah, addr); - tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); - tmp &= ~(0x1f << gpio_shift); - tmp |= (type << gpio_shift); - REG_WRITE(ah, addr, tmp); - } -} - -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - u32 ah_signal_type) -{ - u32 gpio_shift; - - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - - gpio_shift = 2 * gpio; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -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)); -} - -/* - * Configure GPIO Input lines - */ -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) -{ - u32 gpio_shift; - - ASSERT(gpio < ah->ah_caps.num_gpio_pins); - - gpio_shift = gpio << 1; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -#ifdef CONFIG_RFKILL -static void ath9k_enable_rfkill(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - - REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, - AR_GPIO_INPUT_MUX2_RFSILENT); - - ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); -} -#endif - -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) -{ - if (gpio >= ah->ah_caps.num_gpio_pins) - return 0xffffffff; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - return (MS - (REG_READ(ah, AR_GPIO_IN_OUT), - AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; - } else { - return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & - AR_GPIO_BIT(gpio)) != 0; - } -} - -static int ath9k_hw_post_attach(struct ath_hal *ah) -{ - int ecode; - - if (!ath9k_hw_chip_test(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: hardware self-test failed\n", __func__); - return -ENODEV; - } - - ecode = ath9k_hw_rf_claim(ah); - if (ecode != 0) - return ecode; - - ecode = ath9k_hw_eeprom_attach(ah); - if (ecode != 0) - return ecode; - ecode = ath9k_hw_rfattach(ah); - if (ecode != 0) - return ecode; - - if (!AR_SREV_9100(ah)) { - ath9k_hw_ani_setup(ah); - ath9k_hw_ani_attach(ah); - } - return 0; -} - -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - u32 reg, u32 value) -{ - struct base_eep_header *pBase = &(pEepData->baseEepHeader); - - switch (ah->ah_devid) { - case AR9280_DEVID_PCI: - if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "ini VAL: %x EEPROM: %x\n", value, - (pBase->version & 0xff)); - - if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "PWDCLKIND: %d\n", - pBase->pwdclkind); - value &= ~AR_AN_TOP2_PWDCLKIND; - value |= AR_AN_TOP2_PWDCLKIND & (pBase-> - pwdclkind << AR_AN_TOP2_PWDCLKIND_S); - } else { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "PWDCLKIND Earlier Rev\n"); - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "final ini VAL: %x\n", value); - } - break; - } - return value; -} - -static bool ath9k_hw_fill_cap_info(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 capField = 0, eeval; - - eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0); - - ah->ah_currentRD = eeval; - - eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1); - ah->ah_currentRDExt = eeval; - - capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP); - - if (ah->ah_opmode != ATH9K_M_HOSTAP && - ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) - ah->ah_currentRD += 5; - else if (ah->ah_currentRD == 0x41) - ah->ah_currentRD = 0x43; - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: regdomain mapped to 0x%x\n", __func__, - ah->ah_currentRD); - } - - eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE); - bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - - if (eeval & AR5416_OPFLAGS_11A) { - set_bit(ATH9K_MODE_11A, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) - set_bit(ATH9K_MODE_11NA_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { - set_bit(ATH9K_MODE_11NA_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NA_HT40MINUS, - pCap->wireless_modes); - } - } - } - - if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11B, pCap->wireless_modes); - set_bit(ATH9K_MODE_11G, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) - set_bit(ATH9K_MODE_11NG_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { - set_bit(ATH9K_MODE_11NG_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NG_HT40MINUS, - pCap->wireless_modes); - } - } - } - - pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK); - if ((ah->ah_isPciExpress) - || (eeval & AR5416_OPFLAGS_11A)) { - pCap->rx_chainmask = - ath9k_hw_get_eeprom(ahp, EEP_RX_MASK); - } else { - pCap->rx_chainmask = - (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; - } - - if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) - ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; - - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - - pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; - - pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - - pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - - if (ah->ah_config.ht_enable) - pCap->hw_caps |= ATH9K_HW_CAP_HT; - else - pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - - pCap->hw_caps |= ATH9K_HW_CAP_GTT; - pCap->hw_caps |= ATH9K_HW_CAP_VEOL; - pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; - pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - - pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->num_mr_retries = 4; - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - - if (AR_SREV_9280_10_OR_LATER(ah)) - pCap->num_gpio_pins = AR928X_NUM_GPIO; - else - pCap->num_gpio_pins = AR_NUM_GPIO; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_WOW; - pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } else { - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } - - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_CST; - pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; - } else { - pCap->rts_aggr_limit = (8 * 1024); - } - - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - -#ifdef CONFIG_RFKILL - ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT); - if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { - ah->ah_rfkill_gpio = - MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); - ah->ah_rfkill_polarity = - MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - - pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; - } -#endif - - if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || - (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || - (ah->ah_macVersion == AR_SREV_VERSION_9160) || - (ah->ah_macVersion == AR_SREV_VERSION_9100) || - (ah->ah_macVersion == AR_SREV_VERSION_9280)) - pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; - else - pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - - if (AR_SREV_9280(ah)) - pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; - else - pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - - if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - - pCap->num_antcfg_5ghz = - ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ); - pCap->num_antcfg_2ghz = - ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ); - - return true; -} - -static void ar5416DisablePciePhy(struct ath_hal *ah) -{ - if (!AR_SREV_9100(ah)) - return; - - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); - REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); -} - -static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - - REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), - AR_RTC_RESET_EN); - } -} - -static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_ON_INT); - } else { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - } -} - -static bool ath9k_hw_set_power_awake(struct ath_hal *ah, - int setChip) -{ - u32 val; - int i; - - if (setChip) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == - AR_RTC_STATUS_SHUTDOWN) { - if (ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON) - != true) { - return false; - } - } - if (AR_SREV_9100(ah)) - REG_SET_BIT(ah, AR_RTC_RESET, - AR_RTC_RESET_EN); - - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - udelay(50); - - for (i = POWER_UP_TIME / 50; i > 0; i--) { - val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; - if (val == AR_RTC_STATUS_ON) - break; - udelay(50); - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: Failed to wakeup in %uus\n", - __func__, POWER_UP_TIME / 20); - return false; - } - } - - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - return true; -} - -bool ath9k_hw_setpower(struct ath_hal *ah, - enum ath9k_power_mode mode) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - static const char *modes[] = { - "AWAKE", - "FULL-SLEEP", - "NETWORK SLEEP", - "UNDEFINED" - }; - int status = true, setChip = true; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], - setChip ? "set chip " : ""); - - switch (mode) { - case ATH9K_PM_AWAKE: - status = ath9k_hw_set_power_awake(ah, setChip); - break; - case ATH9K_PM_FULL_SLEEP: - ath9k_set_power_sleep(ah, setChip); - ahp->ah_chipFullSleep = true; - break; - case ATH9K_PM_NETWORK_SLEEP: - ath9k_set_power_network_sleep(ah, setChip); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: unknown power mode %u\n", __func__, mode); - return false; - } - ahp->ah_powerMode = mode; - return status; -} - -static struct ath_hal *ath9k_hw_do_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *status) -{ - struct ath_hal_5416 *ahp; - struct ath_hal *ah; - int ecode; -#ifndef CONFIG_SLOW_ANT_DIV - u32 i; - u32 j; -#endif - - ahp = ath9k_hw_newstate(devid, sc, mem, status); - if (ahp == NULL) - return NULL; - - ah = &ahp->ah; - - ath9k_hw_set_defaults(ah); - - if (ah->ah_config.intr_mitigation != 0) - ahp->ah_intrMitigation = true; - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n", - __func__); - ecode = -EIO; - goto bad; - } - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n", - __func__); - ecode = -EIO; - goto bad; - } - - if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { - ah->ah_config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->ah_config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: serialize_regmode is %d\n", - __func__, ah->ah_config.serialize_regmode); - - if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->ah_macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", __func__, - ah->ah_macVersion, ah->ah_macRev); - ecode = -EOPNOTSUPP; - goto bad; - } - - if (AR_SREV_9100(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_suppCals = IQ_MISMATCH_CAL; - ah->ah_isPciExpress = false; - } - ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - - if (AR_SREV_9160_10_OR_LATER(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_single_sample; - ahp->ah_adcGainCalData.calData = - &adc_gain_cal_single_sample; - ahp->ah_adcDcCalData.calData = - &adc_dc_cal_single_sample; - ahp->ah_adcDcCalInitData.calData = - &adc_init_dc_cal; - } else { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_adcGainCalData.calData = - &adc_gain_cal_multi_sample; - ahp->ah_adcDcCalData.calData = - &adc_dc_cal_multi_sample; - ahp->ah_adcDcCalInitData.calData = - &adc_init_dc_cal; - } - ahp->ah_suppCals = - ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; - } - - if (AR_SREV_9160(ah)) { - ah->ah_config.enable_ani = 1; - ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - } else { - ahp->ah_ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_ani_function &= - ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, - ah->ah_macVersion, ah->ah_macRev); - - if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, - ARRAY_SIZE(ar9280Common_9280_2), 2); - - if (ah->ah_config.pcie_clock_req) { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE - (ar9280PciePhy_clkreq_off_L1_9280), - 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE - (ar9280PciePhy_clkreq_always_on_L1_9280), - 2); - } - INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, - ar9280Modes_fast_clock_9280_2, - ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), - 3); - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, - ARRAY_SIZE(ar9280Modes_9280), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, - ARRAY_SIZE(ar9280Common_9280), 2); - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, - ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, - ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, - ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, - ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, - ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, - ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, - ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, - ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, - ARRAY_SIZE(ar5416Bank7_9160), 2); - if (AR_SREV_9160_11(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniAddac, - ar5416Addac_91601_1, - ARRAY_SIZE(ar5416Addac_91601_1), 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, - ARRAY_SIZE(ar5416Addac_9160), 2); - } - } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, - ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, - ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, - ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, - ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, - ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, - ARRAY_SIZE(ar5416Bank3_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, - ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, - ARRAY_SIZE(ar5416Bank7_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, - ARRAY_SIZE(ar5416Addac_9100), 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, - ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, - ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, - ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, - ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, - ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); - } - - if (ah->ah_isPciExpress) - ath9k_hw_configpcipowersave(ah, 0); - else - ar5416DisablePciePhy(ah); - - ecode = ath9k_hw_post_attach(ah); - if (ecode != 0) - goto bad; - -#ifndef CONFIG_SLOW_ANT_DIV - if (ah->ah_devid == AR9280_DEVID_PCI) { - for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - - for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { - u32 val = INI_RA(&ahp->ah_iniModes, i, j); - - INI_RA(&ahp->ah_iniModes, i, j) = - ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, - reg, val); - } - } - } -#endif - - if (!ath9k_hw_fill_cap_info(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s:failed ath9k_hw_fill_cap_info\n", __func__); - ecode = -EINVAL; - goto bad; - } - - ecode = ath9k_hw_init_macaddr(ah); - if (ecode != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: failed initializing mac address\n", - __func__); - goto bad; - } - - if (AR_SREV_9285(ah)) - ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); - else - ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); - -#ifndef ATH_NF_PER_CHAN - - ath9k_init_nfcal_hist_buffer(ah); -#endif - - return ah; - -bad: - if (ahp) - ath9k_hw_detach((struct ath_hal *) ahp); - if (status) - *status = ecode; - return NULL; -} - -void ath9k_hw_detach(struct ath_hal *ah) -{ - if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); - ath9k_hw_rfdetach(ah); - - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - kfree(ah); -} - -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - - return true; - } - return false; -} - -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, - u8 pwrMax, - u8 *pPwrList, - u8 *pVpdList, - u16 - numIntercepts, - u8 *pRetVpdList) -{ - u16 i, k; - u8 currPwr = pwrMin; - u16 idxL = 0, idxR = 0; - - for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { - ath9k_hw_get_lower_upper_index(currPwr, pPwrList, - numIntercepts, &(idxL), - &(idxR)); - if (idxR < 1) - idxR = 1; - if (idxL == numIntercepts - 1) - idxL = (u16) (numIntercepts - 2); - if (pPwrList[idxL] == pPwrList[idxR]) - k = pVpdList[idxL]; - else - k = (u16) (((currPwr - - pPwrList[idxL]) * - pVpdList[idxR] + - (pPwrList[idxR] - - currPwr) * pVpdList[idxL]) / - (pPwrList[idxR] - - pPwrList[idxL])); - pRetVpdList[i] = (u8) k; - currPwr += 2; - } - - return true; -} - -static void -ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, - u16 availPiers, - u16 tPdGainOverlap, - int16_t *pMinCalPower, - u16 *pPdGainBoundaries, - u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), bChans, - numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL]. - pwrPdg[i], - pRawDataSet[idxL]. - vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8) (ath9k_hw_interpolate - ((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], - bChans[idxR], vpdTableL[i] - [j], vpdTableR[i] - [j])); - } - } - } - - *pMinCalPower = (int16_t) (minPwrT4[0] / 2); - - k = 0; - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16) (maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16) ((maxPwrT4[i] + - minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16) AR5416_MAX_RATE_POWER, - pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t) (0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t) ((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = - (u8) ((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = - (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < - sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) ((vpdTableI[i] - [sizeCurrVpdTable - - 1] + (ss - maxIndex + - 1) * vpdStep)); - pPDADCValues[k++] = (u8) ((tmpVal > - 255) ? 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - return; -} - -static bool -ath9k_hw_set_power_cal_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - struct ath_hal_5416 *ahp = AH5416(ah); - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = - (u16) (MS - (REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16) (AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, - pRawDataset, - pCalBChans, - numPiers, - pdGainOverlap_t2, - &tMinCalPower, - gainBoundaries, - pdadcValues, - numXpdGain); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = - AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = - ((pdadcValues[4 * j + 0] & 0xFF) << 0) - | ((pdadcValues[4 * j + 1] & 0xFF) << - 8) | ((pdadcValues[4 * j + 2] & - 0xFF) << 16) | - ((pdadcValues[4 * j + 3] & 0xFF) << - 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "PDADC: Chain %d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - *pTxPowerIndexOffset = 0; - - return true; -} - -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u8 i; - - if (ah->ah_isPciExpress != true) - return; - - if (ah->ah_config.pcie_powersave_enable == 2) - return; - - if (restore) - return; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { - REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), - INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); - } - udelay(1000); - } else if (AR_SREV_9280(ah) - && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); - REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); - - if (ah->ah_config.pcie_clock_req) - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); - else - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - - udelay(1000); - } else { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); - REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - } - - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - if (ah->ah_config.pcie_waen) { - REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); - } else { - if (AR_SREV_9280(ah)) - REG_WRITE(ah, AR_WA, 0x0040073f); - else - REG_WRITE(ah, AR_WA, 0x0000073f); - } -} - -static void -ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, - bool isExtTarget) -{ - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) - && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else if ((freq < - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) - && (freq > - ath9k_hw_fbin2freq(powInfo[i - 1]. - bChannel, - IS_CHAN_2GHZ - (chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8) ath9k_hw_interpolate(freq, clo, chi, - powInfo - [lowIndex]. - tPow2x[i], - powInfo - [lowIndex + - 1].tPow2x[i]); - } - } -} - -static void -ath9k_hw_get_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, - bool isHt40Target) -{ - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = isHt40Target ? centers.synth_center : centers.ctl_center; - - if (freq <= - ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) - && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else - if ((freq < - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) - && (freq > - ath9k_hw_fbin2freq(powInfo[i - 1]. - bChannel, - IS_CHAN_2GHZ - (chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8) ath9k_hw_interpolate(freq, clo, chi, - powInfo - [lowIndex]. - tPow2x[i], - powInfo - [lowIndex + - 1].tPow2x[i]); - } - } -} - -static u16 -ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz) -{ - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - int i; - - for (i = 0; (i < AR5416_NUM_BAND_EDGES) - && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, - is2GHz)) { - twiceMaxEdgePower = pRdEdgesPower[i].tPower; - break; - } else if ((i > 0) - && (freq < - ath9k_hw_fbin2freq(pRdEdgesPower[i]. - bChannel, is2GHz))) { - if (ath9k_hw_fbin2freq - (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq - && pRdEdgesPower[i - 1].flag) { - twiceMaxEdgePower = - pRdEdgesPower[i - 1].tPower; - } - break; - } - } - return twiceMaxEdgePower; -} - -static bool -ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u8 AntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int8_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u8 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u8 twiceMinEdgePower; - struct ath_hal_5416 *ahp = AH5416(ah); - - tx_chainmask = ahp->ah_txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8) twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = - (int8_t) min(AntennaReduction - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->ah_tpScale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)]. - pwrDecreaseFor2Chain; - break; - case 3: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)]. - pwrDecreaseFor3Chain; - break; - } - - scaledPower = max(0, (int32_t) scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = - ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, - false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, - false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData-> - calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, - true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, - 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, - 4, true); - } - } else { - - numCtlModes = - ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, - false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData-> - calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, - true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, - 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = - (pCtlMode[ctlMode] == CTL_5GHT40) - || (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ar5416_get_eep_ver(ahp) == 14 - && ar5416_get_eep_rev(ahp) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; - i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) - || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData-> - ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep-> - ctlEdges - [ar5416_get_ntxchains - (tx_chainmask) - - 1], - IS_CHAN_2GHZ - (chan)); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = - min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = - twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = - min(targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = - min(targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = - min(targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = - min(targetPowerCckExt.tPow2x[0], minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = - min(targetPowerOfdmExt.tPow2x[0], minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = - min(targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - ; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } - return true; -} - -static int -ath9k_hw_set_txpower(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } - - if (!ath9k_hw_set_power_cal_table - (ah, pEepData, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = - (int16_t) (txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0) - ); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0) - ); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) - ); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0) - ); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0) - ); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0) - ); - - i = rate6mb; - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->ah_maxPowerLevel = ratesArray[i]; - - return 0; -} - -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, - u32 coef_scaled, - u32 *coef_mantissa, - u32 *coef_exponent) -{ - u32 coef_exp, coef_man; - - for (coef_exp = 31; coef_exp > 0; coef_exp--) - if ((coef_scaled >> coef_exp) & 0x1) - break; - - coef_exp = 14 - (coef_exp - COEF_SCALE_S); - - coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); - - *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); - *coef_exponent = coef_exp - 16; -} - -static void -ath9k_hw_set_delta_slope(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 coef_scaled, ds_coef_exp, ds_coef_man; - u32 clockMhzScaled = 0x64000000; - struct chan_centers centers; - - if (IS_CHAN_HALF_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 1; - else if (IS_CHAN_QUARTER_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 2; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - coef_scaled = clockMhzScaled / centers.synth_center; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); - - coef_scaled = (9 * coef_scaled) / 10; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); -} - -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int freq; - int bin, cur_bin; - int bb_spur_off, spur_subchannel_sd; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, newVal; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - struct chan_centers centers; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); - - if (is2GHz) - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; - else - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; - - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - freq; - - if (IS_CHAN_HT40(chan)) { - if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { - bb_spur = cur_bb_spur; - break; - } - } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - return; - } else { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - } - - bin = bb_spur * 320; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - - newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); - - newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); - - if (IS_CHAN_HT40(chan)) { - if (bb_spur < 0) { - spur_subchannel_sd = 1; - bb_spur_off = bb_spur + 10; - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur - 10; - } - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur; - } - - if (IS_CHAN_HT40(chan)) - spur_delta_phase = - ((bb_spur * 262144) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - else - spur_delta_phase = - ((bb_spur * 524288) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; - spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; - - newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, newVal); - - newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; - REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); - - if (tmp < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, new; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); - - if (tmp < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + if (AR_SREV_9280_20(ah)) { + if (((chan->channel % 20) == 0) + || ((chan->channel % 10) == 0)) + pll = 0x2850; + else + pll = 0x142c; + } + } else { + pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); + } - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_9160_PLL_DIV); + else + pll |= SM(0x58, AR_RTC_9160_PLL_DIV); + } else { + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0xa, AR_RTC_PLL_DIV); + else + pll |= SM(0xb, AR_RTC_PLL_DIV); + } + } + REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); + udelay(RTC_PLL_SETTLE_DELAY); + + REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); } static void ath9k_hw_init_chain_masks(struct ath_hal *ah) @@ -5159,102 +987,34 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); } -static void ath9k_hw_set_addac(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, enum ath9k_opmode opmode) { - struct modal_eep_header *pModal; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 biaslevel; - - if (ah->ah_macVersion != AR_SREV_VERSION_9160) - return; - - if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - resetFreqBin = - FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)); - freqBin = pModal->xpaBiasLvlFreq[0] & 0xff; - biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14); - - freqCount++; - - while (freqCount < 3) { - if (pModal->xpaBiasLvlFreq[freqCount] == 0x0) - break; - - freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff; - if (resetFreqBin >= freqBin) { - biaslevel = - (u8) (pModal-> - xpaBiasLvlFreq[freqCount] - >> 14); - } else { - break; - } - freqCount++; - } - } - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ahp->ah_iniAddac, 7, 1) = - (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel - << 3; - } else { - INI_RA(&ahp->ah_iniAddac, 6, 1) = - (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel - << 6; - } -} + ahp->ah_maskReg = AR_IMR_TXERR | + AR_IMR_TXURN | + AR_IMR_RXERR | + AR_IMR_RXORN | + AR_IMR_BCNMISC; -static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) -{ - if (ah->ah_curchan != NULL) - return clks / - CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; + if (ahp->ah_intrMitigation) + ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else - return clks / CLOCK_RATE[ATH9K_MODE_11B]; -} - -static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) -{ - struct ath9k_channel *chan = ah->ah_curchan; + ahp->ah_maskReg |= AR_IMR_RXOK; - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_usec(ah, clks) / 2; - else - return ath9k_hw_mac_usec(ah, clks); -} + ahp->ah_maskReg |= AR_IMR_TXOK; -static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) -{ - if (ah->ah_curchan != NULL) - return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, - ah->ah_curchan)]; - else - return usecs * CLOCK_RATE[ATH9K_MODE_11B]; -} + if (opmode == ATH9K_M_HOSTAP) + ahp->ah_maskReg |= AR_IMR_MIB; -static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) -{ - struct ath9k_channel *chan = ah->ah_curchan; + REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); + REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_clks(ah, usecs) * 2; - else - return ath9k_hw_mac_clks(ah, usecs); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + } } static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) @@ -5290,8 +1050,8 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) return true; } } -static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, - u32 tu) + +static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -5307,45 +1067,117 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, } } -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) +static void ath9k_hw_init_user_settings(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); - if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n", - __func__, us); - ahp->ah_slottime = (u32) -1; - return false; - } else { - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_slottime = us; - return true; + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n", + __func__, ahp->ah_miscMode); + + if (ahp->ah_miscMode != 0) + REG_WRITE(ah, AR_PCU_MISC, + REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); + if (ahp->ah_slottime != (u32) -1) + ath9k_hw_setslottime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u32) -1) + ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u32) -1) + ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); + if (ahp->ah_globaltxtimeout != (u32) -1) + ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); +} + +const char *ath9k_hw_probe(u16 vendorid, u16 devid) +{ + return vendorid == ATHEROS_VENDOR_ID ? + ath9k_hw_devname(devid) : NULL; +} + +void ath9k_hw_detach(struct ath_hal *ah) +{ + if (!AR_SREV_9100(ah)) + ath9k_hw_ani_detach(ah); + + ath9k_hw_rfdetach(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + kfree(ah); +} + +struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *error) +{ + struct ath_hal *ah = NULL; + + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + ah = ath9k_hw_do_attach(devid, sc, mem, error); + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "devid=0x%x not supported.\n", devid); + ah = NULL; + *error = -ENXIO; + break; } + + return ah; +} + +/*******/ +/* INI */ +/*******/ + +static void ath9k_hw_override_ini(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + if (!AR_SREV_5416_V20_OR_LATER(ah) || + AR_SREV_9280_10_OR_LATER(ah)) + return; + + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } -static void ath9k_hw_init_user_settings(struct ath_hal *ah) +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom *pEepData, + u32 reg, u32 value) { - struct ath_hal_5416 *ahp = AH5416(ah); + struct base_eep_header *pBase = &(pEepData->baseEepHeader); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n", - __func__, ahp->ah_miscMode); - if (ahp->ah_miscMode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); - if (ahp->ah_slottime != (u32) -1) - ath9k_hw_setslottime(ah, ahp->ah_slottime); - if (ahp->ah_acktimeout != (u32) -1) - ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); - if (ahp->ah_ctstimeout != (u32) -1) - ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); - if (ahp->ah_globaltxtimeout != (u32) -1) - ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); + switch (ah->ah_devid) { + case AR9280_DEVID_PCI: + if (reg == 0x7894) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "ini VAL: %x EEPROM: %x\n", value, + (pBase->version & 0xff)); + + if ((pBase->version & 0xff) > 0x0a) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "PWDCLKIND: %d\n", + pBase->pwdclkind); + value &= ~AR_AN_TOP2_PWDCLKIND; + value |= AR_AN_TOP2_PWDCLKIND & + (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); + } else { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "PWDCLKIND Earlier Rev\n"); + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "final ini VAL: %x\n", value); + } + break; + } + + return value; } -static int -ath9k_hw_process_ini(struct ath_hal *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static int ath9k_hw_process_ini(struct ath_hal *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { int i, regWrites = 0; struct ath_hal_5416 *ahp = AH5416(ah); @@ -5396,14 +1228,14 @@ ath9k_hw_process_ini(struct ath_hal *ah, memcpy(ahp->ah_addac5416_21, ahp->ah_iniAddac.ia_array, addacSize); - (ahp->ah_addac5416_21)[31 * - ahp->ah_iniAddac.ia_columns + 1] = 0; + (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0; temp.ia_array = ahp->ah_addac5416_21; temp.ia_columns = ahp->ah_iniAddac.ia_columns; temp.ia_rows = ahp->ah_iniAddac.ia_rows; REG_WRITE_ARRAY(&temp, 1, regWrites); } + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { @@ -5412,8 +1244,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, #ifdef CONFIG_SLOW_ANT_DIV if (ah->ah_devid == AR9280_DEVID_PCI) - val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, - val); + val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, val); #endif REG_WRITE(ah, reg, val); @@ -5451,7 +1282,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, ath9k_hw_set_regs(ah, chan, macmode); ath9k_hw_init_chain_masks(ah); - status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, + status = ath9k_hw_set_txpower(ah, chan, ath9k_regd_get_ctl(ah, chan), ath9k_regd_get_antenna_allowed(ah, chan), @@ -5460,178 +1291,323 @@ ath9k_hw_process_ini(struct ath_hal *ah, (u32) ah->ah_powerLimit)); if (status != 0) { DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: error init'ing transmit power\n", __func__); + "%s: error init'ing transmit power\n", __func__); return -EIO; } if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: ar5416SetRfRegs failed\n", __func__); + "%s: ar5416SetRfRegs failed\n", __func__); return -EIO; } return 0; } -static void ath9k_hw_setup_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +/****************************************/ +/* Reset and Channel Switching Routines */ +/****************************************/ + +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, - currCal->calData->calCountMax); - - switch (currCal->calData->calType) { - case IQ_MISMATCH_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting IQ Mismatch Calibration\n", - __func__); + u32 rfMode = 0; + + if (chan == NULL) + return; + + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + + if (!AR_SREV_9280_10_OR_LATER(ah)) + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} + +static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} + +static inline void ath9k_hw_set_dma(struct ath_hal *ah) +{ + u32 regval; + + regval = REG_READ(ah, AR_AHB_MODE); + REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + + regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + + regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + + REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + + if (AR_SREV_9285(ah)) { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); + } else { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_PCU_TXBUF_CTRL_USABLE_SIZE); + } +} + +static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) +{ + u32 val; + + val = REG_READ(ah, AR_STA_ID1); + val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); + switch (opmode) { + case ATH9K_M_HOSTAP: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP + | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ADC_GAIN_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC Gain Calibration\n", __func__); + case ATH9K_M_IBSS: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC + | AR_STA_ID1_KSRCH_MODE); + REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ADC_DC_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC DC Calibration\n", __func__); + case ATH9K_M_STA: + case ATH9K_M_MONITOR: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); break; - case ADC_DC_INIT_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting Init ADC DC Calibration\n", + } +} + +static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, + u32 coef_scaled, + u32 *coef_mantissa, + u32 *coef_exponent) +{ + u32 coef_exp, coef_man; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + coef_exp = 14 - (coef_exp - COEF_SCALE_S); + + coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); + + *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); + *coef_exponent = coef_exp - 16; +} + +static void ath9k_hw_set_delta_slope(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + u32 coef_scaled, ds_coef_exp, ds_coef_man; + u32 clockMhzScaled = 0x64000000; + struct chan_centers centers; + + if (IS_CHAN_HALF_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 1; + else if (IS_CHAN_QUARTER_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 2; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); + + coef_scaled = (9 * coef_scaled) / 10; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +} + +static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) +{ + u32 rst_flags; + u32 tmpReg; + + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); + + if (AR_SREV_9100(ah)) { + rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | + AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; + } else { + tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (tmpReg & + (AR_INTR_SYNC_LOCAL_TIMEOUT | + AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); + } else { + REG_WRITE(ah, AR_RC, AR_RC_AHB); + } + + rst_flags = AR_RTC_RC_MAC_WARM; + if (type == ATH9K_RESET_COLD) + rst_flags |= AR_RTC_RC_MAC_COLD; + } + + REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); + udelay(50); + + REG_WRITE(ah, (u16) (AR_RTC_RC), 0); + if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s: RTC stuck in MAC reset\n", + __func__); + return false; + } + + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + + ath9k_hw_init_pll(ah, NULL); + + if (AR_SREV_9100(ah)) + udelay(50); + + return true; +} + +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); + + REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); + REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); + + if (!ath9k_hw_wait(ah, + AR_RTC_STATUS, + AR_RTC_STATUS_M, + AR_RTC_STATUS_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n", __func__); - break; + return false; } - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL); + ath9k_hw_read_revisions(ah); + + return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); +} + +static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type) +{ + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + + switch (type) { + case ATH9K_RESET_POWER_ON: + return ath9k_hw_set_reset_power_on(ah); + break; + case ATH9K_RESET_WARM: + case ATH9K_RESET_COLD: + return ath9k_hw_set_reset(ah, type); + break; + default: + return false; + } } -static void ath9k_hw_reset_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { + u32 phymode; struct ath_hal_5416 *ahp = AH5416(ah); - int i; - ath9k_hw_setup_calibration(ah, currCal); + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; + + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN; - currCal->calState = CAL_RUNNING; + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_Meas0.sign[i] = 0; - ahp->ah_Meas1.sign[i] = 0; - ahp->ah_Meas2.sign[i] = 0; - ahp->ah_Meas3.sign[i] = 0; + if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) + phymode |= AR_PHY_FC_DYN2040_EXT_CH; } + REG_WRITE(ah, AR_PHY_TURBO, phymode); + + ath9k_hw_set11nmac2040(ah, macmode); - ahp->ah_CalSamples = 0; + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); } -static void -ath9k_hw_per_calibration(struct ath_hal *ah, - struct ath9k_channel *ichan, - u8 rxchainmask, - struct hal_cal_list *currCal, - bool *isCalDone) +static bool ath9k_hw_chip_reset(struct ath_hal *ah, + struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); - *isCalDone = false; - - if (currCal->calState == CAL_RUNNING) { - if (!(REG_READ(ah, - AR_PHY_TIMING_CTRL4(0)) & - AR_PHY_TIMING_CTRL4_DO_CAL)) { + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) + return false; - currCal->calData->calCollect(ah); + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; - ahp->ah_CalSamples++; + ahp->ah_chipFullSleep = false; - if (ahp->ah_CalSamples >= - currCal->calData->calNumSamples) { - int i, numChains = 0; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } + ath9k_hw_init_pll(ah, chan); - currCal->calData->calPostProc(ah, - numChains); + ath9k_hw_set_rfmode(ah, chan); - ichan->CalValid |= - currCal->calData->calType; - currCal->calState = CAL_DONE; - *isCalDone = true; - } else { - ath9k_hw_setup_calibration(ah, currCal); - } - } - } else if (!(ichan->CalValid & currCal->calData->calType)) { - ath9k_hw_reset_calibration(ah, currCal); - } + return true; } -static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, - int init_cal_count) +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel ichan; - bool isCalDone; - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - const struct hal_percal_data *calData = currCal->calData; - int i; - - if (currCal == NULL) - return false; - - ichan.CalValid = 0; - - for (i = 0; i < init_cal_count; i++) { - ath9k_hw_reset_calibration(ah, currCal); - - if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Cal %d failed to complete in 100ms.\n", - __func__, calData->calType); - - ahp->ah_cal_list = ahp->ah_cal_list_last = - ahp->ah_cal_list_curr = NULL; - return false; - } + if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "%s: invalid channel %u/0x%x; not marked as " + "2GHz or 5GHz\n", __func__, chan->channel, + chan->channelFlags); + return NULL; + } - ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask, - currCal, &isCalDone); - if (!isCalDone) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Not able to run Init Cal %d.\n", - __func__, calData->calType); - } - if (currCal->calNext) { - currCal = currCal->calNext; - calData = currCal->calData; - } + if (!IS_CHAN_OFDM(chan) && + !IS_CHAN_CCK(chan) && + !IS_CHAN_HT20(chan) && + !IS_CHAN_HT40(chan)) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "%s: invalid channel %u/0x%x; not marked as " + "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", + __func__, chan->channel, chan->channelFlags); + return NULL; } - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; - return true; + return ath9k_regd_check_channel(ah, chan); } -static bool -ath9k_hw_channel_change(struct ath_hal *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static bool ath9k_hw_channel_change(struct ath_hal *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { u32 synthDelay, qnum; - struct ath_hal_5416 *ahp = AH5416(ah); for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Transmit frames pending on queue %d\n", - __func__, qnum); + "%s: Transmit frames pending on queue %d\n", + __func__, qnum); return false; } } @@ -5640,7 +1616,7 @@ ath9k_hw_channel_change(struct ath_hal *ah, if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: Could not kill baseband RX\n", __func__); + "%s: Could not kill baseband RX\n", __func__); return false; } @@ -5649,25 +1625,25 @@ ath9k_hw_channel_change(struct ath_hal *ah, if (AR_SREV_9280_10_OR_LATER(ah)) { if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "%s: failed to set channel\n", __func__); return false; } } else { if (!(ath9k_hw_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "%s: failed to set channel\n", __func__); return false; } } - if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, + if (ath9k_hw_set_txpower(ah, chan, ath9k_regd_get_ctl(ah, chan), ath9k_regd_get_antenna_allowed(ah, chan), chan->maxRegTxPower * 2, min((u32) MAX_RATE_POWER, (u32) ah->ah_powerLimit)) != 0) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error init'ing transmit power\n", __func__); + "%s: error init'ing transmit power\n", __func__); return false; } @@ -5681,190 +1657,476 @@ ath9k_hw_channel_change(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); - if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) - ath9k_hw_set_delta_slope(ah, chan); + if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) + ath9k_hw_set_delta_slope(ah, chan); + + if (AR_SREV_9280_10_OR_LATER(ah)) + ath9k_hw_9280_spur_mitigate(ah, chan); + else + ath9k_hw_spur_mitigate(ah, chan); + + if (!chan->oneTimeCalsDone) + chan->oneTimeCalsDone = true; + + return true; +} + +static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + struct chan_centers centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + + if (is2GHz) + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + else + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(chan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + return; + } else { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + if (IS_CHAN_HT40(chan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + if (IS_CHAN_HT40(chan)) + spur_delta_phase = + ((bb_spur * 262144) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = + ((bb_spur * 524288) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp = abs(cur_vit_mask - bin); + + if (tmp < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - if (AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_9280_spur_mitigate(ah, chan); - else - ath9k_hw_spur_mitigate(ah, chan); + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - if (!chan->oneTimeCalsDone) - chan->oneTimeCalsDone = true; + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - return true; + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static bool ath9k_hw_chip_reset(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) - return false; + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); - ahp->ah_chipFullSleep = false; + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); - ath9k_hw_init_pll(ah, chan); + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } - ath9k_hw_set_rfmode(ah, chan); + if (AR_NO_SPUR == bb_spur) + return; - return true; -} + bin = bb_spur * 32; -static inline void ath9k_hw_set_dma(struct ath_hal *ah) -{ - u32 regval; + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); - REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); - if (AR_SREV_9285(ah)) { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_PCU_TXBUF_CTRL_USABLE_SIZE); - } -} + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; -bool ath9k_hw_stopdmarecv(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXD); - if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: dma failed to stop in 10ms\n" - "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", - __func__, - REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); - return false; - } else { - return true; + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); } -} - -void ath9k_hw_startpcureceive(struct ath_hal *ah) -{ - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - - ath9k_enable_mib_counters(ah); - ath9k_ani_reset(ah); -} - -void ath9k_hw_stoppcurecv(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; - ath9k_hw_disable_mib_counters(ah); -} + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { -static bool ath9k_hw_iscal_supported(struct ath_hal *ah, - struct ath9k_channel *chan, - enum hal_cal_types calType) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - bool retval = false; + /* workaround for gcc bug #37014 */ + volatile int tmp = abs(cur_vit_mask - bin); - switch (calType & ahp->ah_suppCals) { - case IQ_MISMATCH_CAL: - if (!IS_CHAN_B(chan)) - retval = true; - break; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - if (!IS_CHAN_B(chan) - && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) - retval = true; - break; + if (tmp < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; } - return retval; -} - -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 = - ath9k_regd_check_channel(ah, chan); - - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait - (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: offset calibration failed to complete in 1ms; " - "noisy environment?\n", __func__); - return false; - } + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = - NULL; + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { - INIT_CAL(&ahp->ah_adcGainCalData); - INSERT_CAL(ahp, &ahp->ah_adcGainCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC Gain Calibration.\n", - __func__); - } - if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { - INIT_CAL(&ahp->ah_adcDcCalData); - INSERT_CAL(ahp, &ahp->ah_adcDcCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC DC Calibration.\n", - __func__); - } - if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { - INIT_CAL(&ahp->ah_iqCalData); - INSERT_CAL(ahp, &ahp->ah_iqCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling IQ Calibration.\n", - __func__); - } + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - ahp->ah_cal_list_curr = ahp->ah_cal_list; + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - if (ahp->ah_cal_list_curr) - ath9k_hw_reset_calibration(ah, - ahp->ah_cal_list_curr); - } + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - ichan->CalValid = 0; + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - return true; + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } - -bool ath9k_hw_reset(struct ath_hal *ah, - struct ath9k_channel *chan, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, - int *status) + bool bChannelChange, int *status) { u32 saveLedState; struct ath_hal_5416 *ahp = AH5416(ah); @@ -5885,8 +2147,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (ath9k_hw_check_chan(ah, chan) == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + "%s: invalid channel %u/0x%x; no mapping\n", + __func__, chan->channel, chan->channelFlags); ecode = -EINVAL; goto bad; } @@ -5964,7 +2226,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (!ath9k_hw_eeprom_set_board_values(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error setting board options\n", __func__); + "%s: error setting board options\n", __func__); ecode = -EIO; goto bad; } @@ -6054,15 +2316,15 @@ bool ath9k_hw_reset(struct ath_hal *ah, mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s CFG Byte Swap Set 0x%x\n", __func__, - mask); + "%s CFG Byte Swap Set 0x%x\n", __func__, + mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s Setting CFG 0x%x\n", __func__, - REG_READ(ah, AR_CFG)); + "%s Setting CFG 0x%x\n", __func__, + REG_READ(ah, AR_CFG)); } } else { #ifdef __BIG_ENDIAN @@ -6077,693 +2339,404 @@ bad: return false; } -bool ath9k_hw_phy_disable(struct ath_hal *ah) -{ - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); -} - -bool ath9k_hw_disable(struct ath_hal *ah) -{ - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; - - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); -} +/************************/ +/* Key Cache Management */ +/************************/ -bool -ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) +bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - - *isCalDone = true; + u32 keyType; - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: entry %u out of range\n", __func__, entry); return false; } - if (currCal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { - ahp->ah_cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - *isCalDone = false; - ath9k_hw_reset_calibration(ah, currCal); - } - } - } - - if (longcal) { - ath9k_hw_getnf(ah, ichan); - ath9k_hw_loadnf(ah, ah->ah_curchan); - ath9k_hw_start_nfcal(ah); - - if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { - - chan->channelFlags |= CHANNEL_CW_INT; - ichan->channelFlags &= ~CHANNEL_CW_INT; - } - } - - return true; -} - -static void ath9k_hw_iqcal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], - ahp->ah_totalPowerMeasQ[i], - ahp->ah_totalIqCorrMeas[i]); - } -} - -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcIOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcIEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcQOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcQEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcIOddPhase[i], - ahp->ah_totalAdcIEvenPhase[i], - ahp->ah_totalAdcQOddPhase[i], - ahp->ah_totalAdcQEvenPhase[i]); - } -} - -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcDcOffsetIOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcDcOffsetIEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcDcOffsetQOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcDcOffsetQEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcDcOffsetIOddPhase[i], - ahp->ah_totalAdcDcOffsetIEvenPhase[i], - ahp->ah_totalAdcDcOffsetQOddPhase[i], - ahp->ah_totalAdcDcOffsetQEvenPhase[i]); - } -} - -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 powerMeasQ, powerMeasI, iqCorrMeas; - u32 qCoffDenom, iCoffDenom; - int32_t qCoff, iCoff; - int iqCorrNeg, i; - - for (i = 0; i < numChains; i++) { - powerMeasI = ahp->ah_totalPowerMeasI[i]; - powerMeasQ = ahp->ah_totalPowerMeasQ[i]; - iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", - i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ahp->ah_totalIqCorrMeas[i]); - - iqCorrNeg = 0; - - - if (iqCorrMeas > 0x80000000) { - iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; - iqCorrNeg = 1; - } - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", - iqCorrNeg); - - iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; - qCoffDenom = powerMeasQ / 64; - - if (powerMeasQ != 0) { - - iCoff = iqCorrMeas / iCoffDenom; - qCoff = powerMeasI / qCoffDenom - 64; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d iCoff = 0x%08x\n", i, iCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d qCoff = 0x%08x\n", i, qCoff); - - - iCoff = iCoff & 0x3f; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "New: Chn %d iCoff = 0x%08x\n", i, iCoff); - if (iqCorrNeg == 0x0) - iCoff = 0x40 - iCoff; - - if (qCoff > 15) - qCoff = 15; - else if (qCoff <= -16) - qCoff = 16; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", - i, iCoff, qCoff); - - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, - iCoff); - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, - qCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "IQ Cal and Correction done for Chain %d\n", - i); - } - } + keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); -} + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); -static void -ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, - qEvenMeasOffset; - u32 qGainMismatch, iGainMismatch, val, i; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC Gain Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = 0x%08x\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = 0x%08x\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = 0x%08x\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = 0x%08x\n", i, - qEvenMeasOffset); - - if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { - iGainMismatch = - ((iEvenMeasOffset * 32) / - iOddMeasOffset) & 0x3f; - qGainMismatch = - ((qOddMeasOffset * 32) / - qEvenMeasOffset) & 0x3f; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", i, - iGainMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", i, - qGainMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xfffff000; - val |= (qGainMismatch) | (iGainMismatch << 6); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC Gain Cal done for Chain %d\n", i); - } - } + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); -} + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); -static void -ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 iOddMeasOffset, iEvenMeasOffset, val, i; - int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct hal_percal_data *calData = - ahp->ah_cal_list_curr->calData; - u32 numSamples = - (1 << (calData->calCountMax + 5)) * calData->calNumSamples; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC DC Offset Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = %d\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = %d\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = %d\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = %d\n", i, - qEvenMeasOffset); - - iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / - numSamples) & 0x1ff; - qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / - numSamples) & 0x1ff; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, - iDcMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, - qDcMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xc0000fff; - val |= (qDcMismatch << 12) | (iDcMismatch << 21); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC DC Offset Cal done for Chain %d\n", i); } - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); -} - -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - - ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); - - if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, - ath9k_regd_get_ctl(ah, chan), - ath9k_regd_get_antenna_allowed(ah, - chan), - chan->maxRegTxPower * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->ah_powerLimit)) != 0) - return false; + if (ah->ah_curchan == NULL) + return true; return true; } -void -ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers) +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) { - int8_t extoff; - struct ath_hal_5416 *ahp = AH5416(ah); + u32 macHi, macLo; - if (!IS_CHAN_HT40(chan)) { - centers->ctl_center = centers->ext_center = - centers->synth_center = chan->channel; - return; + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: entry %u out of range\n", __func__, entry); + return false; } - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) { - centers->synth_center = - chan->channel + HT40_CHANNEL_CENTER_SHIFT; - extoff = 1; + if (mac != NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24) | + (mac[2] << 16) | + (mac[1] << 8) | + mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; + macHi >>= 1; } else { - centers->synth_center = - chan->channel - HT40_CHANNEL_CENTER_SHIFT; - extoff = -1; + macLo = macHi = 0; } + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - centers->ctl_center = centers->synth_center - (extoff * - HT40_CHANNEL_CENTER_SHIFT); - centers->ext_center = centers->synth_center + (extoff * - ((ahp-> - ah_extprotspacing - == - ATH9K_HT_EXTPROTSPACING_20) - ? - HT40_CHANNEL_CENTER_SHIFT - : 15)); - + return true; } -void -ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone) +bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac, int xorKey) { + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u32 key0, key1, key2, key3, key4; + u32 keyType; + u32 xorMask = xorKey ? + (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 + | ATH9K_KEY_XOR) : 0; struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - - *isCalDone = true; - - if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) - return; - if (currCal == NULL) - return; - - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); - return; + if (entry >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: entry %u out of range\n", __func__, entry); + return false; } - - if (currCal->calState != CAL_DONE) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Calibration state incorrect, %d\n", - __func__, currCal->calState); - return; + switch (k->kv_type) { + case ATH9K_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case ATH9K_CIPHER_AES_CCM: + if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: AES-CCM not supported by " + "mac rev 0x%x\n", __func__, + ah->ah_macRev); + return false; + } + keyType = AR_KEYTABLE_TYPE_CCM; + break; + case ATH9K_CIPHER_TKIP: + keyType = AR_KEYTABLE_TYPE_TKIP; + if (ATH9K_IS_MIC_ENABLED(ah) + && entry + 64 >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: entry %u inappropriate for TKIP\n", + __func__, entry); + return false; + } + break; + case ATH9K_CIPHER_WEP: + if (k->kv_len < LEN_WEP40) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: WEP key length %u too small\n", + __func__, k->kv_len); + return false; + } + if (k->kv_len <= LEN_WEP40) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= LEN_WEP104) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case ATH9K_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "%s: cipher %u not supported\n", __func__, + k->kv_type); + return false; } + key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; + key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; + key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; + key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; + key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; + if (k->kv_len <= LEN_WEP104) + key4 &= 0xff; - if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) - return; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Resetting Cal %d state for channel %u/0x%x\n", - __func__, currCal->calData->calType, chan->channel, - chan->channelFlags); - - ichan->CalValid &= ~currCal->calData->calType; - currCal->calState = CAL_WAITING; - - *isCalDone = false; -} - -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(mac, ahp->ah_macaddr, ETH_ALEN); -} + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + (void) ath9k_hw_keysetmac(ah, entry, mac); - memcpy(ahp->ah_macaddr, mac, ETH_ALEN); - return true; -} + if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { + u32 mic0, mic1, mic2, mic3, mic4; -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; + mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; + mic4 = get_unaligned_le32(k->kv_txmic + 4); + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); - memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); -} + } else { + u32 mic0, mic2; -bool -ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + } + REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + } else { + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); + (void) ath9k_hw_keysetmac(ah, entry, mac); + } - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); + if (ah->ah_curchan == NULL) + return true; return true; } -void -ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId) +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) { - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(ahp->ah_bssid, bssid, ETH_ALEN); - ahp->ah_assocId = assocId; - - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | - ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); + if (entry < ah->ah_caps.keycache_size) { + u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return true; + } + return false; } -u64 ath9k_hw_gettsf64(struct ath_hal *ah) +/******************************/ +/* Power Management (Chipset) */ +/******************************/ + +static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) { - u64 tsf; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - tsf = REG_READ(ah, AR_TSF_U32); - tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - return tsf; + REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), + AR_RTC_RESET_EN); + } } -void ath9k_hw_reset_tsf(struct ath_hal *ah) +static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) { - int count; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - count = 0; - while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { - count++; - if (count > 10) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n", - __func__); - break; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_ON_INT); + } else { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); } - udelay(10); } - REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); -} - -u32 ath9k_hw_getdefantenna(struct ath_hal *ah) -{ - return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) +static bool ath9k_hw_set_power_awake(struct ath_hal *ah, + int setChip) { - REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); -} + u32 val; + int i; -bool -ath9k_hw_setantennaswitch(struct ath_hal *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, - u8 *rx_chainmask, - u8 *antenna_cfgd) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - static u8 tx_chainmask_cfg, rx_chainmask_cfg; + if (setChip) { + if ((REG_READ(ah, AR_RTC_STATUS) & + AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if (ath9k_hw_set_reset_reg(ah, + ATH9K_RESET_POWER_ON) != true) { + return false; + } + } + if (AR_SREV_9100(ah)) + REG_SET_BIT(ah, AR_RTC_RESET, + AR_RTC_RESET_EN); - if (AR_SREV_9280(ah)) { - if (!tx_chainmask_cfg) { + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + udelay(50); - tx_chainmask_cfg = *tx_chainmask; - rx_chainmask_cfg = *rx_chainmask; + for (i = POWER_UP_TIME / 50; i > 0; i--) { + val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + if (val == AR_RTC_STATUS_ON) + break; + udelay(50); + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); } - - switch (settings) { - case ATH9K_ANT_FIXED_A: - *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_FIXED_B: - if (ah->ah_caps.tx_chainmask > - ATH9K_ANTENNA1_CHAINMASK) { - *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - } - *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_VARIABLE: - *tx_chainmask = tx_chainmask_cfg; - *rx_chainmask = rx_chainmask_cfg; - *antenna_cfgd = true; - break; - default: - break; + if (i == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "%s: Failed to wakeup in %uus\n", + __func__, POWER_UP_TIME / 20); + return false; } - } else { - ahp->ah_diversityControl = settings; } - return true; -} + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); -void ath9k_hw_setopmode(struct ath_hal *ah) -{ - ath9k_hw_set_operating_mode(ah, ah->ah_opmode); + return true; } -bool -ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, - u32 capability, u32 *result) +bool ath9k_hw_setpower(struct ath_hal *ah, + enum ath9k_power_mode mode) { struct ath_hal_5416 *ahp = AH5416(ah); - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - switch (type) { - case ATH9K_CAP_CIPHER: - switch (capability) { - case ATH9K_CIPHER_AES_CCM: - case ATH9K_CIPHER_AES_OCB: - case ATH9K_CIPHER_TKIP: - case ATH9K_CIPHER_WEP: - case ATH9K_CIPHER_MIC: - case ATH9K_CIPHER_CLR: - return true; - default: - return false; - } - case ATH9K_CAP_TKIP_MIC: - switch (capability) { - case 0: - return true; - case 1: - return (ahp->ah_staId1Defaults & - AR_STA_ID1_CRPT_MIC_ENABLE) ? true : - false; - } - case ATH9K_CAP_TKIP_SPLIT: - return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? - false : true; - case ATH9K_CAP_WME_TKIPMIC: - return 0; - case ATH9K_CAP_PHYCOUNTERS: - return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; - case ATH9K_CAP_DIVERSITY: - return (REG_READ(ah, AR_PHY_CCK_DETECT) & - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? - true : false; - case ATH9K_CAP_PHYDIAG: - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - switch (capability) { - case 0: - return true; - case 1: - if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { - return false; - } else { - return (ahp->ah_staId1Defaults & - AR_STA_ID1_MCAST_KSRCH) ? true : - false; - } - } - return false; - case ATH9K_CAP_TSF_ADJUST: - return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? - true : false; - case ATH9K_CAP_RFSILENT: - if (capability == 3) - return false; - case ATH9K_CAP_ANT_CFG_2GHZ: - *result = pCap->num_antcfg_2ghz; - return true; - case ATH9K_CAP_ANT_CFG_5GHZ: - *result = pCap->num_antcfg_5ghz; - return true; - case ATH9K_CAP_TXPOW: - switch (capability) { - case 0: - return 0; - case 1: - *result = ah->ah_powerLimit; - return 0; - case 2: - *result = ah->ah_maxPowerLevel; - return 0; - case 3: - *result = ah->ah_tpScale; - return 0; - } - return false; + static const char *modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; + int status = true, setChip = true; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + + switch (mode) { + case ATH9K_PM_AWAKE: + status = ath9k_hw_set_power_awake(ah, setChip); + break; + case ATH9K_PM_FULL_SLEEP: + ath9k_set_power_sleep(ah, setChip); + ahp->ah_chipFullSleep = true; + break; + case ATH9K_PM_NETWORK_SLEEP: + ath9k_set_power_network_sleep(ah, setChip); + break; default: + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "%s: unknown power mode %u\n", __func__, mode); return false; } + ahp->ah_powerMode = mode; + + return status; } -int -ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) +void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 ant_config; - u32 halNumAntConfig; + u8 i; - halNumAntConfig = - IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap-> - num_antcfg_5ghz; + if (ah->ah_isPciExpress != true) + return; - if (cfg < halNumAntConfig) { - if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, - cfg, &ant_config)) { - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); - return 0; + if (ah->ah_config.pcie_powersave_enable == 2) + return; + + if (restore) + return; + + if (AR_SREV_9280_20_OR_LATER(ah)) { + for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { + REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), + INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); } + udelay(1000); + } else if (AR_SREV_9280(ah) && + (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); + REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); + + if (ah->ah_config.pcie_clock_req) + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); + else + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + udelay(1000); + } else { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); + REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } - return -EINVAL; + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + + if (ah->ah_config.pcie_waen) { + REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); + } else { + if (AR_SREV_9280(ah)) + REG_WRITE(ah, AR_WA, 0x0040073f); + else + REG_WRITE(ah, AR_WA, 0x0000073f); + } } +/**********************/ +/* Interrupt Handling */ +/**********************/ + bool ath9k_hw_intrpend(struct ath_hal *ah) { u32 host_isr; @@ -6790,6 +2763,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) struct ath9k_hw_capabilities *pCap = &ah->ah_caps; u32 sync_cause = 0; bool fatal_int = false; + struct ath_hal_5416 *ahp = AH5416(ah); if (!AR_SREV_9100(ah)) { if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { @@ -6799,9 +2773,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) } } - sync_cause = - REG_READ(ah, - AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & + AR_INTR_SYNC_DEFAULT; *masked = 0; @@ -6813,8 +2786,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) } if (isr) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (isr & AR_ISR_BCNMISC) { u32 isr2; isr2 = REG_READ(ah, AR_ISR_S2); @@ -6841,7 +2812,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; if (ahp->ah_intrMitigation) { - if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -6866,8 +2836,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (isr & AR_ISR_RXORN) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: receive FIFO overrun interrupt\n", - __func__); + "%s: receive FIFO overrun interrupt\n", + __func__); } if (!AR_SREV_9100(ah)) { @@ -6880,8 +2850,10 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked |= mask2; } + if (AR_SREV_9100(ah)) return true; + if (sync_cause) { fatal_int = (sync_cause & @@ -6891,32 +2863,33 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI FATAL interrupt\n", - __func__); + "%s: received PCI FATAL interrupt\n", + __func__); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI PERR interrupt\n", - __func__); + "%s: received PCI PERR interrupt\n", + __func__); } } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", - __func__); + "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", + __func__); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", - __func__); + "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", + __func__); } REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); } + return true; } @@ -7034,9 +3007,11 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) return omask; } -void -ath9k_hw_beaconinit(struct ath_hal *ah, - u32 next_beacon, u32 beacon_period) +/*******************/ +/* Beacon Handling */ +/*******************/ + +void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) { struct ath_hal_5416 *ahp = AH5416(ah); int flags = 0; @@ -7088,9 +3063,8 @@ ath9k_hw_beaconinit(struct ath_hal *ah, REG_SET_BIT(ah, AR_TIMER_MODE, flags); } -void -ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs) +void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, + const struct ath9k_beacon_state *bs) { u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; struct ath9k_hw_capabilities *pCap = &ah->ah_caps; @@ -7124,1450 +3098,898 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__, nextTbtt); DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__, - beaconintval); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__, - dtimperiod); - - REG_WRITE(ah, AR_NEXT_DTIM, - TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); - REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); - - REG_WRITE(ah, AR_SLEEP1, - SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) - | AR_SLEEP1_ASSUME_DTIM); - - if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) - beacontimeout = (BEACON_TIMEOUT_VAL << 3); - else - beacontimeout = MIN_BEACON_TIMEOUT_VAL; - - REG_WRITE(ah, AR_SLEEP2, - SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - - REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); - REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); - - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | - AR_DTIM_TIMER_EN); - -} - -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) -{ - if (entry < ah->ah_caps.keycache_size) { - u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); - if (val & AR_KEYTABLE_VALID) - return true; - } - return false; -} - -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) -{ - u32 keyType; - - if (entry >= ah->ah_caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - - } - - return true; -} - -bool -ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, - const u8 *mac) -{ - u32 macHi, macLo; - - if (entry >= ah->ah_caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - - if (mac != NULL) { - macHi = (mac[5] << 8) | mac[4]; - macLo = (mac[3] << 24) | (mac[2] << 16) - | (mac[1] << 8) | mac[0]; - macLo >>= 1; - macLo |= (macHi & 1) << 31; - macHi >>= 1; - } else { - macLo = macHi = 0; - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - - return true; -} - -bool -ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, int xorKey) -{ - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u32 key0, key1, key2, key3, key4; - u32 keyType; - u32 xorMask = xorKey ? - (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 - | ATH9K_KEY_XOR) : 0; - struct ath_hal_5416 *ahp = AH5416(ah); - - if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - switch (k->kv_type) { - case ATH9K_CIPHER_AES_OCB: - keyType = AR_KEYTABLE_TYPE_AES; - break; - case ATH9K_CIPHER_AES_CCM: - if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: AES-CCM not supported by " - "mac rev 0x%x\n", __func__, - ah->ah_macRev); - return false; - } - keyType = AR_KEYTABLE_TYPE_CCM; - break; - case ATH9K_CIPHER_TKIP: - keyType = AR_KEYTABLE_TYPE_TKIP; - if (ATH9K_IS_MIC_ENABLED(ah) - && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u inappropriate for TKIP\n", - __func__, entry); - return false; - } - break; - case ATH9K_CIPHER_WEP: - if (k->kv_len < LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: WEP key length %u too small\n", - __func__, k->kv_len); - return false; - } - if (k->kv_len <= LEN_WEP40) - keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= LEN_WEP104) - keyType = AR_KEYTABLE_TYPE_104; - else - keyType = AR_KEYTABLE_TYPE_128; - break; - case ATH9K_CIPHER_CLR: - keyType = AR_KEYTABLE_TYPE_CLR; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: cipher %u not supported\n", __func__, - k->kv_type); - return false; - } - - key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; - key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; - key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; - key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; - key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; - if (k->kv_len <= LEN_WEP104) - key4 &= 0xff; - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - (void) ath9k_hw_keysetmac(ah, entry, mac); + beaconintval); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__, + dtimperiod); - if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { - u32 mic0, mic1, mic2, mic3, mic4; + REG_WRITE(ah, AR_NEXT_DTIM, + TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); + REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; - mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; - mic4 = get_unaligned_le32(k->kv_txmic + 4); - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); + REG_WRITE(ah, AR_SLEEP1, + SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) + | AR_SLEEP1_ASSUME_DTIM); - } else { - u32 mic0, mic2; + if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) + beacontimeout = (BEACON_TIMEOUT_VAL << 3); + else + beacontimeout = MIN_BEACON_TIMEOUT_VAL; - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - } else { - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + REG_WRITE(ah, AR_SLEEP2, + SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - (void) ath9k_hw_keysetmac(ah, entry, mac); - } + REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); + REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); - if (ah->ah_curchan == NULL) - return true; + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | + AR_DTIM_TIMER_EN); - return true; } -bool -ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 txcfg, curLevel, newLevel; - enum ath9k_int omask; +/***************/ +/* Rate tables */ +/***************/ - if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) - return false; +static struct ath9k_rate_table ar5416_11a_table = { + 8, + {0}, + { + {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, + {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, + {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, + {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, + {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, + {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, + {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, + {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4} + }, +}; - omask = ath9k_hw_set_interrupts(ah, - ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); +static struct ath9k_rate_table ar5416_11b_table = { + 4, + {0}, + { + {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, + {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, + {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1}, + {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1} + }, +}; - txcfg = REG_READ(ah, AR_TXCFG); - curLevel = MS(txcfg, AR_FTRIG); - newLevel = curLevel; - if (bIncTrigLevel) { - if (curLevel < MAX_TX_FIFO_THRESHOLD) - newLevel++; - } else if (curLevel > MIN_TX_FIFO_THRESHOLD) - newLevel--; - if (newLevel != curLevel) - REG_WRITE(ah, AR_TXCFG, - (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); +static struct ath9k_rate_table ar5416_11g_table = { + 12, + {0}, + { + {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, + {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, + {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, + {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - ath9k_hw_set_interrupts(ah, omask); + {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, + {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, + {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, + {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, + {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, + {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, + {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, + {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8} + }, +}; - ah->ah_txTrigLevel = newLevel; +static struct ath9k_rate_table ar5416_11ng_table = { + 28, + {0}, + { + {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, + {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, + {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, + {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - return newLevel != curLevel; -} + {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, + {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, + {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, + {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, + {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, + {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, + {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, + {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}, + {true, PHY_HT, 6500, 0x80, 0x00, 0, 4}, + {true, PHY_HT, 13000, 0x81, 0x00, 1, 6}, + {true, PHY_HT, 19500, 0x82, 0x00, 2, 6}, + {true, PHY_HT, 26000, 0x83, 0x00, 3, 8}, + {true, PHY_HT, 39000, 0x84, 0x00, 4, 8}, + {true, PHY_HT, 52000, 0x85, 0x00, 5, 8}, + {true, PHY_HT, 58500, 0x86, 0x00, 6, 8}, + {true, PHY_HT, 65000, 0x87, 0x00, 7, 8}, + {true, PHY_HT, 13000, 0x88, 0x00, 8, 4}, + {true, PHY_HT, 26000, 0x89, 0x00, 9, 6}, + {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6}, + {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8}, + {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8}, + {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8}, + {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8}, + {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8}, + }, +}; + +static struct ath9k_rate_table ar5416_11na_table = { + 24, + {0}, + { + {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, + {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, + {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, + {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, + {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, + {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, + {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, + {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}, + {true, PHY_HT, 6500, 0x80, 0x00, 0, 0}, + {true, PHY_HT, 13000, 0x81, 0x00, 1, 2}, + {true, PHY_HT, 19500, 0x82, 0x00, 2, 2}, + {true, PHY_HT, 26000, 0x83, 0x00, 3, 4}, + {true, PHY_HT, 39000, 0x84, 0x00, 4, 4}, + {true, PHY_HT, 52000, 0x85, 0x00, 5, 4}, + {true, PHY_HT, 58500, 0x86, 0x00, 6, 4}, + {true, PHY_HT, 65000, 0x87, 0x00, 7, 4}, + {true, PHY_HT, 13000, 0x88, 0x00, 8, 0}, + {true, PHY_HT, 26000, 0x89, 0x00, 9, 2}, + {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2}, + {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4}, + {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4}, + {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4}, + {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4}, + {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4}, + }, +}; -bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, - const struct ath9k_tx_queue_info *qinfo) +static void ath9k_hw_setup_rate_table(struct ath_hal *ah, + struct ath9k_rate_table *rt) { - u32 cw; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + int i; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } + if (rt->rateCodeToIndex[0] != 0) + return; - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); - return false; + for (i = 0; i < 256; i++) + rt->rateCodeToIndex[i] = (u8) -1; + + for (i = 0; i < rt->rateCount; i++) { + u8 code = rt->info[i].rateCode; + u8 cix = rt->info[i].controlRate; + + rt->rateCodeToIndex[code] = i; + rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; + + rt->info[i].lpAckDuration = + ath9k_hw_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, + cix, + false); + rt->info[i].spAckDuration = + ath9k_hw_computetxtime(ah, rt, + WLAN_CTRL_FRAME_SIZE, + cix, + true); } +} - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi); +const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, + u32 mode) +{ + struct ath9k_rate_table *rt; - qi->tqi_ver = qinfo->tqi_ver; - qi->tqi_subtype = qinfo->tqi_subtype; - qi->tqi_qflags = qinfo->tqi_qflags; - qi->tqi_priority = qinfo->tqi_priority; - if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) - qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); - else - qi->tqi_aifs = INIT_AIFS; - if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmin, 1024U); - qi->tqi_cwmin = 1; - while (qi->tqi_cwmin < cw) - qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; - } else - qi->tqi_cwmin = qinfo->tqi_cwmin; - if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmax, 1024U); - qi->tqi_cwmax = 1; - while (qi->tqi_cwmax < cw) - qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; - } else - qi->tqi_cwmax = INIT_CWMAX; - - if (qinfo->tqi_shretry != 0) - qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); - else - qi->tqi_shretry = INIT_SH_RETRY; - if (qinfo->tqi_lgretry != 0) - qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); - else - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; - qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; - qi->tqi_burstTime = qinfo->tqi_burstTime; - qi->tqi_readyTime = qinfo->tqi_readyTime; - - switch (qinfo->tqi_subtype) { - case ATH9K_WME_UPSD: - if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) - qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; + switch (mode) { + case ATH9K_MODE_11A: + rt = &ar5416_11a_table; break; - default: + case ATH9K_MODE_11B: + rt = &ar5416_11b_table; + break; + case ATH9K_MODE_11G: + rt = &ar5416_11g_table; + break; + case ATH9K_MODE_11NG_HT20: + case ATH9K_MODE_11NG_HT40PLUS: + case ATH9K_MODE_11NG_HT40MINUS: + rt = &ar5416_11ng_table; + break; + case ATH9K_MODE_11NA_HT20: + case ATH9K_MODE_11NA_HT40PLUS: + case ATH9K_MODE_11NA_HT40MINUS: + rt = &ar5416_11na_table; break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n", + __func__, mode); + return NULL; } - return true; + + ath9k_hw_setup_rate_table(ah, rt); + + return rt; } -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo) +/*******************/ +/* HW Capabilities */ +/*******************/ + +bool ath9k_hw_fill_cap_info(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + u16 capField = 0, eeval; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0); - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); - return false; - } + ah->ah_currentRD = eeval; - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_ver = qi->tqi_ver; - qinfo->tqi_subtype = qi->tqi_subtype; - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_priority = qi->tqi_priority; - qinfo->tqi_aifs = qi->tqi_aifs; - qinfo->tqi_cwmin = qi->tqi_cwmin; - qinfo->tqi_cwmax = qi->tqi_cwmax; - qinfo->tqi_shretry = qi->tqi_shretry; - qinfo->tqi_lgretry = qi->tqi_lgretry; - qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; - qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; - qinfo->tqi_burstTime = qi->tqi_burstTime; - qinfo->tqi_readyTime = qi->tqi_readyTime; + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1); + ah->ah_currentRDExt = eeval; - return true; -} + capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP); + + if (ah->ah_opmode != ATH9K_M_HOSTAP && + ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) + ah->ah_currentRD += 5; + else if (ah->ah_currentRD == 0x41) + ah->ah_currentRD = 0x43; + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + "%s: regdomain mapped to 0x%x\n", __func__, + ah->ah_currentRD); + } -int -ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - int q; + eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE); + bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - switch (type) { - case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; - break; - case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; - break; - case ATH9K_TX_QUEUE_PSPOLL: - q = 1; - break; - case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; - break; - case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) - if (ahp->ah_txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: no available tx queue\n", __func__); - return -1; + if (eeval & AR5416_OPFLAGS_11A) { + set_bit(ATH9K_MODE_11A, pCap->wireless_modes); + if (ah->ah_config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) + set_bit(ATH9K_MODE_11NA_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { + set_bit(ATH9K_MODE_11NA_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NA_HT40MINUS, + pCap->wireless_modes); + } } - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n", - __func__, type); - return -1; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); - - qi = &ahp->ah_txq[q]; - if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: tx queue %u already active\n", __func__, q); - return -1; + if (eeval & AR5416_OPFLAGS_11G) { + set_bit(ATH9K_MODE_11B, pCap->wireless_modes); + set_bit(ATH9K_MODE_11G, pCap->wireless_modes); + if (ah->ah_config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) + set_bit(ATH9K_MODE_11NG_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { + set_bit(ATH9K_MODE_11NG_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NG_HT40MINUS, + pCap->wireless_modes); + } + } } - memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); - qi->tqi_type = type; - if (qinfo == NULL) { - qi->tqi_qflags = - TXQ_FLAG_TXOKINT_ENABLE - | TXQ_FLAG_TXERRINT_ENABLE - | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; - qi->tqi_aifs = INIT_AIFS; - qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi->tqi_cwmax = INIT_CWMAX; - qi->tqi_shretry = INIT_SH_RETRY; - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_physCompBuf = 0; + + pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK); + if ((ah->ah_isPciExpress) + || (eeval & AR5416_OPFLAGS_11A)) { + pCap->rx_chainmask = + ath9k_hw_get_eeprom(ah, EEP_RX_MASK); } else { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); + pCap->rx_chainmask = + (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; } - return q; -} - -static void -ath9k_hw_set_txq_interrupts(struct ath_hal *ah, - struct ath9k_tx_queue_info *qi) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - __func__, ahp->ah_txOkInterruptMask, - ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask, - ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask); - - REG_WRITE(ah, AR_IMR_S0, - SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) - | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); - REG_WRITE(ah, AR_IMR_S1, - SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) - | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); - REG_RMW_FIELD(ah, AR_IMR_S2, - AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); -} + if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) + ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + pCap->low_2ghz_chan = 2312; + pCap->high_2ghz_chan = 2732; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); - return false; - } + pCap->low_5ghz_chan = 4920; + pCap->high_5ghz_chan = 6100; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n", - __func__, q); + pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; - qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ahp->ah_txOkInterruptMask &= ~(1 << q); - ahp->ah_txErrInterruptMask &= ~(1 << q); - ahp->ah_txDescInterruptMask &= ~(1 << q); - ahp->ah_txEolInterruptMask &= ~(1 << q); - ahp->ah_txUrnInterruptMask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); + pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - return true; -} + pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_channel *chan = ah->ah_curchan; - struct ath9k_tx_queue_info *qi; - u32 cwMin, chanCwMin, value; + if (ah->ah_config.ht_enable) + pCap->hw_caps |= ATH9K_HW_CAP_HT; + else + pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); - return true; - } + pCap->hw_caps |= ATH9K_HW_CAP_GTT; + pCap->hw_caps |= ATH9K_HW_CAP_VEOL; + pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; + pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q); + if (capField & AR_EEPROM_EEPCAP_MAXQCU) + pCap->total_queues = + MS(capField, AR_EEPROM_EEPCAP_MAXQCU); + else + pCap->total_queues = ATH9K_NUM_TX_QUEUES; - if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { - if (chan && IS_CHAN_B(chan)) - chanCwMin = INIT_CWMIN_11B; - else - chanCwMin = INIT_CWMIN; - - for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); - } else - cwMin = qi->tqi_cwmin; - - REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN) - | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) - | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); - - 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)); - - REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - REG_WRITE(ah, AR_DMISC(q), - AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); - - if (qi->tqi_cbrPeriod) { - REG_WRITE(ah, AR_QCBRCFG(q), - SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) - | SM(qi->tqi_cbrOverflowLimit, - AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi-> - tqi_cbrOverflowLimit - ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN - : - 0)); - } - if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { - REG_WRITE(ah, AR_QRDYTIMECFG(q), - SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | - AR_Q_RDYTIMECFG_EN); - } + if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) + pCap->keycache_size = + 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); + else + pCap->keycache_size = AR_KEYTABLE_SIZE; - REG_WRITE(ah, AR_DCHNTIME(q), - SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | - (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; + pCap->num_mr_retries = 4; + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); + if (AR_SREV_9280_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR928X_NUM_GPIO; + else + pCap->num_gpio_pins = AR_NUM_GPIO; + if (AR_SREV_9280_10_OR_LATER(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_WOW; + pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; + } else { + pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; + pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; } - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } - switch (qi->tqi_type) { - case ATH9K_TX_QUEUE_BEACON: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); - - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; - case ATH9K_TX_QUEUE_CAB: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); - value = (qi->tqi_readyTime - - (ah->ah_config.sw_beacon_response_time - - ah->ah_config.dma_beacon_response_time) - - - ah->ah_config.additional_swba_backoff) * - 1024; - REG_WRITE(ah, AR_QRDYTIMECFG(q), - value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); - break; - case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); - break; - case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; - default: - break; + if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_CST; + pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; + } else { + pCap->rts_aggr_limit = (8 * 1024); } - if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); + pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; + +#ifdef CONFIG_RFKILL + ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT); + if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { + ah->ah_rfkill_gpio = + MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); + ah->ah_rfkill_polarity = + MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); + + pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } +#endif - if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) - ahp->ah_txOkInterruptMask |= 1 << q; - else - ahp->ah_txOkInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) - ahp->ah_txErrInterruptMask |= 1 << q; - else - ahp->ah_txErrInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) - ahp->ah_txDescInterruptMask |= 1 << q; - else - ahp->ah_txDescInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) - ahp->ah_txEolInterruptMask |= 1 << q; - else - ahp->ah_txEolInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) - ahp->ah_txUrnInterruptMask |= 1 << q; + if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || + (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || + (ah->ah_macVersion == AR_SREV_VERSION_9160) || + (ah->ah_macVersion == AR_SREV_VERSION_9100) || + (ah->ah_macVersion == AR_SREV_VERSION_9280)) + pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; else - ahp->ah_txUrnInterruptMask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); - - return true; -} + pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - *txqs &= ahp->ah_intrTxqs; - ahp->ah_intrTxqs &= ~(*txqs); -} + if (AR_SREV_9280(ah)) + pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; + else + pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; -bool -ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (firstSeg) { - ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); - } else if (lastSeg) { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen; - ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; - ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | + AR_EEPROM_EEREGCAP_EN_KK_U2 | + AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; } else { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen | AR_TxMore; - ads->ds_ctl2 = 0; - ads->ds_ctl3 = 0; + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; } - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - return true; -} -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); + pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; + + pCap->num_antcfg_5ghz = + ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_5GHZ); + pCap->num_antcfg_2ghz = + ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_2GHZ); - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; + return true; } -int -ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result) { - struct ar5416_desc *ads = AR5416DESC(ds); - - if ((ads->ds_txstatus9 & AR_TxDone) == 0) - return -EINPROGRESS; - - ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); - ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; - - if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; - if (ads->ds_txstatus9 & AR_TxOpExceeded) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; - if (ads->ds_txstatus1 & AR_TxTimerExpired) - ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->ds_txstatus1 & AR_DescCfgErr) - ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->ds_txstatus1 & AR_TxDataUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus0 & AR_TxBaStatus) { - ds->ds_txstat.ts_flags |= ATH9K_TX_BA; - ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; - ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; - } + struct ath_hal_5416 *ahp = AH5416(ah); + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ds->ds_txstat.ts_rateindex) { - case 0: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); - break; - case 1: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); - break; - case 2: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); - break; - case 3: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); - break; + switch (type) { + case ATH9K_CAP_CIPHER: + switch (capability) { + case ATH9K_CIPHER_AES_CCM: + case ATH9K_CIPHER_AES_OCB: + case ATH9K_CIPHER_TKIP: + case ATH9K_CIPHER_WEP: + case ATH9K_CIPHER_MIC: + case ATH9K_CIPHER_CLR: + return true; + default: + return false; + } + case ATH9K_CAP_TKIP_MIC: + switch (capability) { + case 0: + return true; + case 1: + return (ahp->ah_staId1Defaults & + AR_STA_ID1_CRPT_MIC_ENABLE) ? true : + false; + } + case ATH9K_CAP_TKIP_SPLIT: + return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? + false : true; + case ATH9K_CAP_WME_TKIPMIC: + return 0; + case ATH9K_CAP_PHYCOUNTERS: + return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; + case ATH9K_CAP_DIVERSITY: + return (REG_READ(ah, AR_PHY_CCK_DETECT) & + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? + true : false; + case ATH9K_CAP_PHYDIAG: + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + switch (capability) { + case 0: + return true; + case 1: + if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { + return false; + } else { + return (ahp->ah_staId1Defaults & + AR_STA_ID1_MCAST_KSRCH) ? true : + false; + } + } + return false; + case ATH9K_CAP_TSF_ADJUST: + return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? + true : false; + case ATH9K_CAP_RFSILENT: + if (capability == 3) + return false; + case ATH9K_CAP_ANT_CFG_2GHZ: + *result = pCap->num_antcfg_2ghz; + return true; + case ATH9K_CAP_ANT_CFG_5GHZ: + *result = pCap->num_antcfg_5ghz; + return true; + case ATH9K_CAP_TXPOW: + switch (capability) { + case 0: + return 0; + case 1: + *result = ah->ah_powerLimit; + return 0; + case 2: + *result = ah->ah_maxPowerLevel; + return 0; + case 3: + *result = ah->ah_tpScale; + return 0; + } + return false; + default: + return false; } - - ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); - ds->ds_txstat.evm0 = ads->AR_TxEVM0; - ds->ds_txstat.evm1 = ads->AR_TxEVM1; - ds->ds_txstat.evm2 = ads->AR_TxEVM2; - ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 1; - - return 0; } -void -ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) +bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status) { - struct ar5416_desc *ads = AR5416DESC(ds); struct ath_hal_5416 *ahp = AH5416(ah); + u32 v; - txPower += ahp->ah_txPowerIndexOffset; - if (txPower > 63) - txPower = 63; - - ads->ds_ctl0 = (pktLen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txPower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) - | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); - - ads->ds_ctl1 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ds_ctl6 = SM(keyType, AR_EncrType); - - if (AR_SREV_9285(ah)) { - - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; + switch (type) { + case ATH9K_CAP_TKIP_MIC: + if (setting) + ahp->ah_staId1Defaults |= + AR_STA_ID1_CRPT_MIC_ENABLE; + else + ahp->ah_staId1Defaults &= + ~AR_STA_ID1_CRPT_MIC_ENABLE; + return true; + case ATH9K_CAP_DIVERSITY: + v = REG_READ(ah, AR_PHY_CCK_DETECT); + if (setting) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + else + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + REG_WRITE(ah, AR_PHY_CCK_DETECT, v); + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + if (setting) + ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; + else + ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; + return true; + case ATH9K_CAP_TSF_ADJUST: + if (setting) + ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + else + ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; + return true; + default: + return false; } } -void -ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *last_ads = AR5416DESC(lastds); - u32 ds_ctl0; +/****************************/ +/* GPIO / RFKILL / Antennae */ +/****************************/ - (void) nseries; - (void) rtsctsDuration; +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, + u32 gpio, u32 type) +{ + int addr; + u32 gpio_shift, tmp; - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ds_ctl0 = ads->ds_ctl0; + if (gpio > 11) + addr = AR_GPIO_OUTPUT_MUX3; + else if (gpio > 5) + addr = AR_GPIO_OUTPUT_MUX2; + else + addr = AR_GPIO_OUTPUT_MUX1; - if (flags & ATH9K_TXDESC_RTSENA) { - ds_ctl0 &= ~AR_CTSEnable; - ds_ctl0 |= AR_RTSEnable; - } else { - ds_ctl0 &= ~AR_RTSEnable; - ds_ctl0 |= AR_CTSEnable; - } + gpio_shift = (gpio % 6) * 5; - ads->ds_ctl0 = ds_ctl0; + if (AR_SREV_9280_20_OR_LATER(ah) + || (addr != AR_GPIO_OUTPUT_MUX1)) { + REG_RMW(ah, addr, (type << gpio_shift), + (0x1f << gpio_shift)); } else { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + tmp = REG_READ(ah, addr); + tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); + tmp &= ~(0x1f << gpio_shift); + tmp |= (type << gpio_shift); + REG_WRITE(ah, addr, tmp); } - - ads->ds_ctl2 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ds_ctl3 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ds_ctl7 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - last_ads->ds_ctl2 = ads->ds_ctl2; - last_ads->ds_ctl3 = ads->ds_ctl3; } -void -ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen) +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) { - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - - ads->ds_ctl6 &= ~AR_AggrLen; - ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); -} + u32 gpio_shift; -void -ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - unsigned int ctl6; + ASSERT(gpio < ah->ah_caps.num_gpio_pins); - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + gpio_shift = gpio << 1; - ctl6 = ads->ds_ctl6; - ctl6 &= ~AR_PadDelim; - ctl6 |= SM(numDelims, AR_PadDelim); - ads->ds_ctl6 = ctl6; + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) { - struct ar5416_desc *ads = AR5416DESC(ds); + if (gpio >= ah->ah_caps.num_gpio_pins) + return 0xffffffff; - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; + if (AR_SREV_9280_10_OR_LATER(ah)) { + return (MS + (REG_READ(ah, AR_GPIO_IN_OUT), + AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; + } else { + return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & + AR_GPIO_BIT(gpio)) != 0; + } } -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - struct ar5416_desc *ads = AR5416DESC(ds); + u32 gpio_shift; - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); -} + ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); -void -ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, - u32 burstDuration) -{ - struct ar5416_desc *ads = AR5416DESC(ds); + gpio_shift = 2 * gpio; - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -void -ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, - u32 vmf) +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) { - struct ar5416_desc *ads = AR5416DESC(ds); - - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), + AR_GPIO_BIT(gpio)); } -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) +#ifdef CONFIG_RFKILL +void ath9k_enable_rfkill(struct ath_hal *ah) { - REG_WRITE(ah, AR_RXDP, rxdp); -} + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); -void ath9k_hw_rxena(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXE); + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); + + ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); } +#endif -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) { - if (set) { - - REG_SET_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - - if (!ath9k_hw_wait - (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { - u32 reg; - - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT)); + struct ath9k_channel *chan = ah->ah_curchan; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 ant_config; + u32 halNumAntConfig; - reg = REG_READ(ah, AR_OBS_BUS_1); - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: rx failed to go idle in 10 ms RXSM=0x%x\n", - __func__, reg); + halNumAntConfig = IS_CHAN_2GHZ(chan) ? + pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz; - return false; + if (cfg < halNumAntConfig) { + if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan, + cfg, &ant_config)) { + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + return 0; } - } else { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); } - return true; -} - -void -ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, - u32 filter1) -{ - REG_WRITE(ah, AR_MCAST_FIL0, filter0); - REG_WRITE(ah, AR_MCAST_FIL1, filter1); + return -EINVAL; } -bool -ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 size, u32 flags) +u32 ath9k_hw_getdefantenna(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - ads->ds_ctl1 = size & AR_BufLen; - if (flags & ATH9K_RXDESC_INTREQ) - ads->ds_ctl1 |= AR_RxIntrReq; - - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); - return true; + return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -int -ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) { - struct ar5416_desc ads; - struct ar5416_desc *adsp = AR5416DESC(ds); - - if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) - return -EINPROGRESS; - - ads.u.rx = adsp->u.rx; - - ds->ds_rxstat.rs_status = 0; - ds->ds_rxstat.rs_flags = 0; - - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; - - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); - if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) - ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); - else - ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; - - ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); - ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; - - ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - ds->ds_rxstat.rs_moreaggr = - (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; - ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); - ds->ds_rxstat.rs_flags = - (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; - ds->ds_rxstat.rs_flags |= - (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; - - if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; - if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; - if (ads.ds_rxstatus8 & AR_DecryptBusyErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; - - if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { - - if (ads.ds_rxstatus8 & AR_CRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; - else if (ads.ds_rxstatus8 & AR_PHYErr) { - u32 phyerr; - - ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; - phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); - ds->ds_rxstat.rs_phyerr = phyerr; - } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; - else if (ads.ds_rxstatus8 & AR_MichaelErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; - } - - return 0; + REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); } -static void ath9k_hw_setup_rate_table(struct ath_hal *ah, - struct ath9k_rate_table *rt) +bool ath9k_hw_setantennaswitch(struct ath_hal *ah, + enum ath9k_ant_setting settings, + struct ath9k_channel *chan, + u8 *tx_chainmask, + u8 *rx_chainmask, + u8 *antenna_cfgd) { - int i; - - if (rt->rateCodeToIndex[0] != 0) - return; - for (i = 0; i < 256; i++) - rt->rateCodeToIndex[i] = (u8) -1; - for (i = 0; i < rt->rateCount; i++) { - u8 code = rt->info[i].rateCode; - u8 cix = rt->info[i].controlRate; - - rt->rateCodeToIndex[code] = i; - rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; + struct ath_hal_5416 *ahp = AH5416(ah); + static u8 tx_chainmask_cfg, rx_chainmask_cfg; - rt->info[i].lpAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - false); - rt->info[i].spAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - true); - } -} + if (AR_SREV_9280(ah)) { + if (!tx_chainmask_cfg) { -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode) -{ - struct ath9k_rate_table *rt; - switch (mode) { - case ATH9K_MODE_11A: - rt = &ar5416_11a_table; - break; - case ATH9K_MODE_11B: - rt = &ar5416_11b_table; - break; - case ATH9K_MODE_11G: - rt = &ar5416_11g_table; - break; - case ATH9K_MODE_11NG_HT20: - case ATH9K_MODE_11NG_HT40PLUS: - case ATH9K_MODE_11NG_HT40MINUS: - rt = &ar5416_11ng_table; - break; - case ATH9K_MODE_11NA_HT20: - case ATH9K_MODE_11NA_HT40PLUS: - case ATH9K_MODE_11NA_HT40MINUS: - rt = &ar5416_11na_table; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n", - __func__, mode); - return NULL; - } - ath9k_hw_setup_rate_table(ah, rt); - return rt; -} + tx_chainmask_cfg = *tx_chainmask; + rx_chainmask_cfg = *rx_chainmask; + } -static const char *ath9k_hw_devname(u16 devid) -{ - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - return "Atheros 5416"; - case AR9160_DEVID_PCI: - return "Atheros 9160"; - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - return "Atheros 9280"; + switch (settings) { + case ATH9K_ANT_FIXED_A: + *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_FIXED_B: + if (ah->ah_caps.tx_chainmask > + ATH9K_ANTENNA1_CHAINMASK) { + *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + } + *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_VARIABLE: + *tx_chainmask = tx_chainmask_cfg; + *rx_chainmask = rx_chainmask_cfg; + *antenna_cfgd = true; + break; + default: + break; + } + } else { + ahp->ah_diversityControl = settings; } - return NULL; -} -const char *ath9k_hw_probe(u16 vendorid, u16 devid) -{ - return vendorid == ATHEROS_VENDOR_ID ? - ath9k_hw_devname(devid) : NULL; + return true; } -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error) +/*********************/ +/* General Operation */ +/*********************/ + +u32 ath9k_hw_getrxfilter(struct ath_hal *ah) { - struct ath_hal *ah = NULL; + u32 bits = REG_READ(ah, AR_RX_FILTER); + u32 phybits = REG_READ(ah, AR_PHY_ERR); - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - ah = ath9k_hw_do_attach(devid, sc, mem, error); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "devid=0x%x not supported.\n", devid); - ah = NULL; - *error = -ENXIO; - break; - } + if (phybits & AR_PHY_ERR_RADAR) + bits |= ATH9K_RX_FILTER_PHYRADAR; + if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) + bits |= ATH9K_RX_FILTER_PHYERR; - return ah; + return bits; } -u16 -ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble) +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) { - u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; - u32 kbps; - - kbps = rates->info[rateix].rateKbps; - - if (kbps == 0) - return 0; - switch (rates->info[rateix].phy) { + u32 phybits; - case PHY_CCK: - phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (shortPreamble && rates->info[rateix].shortPreamble) - phyTime >>= 1; - numBits = frameLen << 3; - txTime = CCK_SIFS_TIME + phyTime - + ((numBits * 1000) / kbps); - break; - case PHY_OFDM: - if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { - bitsPerSymbol = - (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + phybits = 0; + if (bits & ATH9K_RX_FILTER_PHYRADAR) + phybits |= AR_PHY_ERR_RADAR; + if (bits & ATH9K_RX_FILTER_PHYERR) + phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; + REG_WRITE(ah, AR_PHY_ERR, phybits); - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_QUARTER - + OFDM_PREAMBLE_TIME_QUARTER - + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); - } else if (ah->ah_curchan && - IS_CHAN_HALF_RATE(ah->ah_curchan)) { - bitsPerSymbol = - (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + if (phybits) + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + else + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); +} - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_HALF + - OFDM_PREAMBLE_TIME_HALF - + (numSymbols * OFDM_SYMBOL_TIME_HALF); - } else { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; +bool ath9k_hw_phy_disable(struct ath_hal *ah) +{ + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); +} - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME - + (numSymbols * OFDM_SYMBOL_TIME); - } - break; +bool ath9k_hw_disable(struct ath_hal *ah) +{ + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; - default: - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: unknown phy %u (rate ix %u)\n", __func__, - rates->info[rateix].phy, rateix); - txTime = 0; - break; - } - return txTime; + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) { - if (flags & CHANNEL_2GHZ) { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - else - return 15 + ((freq - 2512) / 20); - } else if (flags & CHANNEL_5GHZ) { - if (ath9k_regd_is_public_safety_sku(ah) && - IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; - } else if ((flags & CHANNEL_A) && (freq <= 5000)) { - return (freq - 4000) / 5; - } else { - return (freq - 5000) / 5; - } - } else { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - if (freq < 5000) { - if (ath9k_regd_is_public_safety_sku(ah) - && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == - 2) ? 5 : 0) - 49400) / 5; - } else if (freq > 4900) { - return (freq - 4000) / 5; - } else { - return 15 + ((freq - 2512) / 20); - } - } - return (freq - 5000) / 5; - } -} + struct ath9k_channel *chan = ah->ah_curchan; -/* We can tune this as we go by monitoring really low values */ -#define ATH9K_NF_TOO_LOW -60 + ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); -/* AR5416 may return very high value (like -31 dBm), in those cases the nf - * is incorrect and we should use the static NF value. Later we can try to - * find out why they are reporting these values */ -static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) -{ - if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: noise floor value detected (%d) is " - "lower than what we think is a " - "reasonable value (%d)\n", - __func__, nf, ATH9K_NF_TOO_LOW); + if (ath9k_hw_set_txpower(ah, chan, + ath9k_regd_get_ctl(ah, chan), + ath9k_regd_get_antenna_allowed(ah, chan), + chan->maxRegTxPower * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->ah_powerLimit)) != 0) return false; - } + return true; } -s16 -ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) { - struct ath9k_channel *ichan; - s16 nf; - - ichan = ath9k_regd_check_channel(ah, chan); - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); - return ATH_DEFAULT_NOISE_FLOOR; - } - if (ichan->rawNoiseFloor == 0) { - enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); - nf = NOISE_FLOOR[mode]; - } else - nf = ichan->rawNoiseFloor; - - if (!ath9k_hw_nf_in_range(ah, nf)) - nf = ATH_DEFAULT_NOISE_FLOOR; + struct ath_hal_5416 *ahp = AH5416(ah); - return nf; + memcpy(mac, ahp->ah_macaddr, ETH_ALEN); } -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) { struct ath_hal_5416 *ahp = AH5416(ah); - if (setting) - ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; - else - ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; + memcpy(ahp->ah_macaddr, mac, ETH_ALEN); + return true; } -bool ath9k_hw_phycounters(struct ath_hal *ah) +void ath9k_hw_setopmode(struct ath_hal *ah) { - struct ath_hal_5416 *ahp = AH5416(ah); - - return ahp->ah_hasHwPhyCounters ? true : false; + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); } -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1) { - return REG_READ(ah, AR_QTXDP(q)); + REG_WRITE(ah, AR_MCAST_FIL0, filter0); + REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp) +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) { - REG_WRITE(ah, AR_QTXDP(q), txdp); + struct ath_hal_5416 *ahp = AH5416(ah); - return true; + memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); } -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + struct ath_hal_5416 *ahp = AH5416(ah); + + memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); - REG_WRITE(ah, AR_Q_TXE, 1 << q); + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); return true; } -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) { - u32 npend; + struct ath_hal_5416 *ahp = AH5416(ah); - npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; - if (npend == 0) { + memcpy(ahp->ah_bssid, bssid, ETH_ALEN); + ahp->ah_assocId = assocId; - if (REG_READ(ah, AR_Q_TXE) & (1 << q)) - npend = 1; - } - return npend; + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | + ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); } -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +u64 ath9k_hw_gettsf64(struct ath_hal *ah) { - u32 wait; - - REG_WRITE(ah, AR_Q_TXD, 1 << q); - - for (wait = 1000; wait != 0; wait--) { - if (ath9k_hw_numtxpending(ah, q) == 0) - break; - udelay(100); - } + u64 tsf; - if (ath9k_hw_numtxpending(ah, q)) { - u32 tsfLow, j; + tsf = REG_READ(ah, AR_TSF_U32); + tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Num of pending TX Frames %d on Q %d\n", - __func__, ath9k_hw_numtxpending(ah, q), q); + return tsf; +} - for (j = 0; j < 2; j++) { - tsfLow = REG_READ(ah, AR_TSF_L32); - REG_WRITE(ah, AR_QUIET2, - SM(10, AR_QUIET2_QUIET_DUR)); - REG_WRITE(ah, AR_QUIET_PERIOD, 100); - REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_QUIET_TIMER_EN); +void ath9k_hw_reset_tsf(struct ath_hal *ah) +{ + int count; - if ((REG_READ(ah, AR_TSF_L32) >> 10) == - (tsfLow >> 10)) { - break; - } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: TSF have moved while trying to set " - "quiet time TSF: 0x%08x\n", - __func__, tsfLow); + count = 0; + while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { + count++; + if (count > 10) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n", + __func__); + break; } + udelay(10); + } + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); +} - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); +bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - udelay(200); - REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); + if (setting) + ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + else + ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - wait = 1000; + return true; +} - while (ath9k_hw_numtxpending(ah, q)) { - if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: Failed to stop Tx DMA in 100 " - "msec after killing last frame\n", - __func__); - break; - } - udelay(100); - } +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n", + __func__, us); + ahp->ah_slottime = (u32) -1; + return false; + } else { + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); + ahp->ah_slottime = us; + return true; } +} + +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) +{ + u32 macmode; + + if (mode == ATH9K_HT_MACMODE_2040 && + !ah->ah_config.cwm_ignore_extcca) + macmode = AR_2040_JOINED_RX_CLEAR; + else + macmode = 0; - REG_WRITE(ah, AR_Q_TXD, 0); - return wait != 0; + REG_WRITE(ah, AR_2040_MODE, macmode); } diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 2113818..6a29f2d 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -923,7 +923,7 @@ struct ath_hal_5416 { #define OFDM_PLCP_BITS_QUARTER 22 #define OFDM_SYMBOL_TIME_QUARTER 16 -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, enum eeprom_param param); #endif diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c new file mode 100644 index 0000000..c344a81 --- /dev/null +++ b/drivers/net/wireless/ath9k/mac.c @@ -0,0 +1,1031 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah, + struct ath9k_tx_queue_info *qi) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", + __func__, ahp->ah_txOkInterruptMask, + ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask, + ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask); + + REG_WRITE(ah, AR_IMR_S0, + SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) + | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); + REG_WRITE(ah, AR_IMR_S1, + SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) + | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); + REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); +} + +void ath9k_hw_dmaRegDump(struct ath_hal *ah) +{ + u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; + int qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase = &val[0], *dcuBase = &val[4]; + int i; + + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n"); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { + if (i % 4 == 0) + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); + + val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]); + } + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n"); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + + for (i = 0; i < ATH9K_NUM_QUEUES; + i++, qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "%2d %2x %1x %2x %2x\n", + i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), + val[2] & (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "qcu_stitch state: %2x qcu_fetch state: %2x\n", + (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "qcu_complete state: %2x dcu_complete state: %2x\n", + (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "dcu_arb state: %2x dcu_fp state: %2x\n", + (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", + (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", + (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", + (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n", + REG_READ(ah, AR_OBS_BUS_1)); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "AR_CR 0x%x \n", REG_READ(ah, AR_CR)); +} + +u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) +{ + return REG_READ(ah, AR_QTXDP(q)); +} + +bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp) +{ + REG_WRITE(ah, AR_QTXDP(q), txdp); + + return true; +} + +bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) +{ + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + + REG_WRITE(ah, AR_Q_TXE, 1 << q); + + return true; +} + +u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +{ + u32 npend; + + npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; + if (npend == 0) { + + if (REG_READ(ah, AR_Q_TXE) & (1 << q)) + npend = 1; + } + + return npend; +} + +bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 txcfg, curLevel, newLevel; + enum ath9k_int omask; + + if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) + return false; + + omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); + + txcfg = REG_READ(ah, AR_TXCFG); + curLevel = MS(txcfg, AR_FTRIG); + newLevel = curLevel; + if (bIncTrigLevel) { + if (curLevel < MAX_TX_FIFO_THRESHOLD) + newLevel++; + } else if (curLevel > MIN_TX_FIFO_THRESHOLD) + newLevel--; + if (newLevel != curLevel) + REG_WRITE(ah, AR_TXCFG, + (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); + + ath9k_hw_set_interrupts(ah, omask); + + ah->ah_txTrigLevel = newLevel; + + return newLevel != curLevel; +} + +bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +{ + u32 tsfLow, j, wait; + + REG_WRITE(ah, AR_Q_TXD, 1 << q); + + for (wait = 1000; wait != 0; wait--) { + if (ath9k_hw_numtxpending(ah, q) == 0) + break; + udelay(100); + } + + if (ath9k_hw_numtxpending(ah, q)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: Num of pending TX Frames %d on Q %d\n", + __func__, ath9k_hw_numtxpending(ah, q), q); + + for (j = 0; j < 2; j++) { + tsfLow = REG_READ(ah, AR_TSF_L32); + REG_WRITE(ah, AR_QUIET2, + SM(10, AR_QUIET2_QUIET_DUR)); + REG_WRITE(ah, AR_QUIET_PERIOD, 100); + REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_QUIET_TIMER_EN); + + if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) + break; + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: TSF have moved while trying to set " + "quiet time TSF: 0x%08x\n", + __func__, tsfLow); + } + + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + + udelay(200); + REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); + + wait = 1000; + + while (ath9k_hw_numtxpending(ah, q)) { + if ((--wait) == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_XMIT, + "%s: Failed to stop Tx DMA in 100 " + "msec after killing last frame\n", + __func__); + break; + } + udelay(100); + } + + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + } + + REG_WRITE(ah, AR_Q_TXD, 0); + + return wait != 0; +} + +bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (firstSeg) { + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); + } else if (lastSeg) { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen; + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + } else { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; + + return true; +} + +void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; +} + +int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if ((ads->ds_txstatus9 & AR_TxDone) == 0) + return -EINPROGRESS; + + ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); + ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; + ds->ds_txstat.ts_status = 0; + ds->ds_txstat.ts_flags = 0; + + if (ads->ds_txstatus1 & AR_ExcessiveRetries) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; + if (ads->ds_txstatus1 & AR_Filtered) + ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; + if (ads->ds_txstatus1 & AR_FIFOUnderrun) + ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; + if (ads->ds_txstatus9 & AR_TxOpExceeded) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; + if (ads->ds_txstatus1 & AR_TxTimerExpired) + ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + + if (ads->ds_txstatus1 & AR_DescCfgErr) + ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; + if (ads->ds_txstatus1 & AR_TxDataUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus0 & AR_TxBaStatus) { + ds->ds_txstat.ts_flags |= ATH9K_TX_BA; + ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; + ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; + } + + ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); + switch (ds->ds_txstat.ts_rateindex) { + case 0: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); + break; + case 1: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); + break; + case 2: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); + break; + case 3: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); + break; + } + + ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); + ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); + ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); + ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); + ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); + ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); + ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); + ds->ds_txstat.evm0 = ads->AR_TxEVM0; + ds->ds_txstat.evm1 = ads->AR_TxEVM1; + ds->ds_txstat.evm2 = ads->AR_TxEVM2; + ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); + ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); + ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); + ds->ds_txstat.ts_antenna = 1; + + return 0; +} + +void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5416 *ahp = AH5416(ah); + + txPower += ahp->ah_txPowerIndexOffset; + if (txPower > 63) + txPower = 63; + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txPower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); + + ads->ds_ctl1 = + (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) + | SM(type, AR_FrameType) + | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ads->ds_ctl6 = SM(keyType, AR_EncrType); + + if (AR_SREV_9285(ah)) { + ads->ds_ctl8 = 0; + ads->ds_ctl9 = 0; + ads->ds_ctl10 = 0; + ads->ds_ctl11 = 0; + } +} + +void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, + struct ath_desc *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *last_ads = AR5416DESC(lastds); + u32 ds_ctl0; + + (void) nseries; + (void) rtsctsDuration; + + if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { + ds_ctl0 = ads->ds_ctl0; + + if (flags & ATH9K_TXDESC_RTSENA) { + ds_ctl0 &= ~AR_CTSEnable; + ds_ctl0 |= AR_RTSEnable; + } else { + ds_ctl0 &= ~AR_RTSEnable; + ds_ctl0 |= AR_CTSEnable; + } + + ads->ds_ctl0 = ds_ctl0; + } else { + ads->ds_ctl0 = + (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + } + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + last_ads->ds_ctl2 = ads->ds_ctl2; + last_ads->ds_ctl3 = ads->ds_ctl3; +} + +void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, + u32 aggrLen) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + ads->ds_ctl6 &= ~AR_AggrLen; + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); +} + +void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, + u32 numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + unsigned int ctl6; + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ctl6 = ads->ds_ctl6; + ctl6 &= ~AR_PadDelim; + ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 = ctl6; +} + +void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= AR_IsAggr; + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; +} + +void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); +} + +void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, + u32 burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} + +void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, + u32 vmf) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (vmf) + ads->ds_ctl0 |= AR_VirtMoreFrag; + else + ads->ds_ctl0 &= ~AR_VirtMoreFrag; +} + +void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *txqs &= ahp->ah_intrTxqs; + ahp->ah_intrTxqs &= ~(*txqs); +} + +bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, + const struct ath9k_tx_queue_info *qinfo) +{ + u32 cw; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", + __func__, q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", + __func__); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi); + + qi->tqi_ver = qinfo->tqi_ver; + qi->tqi_subtype = qinfo->tqi_subtype; + qi->tqi_qflags = qinfo->tqi_qflags; + qi->tqi_priority = qinfo->tqi_priority; + if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) + qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); + else + qi->tqi_aifs = INIT_AIFS; + if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmin, 1024U); + qi->tqi_cwmin = 1; + while (qi->tqi_cwmin < cw) + qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; + } else + qi->tqi_cwmin = qinfo->tqi_cwmin; + if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmax, 1024U); + qi->tqi_cwmax = 1; + while (qi->tqi_cwmax < cw) + qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; + } else + qi->tqi_cwmax = INIT_CWMAX; + + if (qinfo->tqi_shretry != 0) + qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); + else + qi->tqi_shretry = INIT_SH_RETRY; + if (qinfo->tqi_lgretry != 0) + qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); + else + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; + qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; + qi->tqi_burstTime = qinfo->tqi_burstTime; + qi->tqi_readyTime = qinfo->tqi_readyTime; + + switch (qinfo->tqi_subtype) { + case ATH9K_WME_UPSD: + if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) + qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; + break; + default: + break; + } + + return true; +} + +bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, + struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", + __func__, q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", + __func__); + return false; + } + + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_ver = qi->tqi_ver; + qinfo->tqi_subtype = qi->tqi_subtype; + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_priority = qi->tqi_priority; + qinfo->tqi_aifs = qi->tqi_aifs; + qinfo->tqi_cwmin = qi->tqi_cwmin; + qinfo->tqi_cwmax = qi->tqi_cwmax; + qinfo->tqi_shretry = qi->tqi_shretry; + qinfo->tqi_lgretry = qi->tqi_lgretry; + qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; + qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; + qinfo->tqi_burstTime = qi->tqi_burstTime; + qinfo->tqi_readyTime = qi->tqi_readyTime; + + return true; +} + +int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_tx_queue_info *qi; + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + int q; + + switch (type) { + case ATH9K_TX_QUEUE_BEACON: + q = pCap->total_queues - 1; + break; + case ATH9K_TX_QUEUE_CAB: + q = pCap->total_queues - 2; + break; + case ATH9K_TX_QUEUE_PSPOLL: + q = 1; + break; + case ATH9K_TX_QUEUE_UAPSD: + q = pCap->total_queues - 3; + break; + case ATH9K_TX_QUEUE_DATA: + for (q = 0; q < pCap->total_queues; q++) + if (ahp->ah_txq[q].tqi_type == + ATH9K_TX_QUEUE_INACTIVE) + break; + if (q == pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: no available tx queue\n", __func__); + return -1; + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n", + __func__, type); + return -1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: tx queue %u already active\n", __func__, q); + return -1; + } + memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); + qi->tqi_type = type; + if (qinfo == NULL) { + qi->tqi_qflags = + TXQ_FLAG_TXOKINT_ENABLE + | TXQ_FLAG_TXERRINT_ENABLE + | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_physCompBuf = 0; + } else { + qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; + (void) ath9k_hw_set_txq_props(ah, q, qinfo); + } + + return q; +} + +bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", + __func__, q); + return false; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", + __func__, q); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n", + __func__, q); + + qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; + ahp->ah_txOkInterruptMask &= ~(1 << q); + ahp->ah_txErrInterruptMask &= ~(1 << q); + ahp->ah_txDescInterruptMask &= ~(1 << q); + ahp->ah_txEolInterruptMask &= ~(1 << q); + ahp->ah_txUrnInterruptMask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_channel *chan = ah->ah_curchan; + struct ath9k_tx_queue_info *qi; + u32 cwMin, chanCwMin, value; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", + __func__, q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", + __func__, q); + return true; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q); + + if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { + if (chan && IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); + } else + cwMin = qi->tqi_cwmin; + + REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) | + SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | + SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + 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)); + + REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + + if (qi->tqi_cbrPeriod) { + REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | + SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + } + if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { + REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | + AR_Q_RDYTIMECFG_EN); + } + + REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | + (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + + if (qi->tqi_burstTime + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_RDYTIME_EXP_POLICY); + + } + + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_FRAG_BKOFF_EN); + } + switch (qi->tqi_type) { + case ATH9K_TX_QUEUE_BEACON: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); + + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S) + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); + break; + case ATH9K_TX_QUEUE_CAB: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); + value = (qi->tqi_readyTime - + (ah->ah_config.sw_beacon_response_time - + ah->ah_config.dma_beacon_response_time) - + ah->ah_config.additional_swba_backoff) * 1024; + REG_WRITE(ah, AR_QRDYTIMECFG(q), + value | AR_Q_RDYTIMECFG_EN); + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); + break; + case ATH9K_TX_QUEUE_PSPOLL: + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + break; + case ATH9K_TX_QUEUE_UAPSD: + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + break; + default: + break; + } + + if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + + if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) + ahp->ah_txOkInterruptMask |= 1 << q; + else + ahp->ah_txOkInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) + ahp->ah_txErrInterruptMask |= 1 << q; + else + ahp->ah_txErrInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) + ahp->ah_txDescInterruptMask |= 1 << q; + else + ahp->ah_txDescInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) + ahp->ah_txEolInterruptMask |= 1 << q; + else + ahp->ah_txEolInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) + ahp->ah_txUrnInterruptMask |= 1 << q; + else + ahp->ah_txUrnInterruptMask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf) +{ + struct ar5416_desc ads; + struct ar5416_desc *adsp = AR5416DESC(ds); + u32 phyerr; + + if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) + return -EINPROGRESS; + + ads.u.rx = adsp->u.rx; + + ds->ds_rxstat.rs_status = 0; + ds->ds_rxstat.rs_flags = 0; + + ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; + ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + + ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); + ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); + ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); + ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); + ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); + ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); + if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) + ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); + else + ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; + + ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); + ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + + ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + ds->ds_rxstat.rs_moreaggr = + (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); + ds->ds_rxstat.rs_flags = + (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; + ds->ds_rxstat.rs_flags |= + (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; + + if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; + if (ads.ds_rxstatus8 & AR_DecryptBusyErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; + + if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { + if (ads.ds_rxstatus8 & AR_CRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; + else if (ads.ds_rxstatus8 & AR_PHYErr) { + ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; + phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); + ds->ds_rxstat.rs_phyerr = phyerr; + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; + else if (ads.ds_rxstatus8 & AR_MichaelErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; + } + + return 0; +} + +bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 size, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & ATH9K_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + ads->ds_rxstatus8 &= ~AR_RxDone; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + memset(&(ads->u), 0, sizeof(ads->u)); + + return true; +} + +bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +{ + u32 reg; + + if (set) { + REG_SET_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | + AR_DIAG_RX_ABORT)); + + reg = REG_READ(ah, AR_OBS_BUS_1); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "%s: rx failed to go idle in 10 ms RXSM=0x%x\n", + __func__, reg); + + return false; + } + } else { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + } + + return true; +} + +void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) +{ + REG_WRITE(ah, AR_RXDP, rxdp); +} + +void ath9k_hw_rxena(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +void ath9k_hw_startpcureceive(struct ath_hal *ah) +{ + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + ath9k_enable_mib_counters(ah); + + ath9k_ani_reset(ah); +} + +void ath9k_hw_stoppcurecv(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + + ath9k_hw_disable_mib_counters(ah); +} + +bool ath9k_hw_stopdmarecv(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: dma failed to stop in 10ms\n" + "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", + __func__, + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return false; + } else { + return true; + } +} diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index eb9121f..4f1c8bf 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c @@ -215,7 +215,7 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) return true; - eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV); + eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV); RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1); @@ -235,15 +235,15 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (eepMinorRev >= 2) { if (IS_CHAN_2GHZ(chan)) { - ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2); - db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2); + ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2); + db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, ob2GHz, 3, 197, 0); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, db2GHz, 3, 194, 0); } else { - ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5); - db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5); + ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5); + db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, ob5GHz, 3, 203, 0); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, -- cgit v1.1 From 50fdae2c7bcb6417997f90c3d9853a59a9ed06ce Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:16:52 +0530 Subject: ath9k: Remove unused function ath_get_currentCountry() Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 23 ----------------------- drivers/net/wireless/ath9k/core.h | 2 -- 2 files changed, 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index aa1f1fc..b45953f 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -17,8 +17,6 @@ #include "core.h" #include "regd.h" -static int ath_outdoor; /* enable outdoor use */ - static u32 ath_chainmask_sel_up_rssi_thres = ATH_CHAINMASK_SEL_UP_RSSI_THRES; static u32 ath_chainmask_sel_down_rssi_thres = @@ -1349,27 +1347,6 @@ void ath_update_txpow(struct ath_softc *sc) } } -/* Return the current country and domain information */ -void ath_get_currentCountry(struct ath_softc *sc, - struct ath9k_country_entry *ctry) -{ - ath9k_regd_get_current_country(sc->sc_ah, ctry); - - /* If HAL not specific yet, since it is band dependent, - * use the one we passed in. */ - if (ctry->countryCode == CTRY_DEFAULT) { - ctry->iso[0] = 0; - ctry->iso[1] = 0; - } else if (ctry->iso[0] && ctry->iso[1]) { - if (!ctry->iso[2]) { - if (ath_outdoor) - ctry->iso[2] = 'O'; - else - ctry->iso[2] = 'I'; - } - } -} - /**************************/ /* Slow Antenna Diversity */ /**************************/ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index c03acf7..fdaecb1 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1018,8 +1018,6 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); void ath_setslottime(struct ath_softc *sc); void ath_update_txpow(struct ath_softc *sc); 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); #endif /* CORE_H */ -- cgit v1.1 From 9c84b7978f1b99048bf31be5a0218cd509e74148 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:17:13 +0530 Subject: ath9k: Streamline attach/detach Simplify attach and detach routines by consolidating the stop and suspend functions. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 218 ++++++++++++++------------------------ drivers/net/wireless/ath9k/core.h | 3 +- drivers/net/wireless/ath9k/main.c | 185 ++++++++++++++------------------ 3 files changed, 158 insertions(+), 248 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index b45953f..1826818 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -186,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc) struct ath9k_channel *c; /* Fill in ah->ah_channels */ - if (!ath9k_regd_init_channels(ah, - ATH_CHAN_MAX, - (u32 *)&nchan, - regclassids, - ATH_REGCLASSIDS_MAX, - &nregclass, - CTRY_DEFAULT, - false, - 1)) { + if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, + regclassids, ATH_REGCLASSIDS_MAX, + &nregclass, CTRY_DEFAULT, false, 1)) { u32 rd = ah->ah_currentRD; - DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to collect channel list; " "regdomain likely %u country code %u\n", @@ -217,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc) chan_2ghz[a].max_power = c->maxTxPower; if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_2ghz[a].flags |= - IEEE80211_CHAN_NO_IBSS; + chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; if (c->channelFlags & CHANNEL_PASSIVE) - chan_2ghz[a].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; band_2ghz->n_channels = ++a; DPRINTF(sc, ATH_DBG_CONFIG, "%s: 2MHz channel: %d, " "channelFlags: 0x%x\n", - __func__, - c->channel, - c->channelFlags); + __func__, c->channel, c->channelFlags); } else if (IS_CHAN_5GHZ(c)) { chan_5ghz[b].band = IEEE80211_BAND_5GHZ; chan_5ghz[b].center_freq = c->channel; chan_5ghz[b].max_power = c->maxTxPower; if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_5ghz[b].flags |= - IEEE80211_CHAN_NO_IBSS; + chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; if (c->channelFlags & CHANNEL_PASSIVE) - chan_5ghz[b].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; band_5ghz->n_channels = ++b; DPRINTF(sc, ATH_DBG_CONFIG, "%s: 5MHz channel: %d, " "channelFlags: 0x%x\n", - __func__, - c->channel, - c->channelFlags); + __func__, c->channel, c->channelFlags); } } @@ -292,44 +277,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) } /* - * Stop the device, grabbing the top-level lock to protect - * against concurrent entry through ath_init (which can happen - * if another thread does a system call and the thread doing the - * stop is preempted). - */ - -static int ath_stop(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", - __func__, sc->sc_flags & SC_OP_INVALID); - - /* - * Shutdown the hardware and driver: - * stop output from above - * turn off timers - * disable interrupts - * clear transmit machinery - * clear receive machinery - * turn off the radio - * reclaim beacon resources - * - * Note that some of this work is not possible if the - * hardware is gone (invalid). - */ - - ath_draintxq(sc, false); - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_stoprecv(sc); - ath9k_hw_phy_disable(ah); - } else - sc->sc_rxlink = NULL; - - return 0; -} - -/* * Set the current channel * * Set/change channels. If the channel is really being changed, it's done @@ -650,16 +597,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_ah->ah_opmode); - /* - * Stop anything previously setup. This is safe - * whether this is the first time through or not. - */ - ath_stop(sc); - - /* Initialize chanmask selection */ - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - /* Reset SERDES registers */ ath9k_hw_configpcipowersave(ah, 0); @@ -685,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) goto done; } spin_unlock_bh(&sc->sc_resetlock); + /* * This is needed only to setup initial state * but it's best done after a reset. @@ -704,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) error = -EIO; goto done; } + /* Setup our intr mask. */ sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN @@ -733,30 +672,61 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) (sc->sc_ah->ah_opmode == ATH9K_M_STA) && !sc->sc_config.swBeaconProcess) sc->sc_imask |= ATH9K_INT_TIM; + + ath_setcurmode(sc, ath_chan2mode(initial_chan)); + /* * Don't enable interrupts here as we've not yet built our * vap and node data structures, which will be needed as soon * as we start receiving. */ - ath_setcurmode(sc, ath_chan2mode(initial_chan)); - - /* XXX: we must make sure h/w is ready and clear invalid flag - * before turning on interrupt. */ sc->sc_flags &= ~SC_OP_INVALID; + + ieee80211_wake_queues(sc->hw); done: return error; } +void ath_stop(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__); + + ieee80211_stop_queues(sc->hw); + + /* make sure h/w will not generate any interrupt + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(ah, 0); + + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_draintxq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(ah); + } else + sc->sc_rxlink = NULL; + +#ifdef CONFIG_RFKILL + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(sc->sc_ah); + ath9k_hw_configpcipowersave(sc->sc_ah, 1); + + sc->sc_flags |= SC_OP_INVALID; +} + int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; int status; int error = 0; - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, retry_tx); /* stop xmit */ - ath_stoprecv(sc); /* stop recv */ - ath_flushrecv(sc); /* flush recv queue */ + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, retry_tx); + ath_stoprecv(sc); + ath_flushrecv(sc); /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); @@ -771,7 +741,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } spin_unlock_bh(&sc->sc_resetlock); - if (ath_startrecv(sc) != 0) /* restart recv */ + if (ath_startrecv(sc) != 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to start recv logic\n", __func__); @@ -804,29 +774,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return error; } -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_flags & SC_OP_INVALID) - return -EIO; - - /* Shut off the interrupt before setting sc->sc_invalid to '1' */ - ath9k_hw_set_interrupts(ah, 0); - - /* XXX: we must make sure h/w will not generate any interrupt - * before setting the invalid flag. */ - sc->sc_flags |= SC_OP_INVALID; - - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - - ath9k_hw_configpcipowersave(sc->sc_ah, 1); - - return 0; -} - /* Interrupt handler. Most of the actual processing is deferred. * It's the caller's responsibility to ensure the chip is awake. */ @@ -994,11 +941,9 @@ int ath_init(u16 devid, struct ath_softc *sc) /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; - sc->sc_debug = DBG_DEFAULT; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); - /* Initialize tasklet */ + spin_lock_init(&sc->sc_resetlock); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, (unsigned long)sc); @@ -1011,8 +956,6 @@ int ath_init(u16 devid, struct ath_softc *sc) /* XXX assert csz is non-zero */ sc->sc_cachelsz = csz << 2; /* convert to bytes */ - spin_lock_init(&sc->sc_resetlock); - ah = ath9k_hw_attach(devid, sc, sc->mem, &status); if (ah == NULL) { DPRINTF(sc, ATH_DBG_FATAL, @@ -1023,10 +966,6 @@ int ath_init(u16 devid, struct ath_softc *sc) } sc->sc_ah = ah; - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ - sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; - /* Get the hardware key cache size. */ sc->sc_keymax = ah->ah_caps.keycache_size; if (sc->sc_keymax > ATH_KEYMAX) { @@ -1054,17 +993,14 @@ int ath_init(u16 devid, struct ath_softc *sc) set_bit(i + 64, sc->sc_keymap); set_bit(i + 32 + 64, sc->sc_keymap); } - /* - * Collect the channel list using the default country - * code and including outdoor channels. The 802.11 layer - * is resposible for filtering this list based on settings - * like the phy mode. - */ + + /* Collect the channel list using the default country code */ + error = ath_setup_channels(sc); if (error) goto bad; - /* default to STA mode */ + /* default to MONITOR mode */ sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; /* Setup rate tables */ @@ -1134,6 +1070,10 @@ int ath_init(u16 devid, struct ath_softc *sc) goto bad2; } + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); sc->sc_rc = ath_rate_attach(ah); @@ -1194,6 +1134,7 @@ int ath_init(u16 devid, struct ath_softc *sc) ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); } + sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ /* initialize beacon slots */ @@ -1208,6 +1149,22 @@ int ath_init(u16 devid, struct ath_softc *sc) ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); #endif + /* setup channels and rates */ + + sc->sbands[IEEE80211_BAND_2GHZ].channels = + sc->channels[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = + sc->rates[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = + sc->channels[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + sc->rates[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + } + return 0; bad2: /* cleanup tx queues */ @@ -1217,27 +1174,8 @@ bad2: bad: if (ah) ath9k_hw_detach(ah); - return error; -} - -void ath_deinit(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int i; - DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - ath_stop(sc); - 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 */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); - ath9k_hw_detach(ah); + return error; } /*******************/ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index fdaecb1..49d2f89 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -997,9 +997,8 @@ struct ath_softc { }; int ath_init(u16 devid, struct ath_softc *sc); -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); +void ath_stop(struct ath_softc *sc); irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0194e44..0d60002 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -616,6 +616,7 @@ fail: } #ifdef CONFIG_RFKILL + /*******************/ /* Rfkill */ /*******************/ @@ -816,43 +817,72 @@ static void ath_deinit_rfkill(struct ath_softc *sc) sc->rf_kill.rfkill = NULL; } } + +static int ath_start_rfkill_poll(struct ath_softc *sc) +{ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); + + if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { + if (rfkill_register(sc->rf_kill.rfkill)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to register rfkill\n"); + rfkill_free(sc->rf_kill.rfkill); + + /* Deinitialize the device */ + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + ath_detach(sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(hw); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } + + return 0; +} #endif /* CONFIG_RFKILL */ -static int ath_detach(struct ath_softc *sc) +static void ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; + int i = 0; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); - /* Deinit LED control */ + ieee80211_unregister_hw(hw); + ath_deinit_leds(sc); #ifdef CONFIG_RFKILL - /* deinit rfkill */ ath_deinit_rfkill(sc); #endif - - /* Unregister hw */ - - ieee80211_unregister_hw(hw); - - /* unregister Rate control */ ath_rate_control_unregister(); - - /* tx/rx cleanup */ + ath_rate_detach(sc->sc_rc); ath_rx_cleanup(sc); ath_tx_cleanup(sc); - /* Deinit */ + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); - ath_deinit(sc); + if (!(sc->sc_flags & SC_OP_INVALID)) + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - return 0; + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->sc_txq[i]); + + ath9k_hw_detach(sc->sc_ah); } -static int ath_attach(u16 devid, - struct ath_softc *sc) +static int ath_attach(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; int error = 0; @@ -867,36 +897,15 @@ static int ath_attach(u16 devid, SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); - /* setup channels and rates */ - - sc->sbands[IEEE80211_BAND_2GHZ].channels = - sc->channels[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = - sc->rates[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 2.4Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = - sc->channels[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = - IEEE80211_BAND_5GHZ; - - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 5Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; - } + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); hw->queues = 4; hw->sta_data_size = sizeof(struct ath_node); @@ -913,6 +922,17 @@ static int ath_attach(u16 devid, goto bad; } + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; + error = ieee80211_register_hw(hw); if (error != 0) { ath_rate_control_unregister(); @@ -963,49 +983,26 @@ static int ath9k_start(struct ieee80211_hw *hw) pos = ath_get_channel(sc, curchan); if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; + error = -EINVAL; + goto exit; } sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - /* open ath_dev */ error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); if (error) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to complete ath_open\n", __func__); - return error; + goto exit; } #ifdef CONFIG_RFKILL - /* Start rfkill polling */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); - - if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { - if (rfkill_register(sc->rf_kill.rfkill)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to register rfkill\n"); - rfkill_free(sc->rf_kill.rfkill); - - /* Deinitialize the device */ - if (sc->pdev->irq) - free_irq(sc->pdev->irq, sc); - ath_detach(sc); - pci_iounmap(sc->pdev, sc->mem); - pci_release_region(sc->pdev, 0); - pci_disable_device(sc->pdev); - ieee80211_free_hw(hw); - return -EIO; - } else { - sc->sc_flags |= SC_OP_RFKILL_REGISTERED; - } - } + error = ath_start_rfkill_poll(sc); #endif - ieee80211_wake_queues(hw); - return 0; +exit: + return error; } static int ath9k_tx(struct ieee80211_hw *hw, @@ -1065,21 +1062,15 @@ exit: static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - int error; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); - - error = ath_suspend(sc); - if (error) - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Device is no longer present\n", __func__); + if (sc->sc_flags & SC_OP_INVALID) { + DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__); + return; + } - ieee80211_stop_queues(hw); + ath_stop(sc); -#ifdef CONFIG_RFKILL - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -1643,17 +1634,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad2; } - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_AMPDU_AGGREGATION; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -1701,17 +1681,10 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; - enum ath9k_int status; - if (pdev->irq) { - ath9k_hw_set_interrupts(sc->sc_ah, 0); - /* clear the ISR */ - ath9k_hw_getisr(sc->sc_ah, &status); - sc->sc_flags |= SC_OP_INVALID; - free_irq(pdev->irq, sc); - } ath_detach(sc); - + if (pdev->irq) + free_irq(pdev->irq, sc); pci_iounmap(pdev, sc->mem); pci_release_region(pdev, 0); pci_disable_device(pdev); -- cgit v1.1 From 154662a6356ec3ccfea0a22218cf149220ea6373 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:17:34 +0530 Subject: ath9k: Remove unnecessary TSF reset The TSF is already reset properly via mac80211's callback. Resetting it in config_interface() is not needed. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0d60002..01a5be9 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1237,17 +1237,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->sc_config.ath_aggr_prot = 0; - /* - * Reset our TSF so that its value is lower than the - * beacon that we are trying to catch. - * Only then hw will update its TSF register with the - * new beacon. Reset the TSF before setting the BSSID - * to avoid allowing in any frames that would update - * our TSF only to have us clear it - * immediately thereafter. - */ - ath9k_hw_reset_tsf(sc->sc_ah); - /* Disable BMISS interrupt when we're not associated */ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & -- cgit v1.1 From 05a1e2d111c98340fb17ec702cf09450eec3a947 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:17:54 +0530 Subject: ath9k: Enable interrupts at the proper place config_interface() was the wrong place to enable interrupts when bringing up an interface, move it to ath_open(). Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 9 ++++----- drivers/net/wireless/ath9k/main.c | 6 ------ 2 files changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 1826818..d138446 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -675,13 +675,12 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) ath_setcurmode(sc, ath_chan2mode(initial_chan)); - /* - * Don't enable interrupts here as we've not yet built our - * vap and node data structures, which will be needed as soon - * as we start receiving. - */ sc->sc_flags &= ~SC_OP_INVALID; + /* Disable BMISS interrupt when we're not associated */ + sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(sc->sc_ah,sc->sc_imask); + ieee80211_wake_queues(sc->hw); done: return error; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 01a5be9..85a23c6 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1237,12 +1237,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->sc_config.ath_aggr_prot = 0; - /* Disable BMISS interrupt when we're not associated */ - ath9k_hw_set_interrupts(sc->sc_ah, - sc->sc_imask & - ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: RX filter 0x%x bssid %pM aid 0x%x\n", __func__, rfilt, -- cgit v1.1 From ccc75c526611e62c4c9adcb4a62bf4a164478d2c Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:18:14 +0530 Subject: ath9k: Remove ath_tx_aggr_resp() Accessing mac80211's internal state machine is wrong. Will add resumption of a TID in a later patch. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 11 +------ drivers/net/wireless/ath9k/rc.c | 65 ++------------------------------------- drivers/net/wireless/ath9k/xmit.c | 12 +++----- 3 files changed, 8 insertions(+), 80 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 49d2f89..dd33cb7 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -588,14 +588,6 @@ enum ATH_AGGR_STATUS { ATH_AGGR_8K_LIMITED, }; -enum ATH_AGGR_CHECK { - AGGR_NOT_REQUIRED, - AGGR_REQUIRED, - AGGR_CLEANUP_PROGRESS, - AGGR_EXCHANGE_PROGRESS, - AGGR_EXCHANGE_DONE -}; - struct aggr_rifs_param { int param_max_frames; int param_max_len; @@ -621,8 +613,7 @@ struct ath_node { void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid); -enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, - struct ath_node *an, u8 tidno); +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); void ath_rx_aggr_teardown(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index fecc839..aa6bfd7 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1879,49 +1879,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, tx_info->control.vif = NULL; } -static void ath_tx_aggr_resp(struct ath_softc *sc, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_node *an, - u8 tidno) -{ - struct ath_atx_tid *txtid; - u16 buffersize = 0; - int state; - struct sta_info *si; - - if (!(sc->sc_flags & SC_OP_TXAGGR)) - return; - - txtid = ATH_AN_2_TID(an, tidno); - if (!txtid->paused) - return; - - /* - * XXX: This is entirely busted, we aren't supposed to - * access the sta from here because it's internal - * to mac80211, and looking at the state without - * locking is wrong too. - */ - si = container_of(sta, struct sta_info, sta); - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_cap.ampdu_factor; /* FIXME */ - state = si->ampdu_mlme.tid_state_tx[tidno]; - - if (state & HT_ADDBA_RECEIVED_MSK) { - txtid->state |= AGGR_ADDBA_COMPLETE; - txtid->state &= ~AGGR_ADDBA_PROGRESS; - txtid->baw_size = buffersize; - - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Resuming tid, buffersize: %d\n", - __func__, - buffersize); - - ath_tx_resume_tid(sc, txtid); - } -} - static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { @@ -1934,7 +1891,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ath_rate_node *ath_rc_priv = priv_sta; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe = FALSE, chk, ret; + int is_probe = FALSE; s8 lowest_idx; __le16 fc = hdr->frame_control; u8 *qc, tid; @@ -1981,26 +1938,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; - an = (struct ath_node *)sta->drv_priv; - chk = ath_tx_aggr_check(sc, an, tid); - if (chk == AGGR_REQUIRED) { - ret = ieee80211_start_tx_ba_session(hw, - hdr->addr1, tid); - if (ret) - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to start tx " - "aggr for: %pM\n", - __func__, - hdr->addr1); - else - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Started tx aggr for: %pM\n", - __func__, - hdr->addr1); - } else if (chk == AGGR_EXCHANGE_PROGRESS) - ath_tx_aggr_resp(sc, sband, sta, an, tid); + if(ath_tx_aggr_check(sc, an, tid)) + ieee80211_start_tx_ba_session(hw, hdr->addr1, tid); } } } diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index f41030d..7e6f4e5 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2322,28 +2322,24 @@ u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum) return sc->sc_txq[qnum].axq_aggr_depth; } -/* Check if an ADDBA is required. A valid node must be passed. */ -enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, - struct ath_node *an, - u8 tidno) +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) { struct ath_atx_tid *txtid; if (!(sc->sc_flags & SC_OP_TXAGGR)) - return AGGR_NOT_REQUIRED; + return false; - /* ADDBA exchange must be completed before sending aggregates */ txtid = ATH_AN_2_TID(an, tidno); if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { if (!(txtid->state & AGGR_ADDBA_PROGRESS) && (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { txtid->addba_exchangeattempts++; - return AGGR_REQUIRED; + return true; } } - return AGGR_NOT_REQUIRED; + return false; } /* Start TX aggregation */ -- cgit v1.1 From 7f959032bbee5eedaf4c606d11f0c5d41498644e Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:18:39 +0530 Subject: ath9k: Clear HT info on starting the driver Doing an interface down/up leaves the old HT assoc information, clear it. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 85a23c6..e177de4 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -978,6 +978,8 @@ static int ath9k_start(struct ieee80211_hw *hw) DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " "initial channel: %d MHz\n", __func__, curchan->center_freq); + memset(&sc->sc_ht_info, 0, sizeof(struct ath_ht_info)); + /* setup initial channel */ pos = ath_get_channel(sc, curchan); -- cgit v1.1 From dca3edb88ef567671886a85c5e40d491ccecf934 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:19:01 +0530 Subject: ath9k: Remove internal RX A-MPDU processing mac80211 has RX A-MPDU reordering support. Use that and remove redundant RX processing within the driver. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 6 - drivers/net/wireless/ath9k/core.h | 43 ---- drivers/net/wireless/ath9k/main.c | 36 +-- drivers/net/wireless/ath9k/recv.c | 501 -------------------------------------- 4 files changed, 2 insertions(+), 584 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index d138446..5f5184a 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1189,8 +1189,6 @@ void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_node_init(sc, an); - if (sc->sc_flags & SC_OP_RXAGGR) - ath_rx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + sta->ht_cap.ampdu_factor); @@ -1208,8 +1206,6 @@ void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_node_cleanup(sc, an); - if (sc->sc_flags & SC_OP_RXAGGR) - ath_rx_node_cleanup(sc, an); } /* @@ -1230,8 +1226,6 @@ void ath_newassoc(struct ath_softc *sc, for (tidno = 0; tidno < WME_NUM_TID; tidno++) { if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_aggr_teardown(sc, an, tidno); - 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 dd33cb7..5b17e88 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -304,15 +304,7 @@ void ath_descdma_cleanup(struct ath_softc *sc, #define ATH_MAX_ANTENNA 3 #define ATH_RXBUF 512 -#define ATH_RX_TIMEOUT 40 /* 40 milliseconds */ #define WME_NUM_TID 16 -#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ -#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ - -enum ATH_RX_TYPE { - ATH_RX_NON_CONSUMED = 0, - ATH_RX_CONSUMED -}; /* per frame rx status block */ struct ath_recv_status { @@ -346,47 +338,18 @@ struct ath_rxbuf { struct ath_recv_status rx_status; /* cached rx status */ }; -/* Per-TID aggregate receiver state for a node */ -struct ath_arx_tid { - struct ath_node *an; - struct ath_rxbuf *rxbuf; /* re-ordering buffer */ - struct timer_list timer; - spinlock_t tidlock; - int baw_head; /* seq_next at head */ - int baw_tail; /* tail of block-ack window */ - int seq_reset; /* need to reset start sequence */ - int addba_exchangecomplete; - u16 seq_next; /* next expected sequence */ - u16 baw_size; /* block-ack window size */ -}; - -/* Per-node receiver aggregate state */ -struct ath_arx { - struct ath_arx_tid tid[WME_NUM_TID]; -}; - int ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); void ath_flushrecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); -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); void ath_handle_rx_intr(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); void ath_rx_cleanup(struct ath_softc *sc); int ath_rx_tasklet(struct ath_softc *sc, int flush); -int ath_rx_input(struct ath_softc *sc, - struct ath_node *node, - 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_subframe(struct ath_node *an, struct sk_buff *skb, - struct ath_recv_status *status); - /******/ /* TX */ /******/ @@ -599,7 +562,6 @@ struct aggr_rifs_param { /* Per-node aggregation state */ struct ath_node_aggr { struct ath_atx tx; /* node transmit state */ - struct ath_arx rx; /* node receive state */ }; /* driver-specific node state */ @@ -616,11 +578,6 @@ void ath_tx_resume_tid(struct ath_softc *sc, bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -int ath_rx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn); -int ath_rx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index e177de4..65a532e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -444,12 +444,10 @@ int _ath_rx_indicate(struct ath_softc *sc, u16 keyix) { struct ieee80211_hw *hw = sc->hw; - struct ath_node *an = NULL; struct ieee80211_rx_status rx_status; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; int hdrlen = ieee80211_get_hdrlen_from_skb(skb); int padsize; - enum ATH_RX_TYPE st; /* see if any padding is done by the hw and remove it */ if (hdrlen & 3) { @@ -473,28 +471,6 @@ int _ath_rx_indicate(struct ath_softc *sc, rx_status.flag |= RX_FLAG_DECRYPTED; } - if (an) { - ath_rx_input(sc, an, - skb, status, &st); - } - if (!an || (st != ATH_RX_CONSUMED)) - __ieee80211_rx(hw, skb, &rx_status); - - return 0; -} - -int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, - struct ath_recv_status *status) -{ - struct ath_softc *sc = an->an_sc; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_rx_status rx_status; - - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - if (!(status->flags & ATH_RX_DECRYPT_ERROR)) - rx_status.flag |= RX_FLAG_DECRYPTED; - __ieee80211_rx(hw, skb, &rx_status); return 0; @@ -1483,18 +1459,10 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, sta, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start RX aggregation\n", - __func__); + if (!(sc->sc_flags & SC_OP_RXAGGR)) + ret = -ENOTSUPP; break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, sta, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop RX aggregation\n", - __func__); break; case IEEE80211_AMPDU_TX_START: ret = ath_tx_aggr_start(sc, sta, tid, ssn); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 80f26b4..2ecb0a0 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -64,328 +64,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ath9k_hw_rxena(ah); } -/* Process received BAR frame */ - -static int ath_bar_rx(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb) -{ - struct ieee80211_bar *bar; - struct ath_arx_tid *rxtid; - struct sk_buff *tskb; - struct ath_recv_status *rx_status; - int tidno, index, cindex; - u16 seqno; - - /* look at BAR contents */ - - bar = (struct ieee80211_bar *)skb->data; - tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M) - >> IEEE80211_BAR_CTL_TID_S; - seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT; - - /* process BAR - indicate all pending RX frames till the BAR seqno */ - - rxtid = &an->an_aggr.rx.tid[tidno]; - - spin_lock_bh(&rxtid->tidlock); - - /* get relative index */ - - index = ATH_BA_INDEX(rxtid->seq_next, seqno); - - /* drop BAR if old sequence (index is too large) */ - - if ((index > rxtid->baw_size) && - (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2)))) - /* discard frame, ieee layer may not treat frame as a dup */ - goto unlock_and_free; - - /* complete receive processing for all pending frames upto BAR seqno */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - while ((rxtid->baw_head != rxtid->baw_tail) && - (rxtid->baw_head != cindex)) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - if (tskb != NULL) - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* ... and indicate rest of the frames in-order */ - - while (rxtid->baw_head != rxtid->baw_tail && - rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - -unlock_and_free: - spin_unlock_bh(&rxtid->tidlock); - /* free bar itself */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_CTL; -} - -/* Function to handle a subframe of aggregation when HT is enabled */ - -static int ath_ampdu_input(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *rx_status) -{ - struct ieee80211_hdr *hdr; - struct ath_arx_tid *rxtid; - struct ath_rxbuf *rxbuf; - u8 type, subtype; - u16 rxseq; - int tid = 0, index, cindex, rxdiff; - __le16 fc; - u8 *qc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - /* collect stats of frames with non-zero version */ - - if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) { - dev_kfree_skb(skb); - return -1; - } - - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; - - if (ieee80211_is_back_req(fc)) - return ath_bar_rx(sc, an, skb); - - /* special aggregate processing only for qos unicast data frames */ - - if (!ieee80211_is_data(fc) || - !ieee80211_is_data_qos(fc) || - is_multicast_ether_addr(hdr->addr1)) - return ath_rx_subframe(an, skb, rx_status); - - /* lookup rx tid state */ - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - 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); - return -1; - } - } - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock(&rxtid->tidlock); - - rxdiff = (rxtid->baw_tail - rxtid->baw_head) & - (ATH_TID_MAX_BUFS - 1); - - /* - * If the ADDBA exchange has not been completed by the source, - * process via legacy path (i.e. no reordering buffer is needed) - */ - if (!rxtid->addba_exchangecomplete) { - spin_unlock(&rxtid->tidlock); - return ath_rx_subframe(an, skb, rx_status); - } - - /* extract sequence number from recvd frame */ - - rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; - - if (rxtid->seq_reset) { - rxtid->seq_reset = 0; - rxtid->seq_next = rxseq; - } - - index = ATH_BA_INDEX(rxtid->seq_next, rxseq); - - /* drop frame if old sequence (index is too large) */ - - if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) { - /* discard frame, ieee layer may not treat frame as a dup */ - spin_unlock(&rxtid->tidlock); - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - /* sequence number is beyond block-ack window */ - - if (index >= rxtid->baw_size) { - - /* complete receive processing for all pending frames */ - - while (index >= rxtid->baw_size) { - - rxbuf = rxtid->rxbuf + rxtid->baw_head; - - if (rxbuf->rx_wbuf != NULL) { - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - } - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - - index--; - } - } - - /* add buffer to the recv ba window */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - rxbuf = rxtid->rxbuf + cindex; - - if (rxbuf->rx_wbuf != NULL) { - spin_unlock(&rxtid->tidlock); - /* duplicate frame */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - rxbuf->rx_wbuf = skb; - rxbuf->rx_time = get_timestamp(); - rxbuf->rx_status = *rx_status; - - /* advance tail if sequence received is newer - * than any received so far */ - - if (index >= rxdiff) { - rxtid->baw_tail = cindex; - INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS); - } - - /* indicate all in-order received frames */ - - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - mod_timer(&rxtid->timer, ATH_RX_TIMEOUT); - else - del_timer_sync(&rxtid->timer); - - spin_unlock(&rxtid->tidlock); - return IEEE80211_FTYPE_DATA; -} - -/* Timer to flush all received sub-frames */ - -static void ath_rx_timer(unsigned long data) -{ - struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data; - struct ath_node *an = rxtid->an; - struct ath_rxbuf *rxbuf; - int nosched; - - spin_lock_bh(&rxtid->tidlock); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - /* - * Stop if the next one is a very recent frame. - * - * Call get_timestamp in every iteration to protect against the - * case in which a new frame is received while we are executing - * this function. Using a timestamp obtained before entering - * the loop could lead to a very large time interval - * (a negative value typecast to unsigned), breaking the - * function's logic. - */ - if ((get_timestamp() - rxbuf->rx_time) < - (ATH_RX_TIMEOUT * HZ / 1000)) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - nosched = 0; - else - nosched = 1; /* no need to re-arm the timer again */ - - spin_unlock_bh(&rxtid->tidlock); -} - -/* Free all pending sub-frames in the re-ordering buffer */ - -static void ath_rx_flush_tid(struct ath_softc *sc, struct ath_arx_tid *rxtid, - int drop) -{ - struct ath_rxbuf *rxbuf; - unsigned long flag; - - spin_lock_irqsave(&rxtid->tidlock, flag); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - if (drop) - dev_kfree_skb(rxbuf->rx_wbuf); - else - ath_rx_subframe(rxtid->an, - rxbuf->rx_wbuf, - &rxbuf->rx_status); - - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - spin_unlock_irqrestore(&rxtid->tidlock, flag); -} - static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { @@ -716,23 +394,6 @@ void ath_flushrecv(struct ath_softc *sc) spin_unlock_bh(&sc->sc_rxflushlock); } -/* Process an individual frame */ - -int ath_rx_input(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *rx_status, - enum ATH_RX_TYPE *status) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - *status = ATH_RX_CONSUMED; - return ath_ampdu_input(sc, an, skb, rx_status); - } else { - *status = ATH_RX_NON_CONSUMED; - return -1; - } -} - /* Process receive queue, as well as LED, etc. */ int ath_rx_tasklet(struct ath_softc *sc, int flush) @@ -1091,165 +752,3 @@ rx_next: return 0; #undef PA2DESC } - -/* Process ADDBA request in per-TID data structure */ - -int ath_rx_aggr_start(struct ath_softc *sc, - struct ieee80211_sta *sta, - u16 tid, - u16 *ssn) -{ - struct ath_arx_tid *rxtid; - struct ath_node *an; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_supported_band *sband; - u16 buffersize = 0; - - an = (struct ath_node *)sta->drv_priv; - sband = hw->wiphy->bands[hw->conf.channel->band]; - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_cap.ampdu_factor; /* FIXME */ - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock_bh(&rxtid->tidlock); - 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. - */ - if (buffersize) - rxtid->baw_size = min(buffersize, rxtid->baw_size); - - /* set rx sequence number */ - rxtid->seq_next = *ssn; - - /* Allocate the receive buffers for this TID */ - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allcating rxbuffer for TID %d\n", __func__, tid); - - if (rxtid->rxbuf == NULL) { - /* - * If the rxbuff is not NULL at this point, we *probably* - * already allocated the buffer on a previous ADDBA, - * and this is a subsequent ADDBA that got through. - * Don't allocate, but use the value in the pointer, - * we zero it out when we de-allocate. - */ - rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf), GFP_ATOMIC); - } - if (rxtid->rxbuf == NULL) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to allocate RX buffer, " - "refusing ADDBA\n", __func__); - } else { - /* Ensure the memory is zeroed out (all internal - * pointers are null) */ - memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf)); - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allocated @%p\n", __func__, rxtid->rxbuf); - - /* Allow aggregation reception */ - rxtid->addba_exchangecomplete = 1; - } - } - spin_unlock_bh(&rxtid->tidlock); - - return 0; -} - -/* Process DELBA */ - -int ath_rx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - - ath_rx_aggr_teardown(sc, an, tid); - return 0; -} - -/* Rx aggregation tear down */ - -void ath_rx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) -{ - struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid]; - - if (!rxtid->addba_exchangecomplete) - return; - - del_timer_sync(&rxtid->timer); - ath_rx_flush_tid(sc, rxtid, 0); - rxtid->addba_exchangecomplete = 0; - - /* De-allocate the receive buffer array allocated when addba started */ - - if (rxtid->rxbuf) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Deallocating TID %d rxbuff @%p\n", - __func__, tid, rxtid->rxbuf); - kfree(rxtid->rxbuf); - - /* Set pointer to null to avoid reuse*/ - rxtid->rxbuf = NULL; - } -} - -/* Initialize per-node receive state */ - -void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_arx_tid *rxtid; - int tidno; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - rxtid->an = an; - rxtid->seq_reset = 1; - rxtid->seq_next = 0; - rxtid->baw_size = WME_MAX_BA; - rxtid->baw_head = rxtid->baw_tail = 0; - - /* - * Ensure the buffer pointer is null at this point - * (needs to be allocated when addba is received) - */ - - rxtid->rxbuf = NULL; - setup_timer(&rxtid->timer, ath_rx_timer, - (unsigned long)rxtid); - spin_lock_init(&rxtid->tidlock); - - /* ADDBA state */ - rxtid->addba_exchangecomplete = 0; - } -} - -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_arx_tid *rxtid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - - if (!rxtid->addba_exchangecomplete) - continue; - - /* must cancel timer first */ - del_timer_sync(&rxtid->timer); - - /* drop any pending sub-frames */ - ath_rx_flush_tid(sc, rxtid, 1); - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); - - rxtid->addba_exchangecomplete = 0; - } -} -- cgit v1.1 From 8469cdef1f123e2e3e56645f1ac26c7cfb333d9c Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:19:28 +0530 Subject: mac80211: Add a new event in ieee80211_ampdu_mlme_action Send a notification to the driver on succesful reception of an ADDBA response, add IEEE80211_AMPDU_TX_RESUME for this purpose. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 + drivers/net/wireless/ath9k/main.c | 3 +++ drivers/net/wireless/ath9k/xmit.c | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 5b17e88..69e8d3e 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -581,6 +581,7 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_newassoc(struct ath_softc *sc, struct ath_node *node, int isnew, int isuapsd); void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 65a532e..fb50aa0 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1482,6 +1482,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; + case IEEE80211_AMPDU_TX_RESUME: + ath_tx_aggr_resume(sc, sta, tid); + break; default: DPRINTF(sc, ATH_DBG_FATAL, "%s: Unknown AMPDU action\n", __func__); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 7e6f4e5..fe386b6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2371,6 +2371,25 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return 0; } +/* Resume tx aggregation */ + +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +{ + struct ath_atx_tid *txtid; + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = + IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); + } +} + /* * Performs transmit side cleanup when TID changes from aggregated to * unaggregated. -- cgit v1.1 From 9ad9a26e7b7b6671a9aefbb1edb2e8a9ed50ee8d Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Oct 2008 08:30:54 -0400 Subject: ath5k: enable hardware encryption for WEP This change re-enables hardware encryption for ath5k after setting up mac80211 to handle the initialization vectors which happens to make it work. Add a module param (nohwcrypt) to optionally turn it off. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 6f368e8..4bf3678 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -60,6 +60,9 @@ #include "debug.h" static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /******************\ @@ -2975,11 +2978,12 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath5k_softc *sc = hw->priv; int ret = 0; + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + switch (key->alg) { case ALG_WEP: - /* XXX: fix hardware encryption, its not working. For now - * allow software encryption */ - /* break; */ + break; case ALG_TKIP: case ALG_CCMP: return -EOPNOTSUPP; @@ -2999,6 +3003,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } __set_bit(key->keyidx, sc->keymap); key->hw_key_idx = key->keyidx; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; case DISABLE_KEY: ath5k_hw_reset_key(sc->ah, key->keyidx); -- cgit v1.1 From 3f64b435ab76e79bfb3b4d36f043e6f892093b71 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Oct 2008 23:19:14 -0400 Subject: ath5k: update keycache to support TKIP handling Newer parts have slots at entry+64 for michael mic and can do WPA-TKIP in hardware. The open-sourced Atheros HAL has code for accessing this portion so now we know how where to put the key material. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 5 +-- drivers/net/wireless/ath5k/pcu.c | 64 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 4bf3678..c7ffcbb 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2983,8 +2983,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (key->alg) { case ALG_WEP: - break; case ALG_TKIP: + break; case ALG_CCMP: return -EOPNOTSUPP; default: @@ -3003,7 +3003,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } __set_bit(key->keyidx, sc->keymap); key->hw_key_idx = key->keyidx; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | + IEEE80211_KEY_FLAG_GENERATE_MMIC); break; case DISABLE_KEY: ath5k_hw_reset_key(sc->ah, key->keyidx); diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index 9c66985..d7f0c10 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -1021,17 +1021,29 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac) { unsigned int i; + int keylen; __le32 key_v[5] = {}; + __le32 key0 = 0, key1 = 0; + __le32 *rxmic, *txmic; u32 keytype; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; + bool is_tkip; ATH5K_TRACE(ah->ah_sc); - /* key->keylen comes in from mac80211 in bytes */ + is_tkip = (key->alg == ALG_TKIP); + + /* + * key->keylen comes in from mac80211 in bytes. + * TKIP is 128 bit + 128 bit mic + */ + keylen = (is_tkip) ? (128 / 8) : key->keylen; - if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + if (entry > AR5K_KEYTABLE_SIZE || + (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) return -EOPNOTSUPP; - switch (key->keylen) { + switch (keylen) { /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ case 40 / 8: memcpy(&key_v[0], key->key, 5); @@ -1045,24 +1057,66 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, memcpy(&key_v[4], &key->key[12], 1); keytype = AR5K_KEYTABLE_TYPE_104; break; - /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ + /* WEP/TKIP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ case 128 / 8: memcpy(&key_v[0], &key->key[0], 6); memcpy(&key_v[2], &key->key[6], 6); memcpy(&key_v[4], &key->key[12], 4); - keytype = AR5K_KEYTABLE_TYPE_128; + keytype = is_tkip ? + AR5K_KEYTABLE_TYPE_TKIP : + AR5K_KEYTABLE_TYPE_128; break; default: return -EINVAL; /* shouldn't happen */ } + /* intentionally corrupt key until mic is installed */ + if (is_tkip) { + key0 = key_v[0] = ~key_v[0]; + key1 = key_v[1] = ~key_v[1]; + } + for (i = 0; i < ARRAY_SIZE(key_v); i++) ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), AR5K_KEYTABLE_OFF(entry, i)); ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); + if (is_tkip) { + /* Install rx/tx MIC */ + rxmic = (__le32 *) &key->key[16]; + txmic = (__le32 *) &key->key[24]; +#if 0 + /* MISC_MODE register & 0x04 - for mac srev >= griffin */ + key_v[0] = rxmic[0]; + key_v[1] = (txmic[0] >> 16) & 0xffff; + key_v[2] = rxmic[1]; + key_v[3] = txmic[0] & 0xffff; + key_v[4] = txmic[1]; +#else + key_v[0] = rxmic[0]; + key_v[1] = 0; + key_v[2] = rxmic[1]; + key_v[3] = 0; + key_v[4] = 0; +#endif + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(micentry, i)); + + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); + + /* restore first 2 words of key */ + ath5k_hw_reg_write(ah, le32_to_cpu(~key0), + AR5K_KEYTABLE_OFF(entry, 0)); + ath5k_hw_reg_write(ah, le32_to_cpu(~key1), + AR5K_KEYTABLE_OFF(entry, 1)); + } + return ath5k_hw_set_key_lladdr(ah, entry, mac); } -- cgit v1.1 From e4ea1c403acece78c271bf9cd6f797d1cb093df9 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 29 Oct 2008 17:17:57 +0100 Subject: rt2x00: Optimize configuration handling Implement latest changed from mac80211 configuration handling to optmize configuration handling in rt2x00. * Remove set_retry_limit callback function, handled through config() * Move config_antenna to its own callback function, it isn't handled by mac80211 anymore * Use IEEE80211_CONF_CHANGED_* flags and remove manual checks * Removed deprecated short slot setting through config() and put it in config_erp() through which mac80211 now configures it * Remove config_phymode() and move contents to config_erp() since it only managed the basic rates which is now determined by mac80211 through config_erp(). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 167 ++++++++++----------- drivers/net/wireless/rt2x00/rt2500pci.c | 206 +++++++++++++------------ drivers/net/wireless/rt2x00/rt2500usb.c | 110 +++++++------- drivers/net/wireless/rt2x00/rt2x00.h | 35 ++--- drivers/net/wireless/rt2x00/rt2x00config.c | 164 +++----------------- drivers/net/wireless/rt2x00/rt2x00lib.h | 3 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 11 +- drivers/net/wireless/rt2x00/rt61pci.c | 231 ++++++++++++++--------------- drivers/net/wireless/rt2x00/rt73usb.c | 216 +++++++++++++-------------- 9 files changed, 488 insertions(+), 655 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 1adca7a..e1891eb 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -396,12 +396,74 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); + rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, erp->difs); + rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); } -static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) +static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { - rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); + u8 r1; + u8 r4; + + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + + rt2400pci_bbp_read(rt2x00dev, 4, &r4); + rt2400pci_bbp_read(rt2x00dev, 1, &r1); + + /* + * Configure the TX antenna. + */ + switch (ant->tx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + } + + rt2400pci_bbp_write(rt2x00dev, 4, r4); + rt2400pci_bbp_write(rt2x00dev, 1, r1); } static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -460,56 +522,17 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower)); } -static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { - u8 r1; - u8 r4; - - /* - * We should never come here because rt2x00lib is supposed - * to catch this and send us the correct antenna explicitely. - */ - BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || - ant->tx == ANTENNA_SW_DIVERSITY); - - rt2400pci_bbp_read(rt2x00dev, 4, &r4); - rt2400pci_bbp_read(rt2x00dev, 1, &r1); - - /* - * Configure the TX antenna. - */ - switch (ant->tx) { - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); - break; - case ANTENNA_A: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); - break; - } - - /* - * Configure the RX antenna. - */ - switch (ant->rx) { - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - break; - case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); - break; - } + u32 reg; - rt2400pci_bbp_write(rt2x00dev, 4, r4); - rt2400pci_bbp_write(rt2x00dev, 1, r1); + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); } static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, @@ -517,20 +540,6 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); - rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); - rt2x00pci_register_write(rt2x00dev, CSR18, reg); - - rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); - rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, CSR19, reg); - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); @@ -548,16 +557,14 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2400pci_config_channel(rt2x00dev, &libconf->rf); - if (flags & CONFIG_UPDATE_TXPOWER) + if (flags & IEEE80211_CONF_CHANGE_POWER) rt2400pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2400pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2400pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2400pci_config_duration(rt2x00dev, libconf); } @@ -1502,20 +1509,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); - rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - return 0; -} - static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -1601,8 +1594,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .config_filter = rt2400pci_config_filter, .config_intf = rt2400pci_config_intf, .config_erp = rt2400pci_config_erp, + .config_ant = rt2400pci_config_ant, .config = rt2400pci_config, - .set_retry_limit = rt2400pci_set_retry_limit, }; static const struct data_queue_desc rt2400pci_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 85b0387..66a94c2 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -402,12 +402,94 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); + rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, erp->difs); + rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); } -static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) +static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { - rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); + u32 reg; + u8 r14; + u8 r2; + + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + + rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); + rt2500pci_bbp_read(rt2x00dev, 14, &r14); + rt2500pci_bbp_read(rt2x00dev, 2, &r2); + + /* + * Configure the TX antenna. + */ + switch (ant->tx) { + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field32(®, BBPCSR1_CCK, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); + rt2x00_set_field32(®, BBPCSR1_OFDM, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); + } + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); + rt2500pci_bbp_write(rt2x00dev, 14, r14); + rt2500pci_bbp_write(rt2x00dev, 2, r2); } static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -489,76 +571,17 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2500pci_rf_write(rt2x00dev, 3, rf3); } -static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { u32 reg; - u8 r14; - u8 r2; - /* - * We should never come here because rt2x00lib is supposed - * to catch this and send us the correct antenna explicitely. - */ - BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || - ant->tx == ANTENNA_SW_DIVERSITY); - - rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); - rt2500pci_bbp_read(rt2x00dev, 14, &r14); - rt2500pci_bbp_read(rt2x00dev, 2, &r2); - - /* - * Configure the TX antenna. - */ - switch (ant->tx) { - case ANTENNA_A: - rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); - rt2x00_set_field32(®, BBPCSR1_CCK, 0); - rt2x00_set_field32(®, BBPCSR1_OFDM, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); - rt2x00_set_field32(®, BBPCSR1_CCK, 2); - rt2x00_set_field32(®, BBPCSR1_OFDM, 2); - break; - } - - /* - * Configure the RX antenna. - */ - switch (ant->rx) { - case ANTENNA_A: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); - break; - } - - /* - * RT2525E and RT5222 need to flip TX I/Q - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || - rt2x00_rf(&rt2x00dev->chip, RF5222)) { - rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); - rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); - rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); - - /* - * RT2525E does not need RX I/Q Flip. - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) - rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); - } else { - rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); - rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); - } - - rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); - rt2500pci_bbp_write(rt2x00dev, 14, r14); - rt2500pci_bbp_write(rt2x00dev, 2, r2); + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); } static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, @@ -566,20 +589,6 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); - rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); - rt2x00pci_register_write(rt2x00dev, CSR18, reg); - - rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); - rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, CSR19, reg); - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); @@ -597,17 +606,16 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2500pci_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2500pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2500pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2500pci_config_duration(rt2x00dev, libconf); } @@ -1827,20 +1835,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); - rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - return 0; -} - static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1901,8 +1895,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .config_filter = rt2500pci_config_filter, .config_intf = rt2500pci_config_intf, .config_erp = rt2500pci_config_erp, + .config_ant = rt2500pci_config_ant, .config = rt2500pci_config, - .set_retry_limit = rt2500pci_set_retry_limit, }; static const struct data_queue_desc rt2500pci_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d19bee4..19970de 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -423,57 +423,16 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); -} - -static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask); -} - -static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - /* - * Set TXpower. - */ - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - - /* - * For RT2525E we should first set the channel to half band higher. - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { - static const u32 vals[] = { - 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, - 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, - 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, - 0x00000902, 0x00000906 - }; - rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); - if (rf->rf4) - rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); - } + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); - rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); - rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); - rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); - if (rf->rf4) - rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); -} - -static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - u32 rf3; - - rt2x00_rf_read(rt2x00dev, 3, &rf3); - rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2500usb_rf_write(rt2x00dev, 3, rf3); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); + rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); } -static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { u8 r2; u8 r14; @@ -555,15 +514,52 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6); } +static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + /* + * Set TXpower. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * For RT2525E we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + static const u32 vals[] = { + 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, + 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, + 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, + 0x00000902, 0x00000906 + }; + + rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); + } + + rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500usb_rf_write(rt2x00dev, 3, rf3); +} + static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { u16 reg; - rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time); - rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs); - rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs); - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, libconf->conf->beacon_int * 4); @@ -574,17 +570,14 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2500usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2500usb_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2500usb_config_duration(rt2x00dev, libconf); } @@ -1794,6 +1787,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .config_filter = rt2500usb_config_filter, .config_intf = rt2500usb_config_intf, .config_erp = rt2500usb_config_erp, + .config_ant = rt2500usb_config_ant, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 0887e89..4d983e6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -433,18 +433,6 @@ struct rt2x00lib_conf { struct rf_channel rf; struct channel_info channel; - - struct antenna_setup ant; - - enum ieee80211_band band; - - u32 basic_rates; - u32 slot_time; - - short sifs; - short pifs; - short difs; - short eifs; }; /* @@ -456,6 +444,15 @@ struct rt2x00lib_erp { int ack_timeout; int ack_consume_time; + + u64 basic_rates; + + int slot_time; + + short sifs; + short pifs; + short difs; + short eifs; }; /* @@ -589,19 +586,11 @@ struct rt2x00lib_ops { void (*config_erp) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp); + void (*config_ant) (struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant); void (*config) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, - const unsigned int flags); -#define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) -#define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) -#define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) -#define CONFIG_UPDATE_ANTENNA ( 1 << 4 ) -#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 ) -#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 ) -#define CONFIG_UPDATE_ALL 0xffff - - int (*set_retry_limit) (struct ieee80211_hw *hw, - u32 short_limit, u32 long_limit); + const unsigned int changed_flags); }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 7910147..3e4eee3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -86,13 +86,14 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.short_preamble = bss_conf->use_short_preamble; erp.cts_protection = bss_conf->use_cts_prot; - erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); + erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME; + erp.sifs = SIFS; + erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS; + erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; + erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) - erp.ack_timeout += SHORT_DIFS; - else - erp.ack_timeout += DIFS; + erp.ack_timeout = PLCP + erp.difs + get_duration(ACK_SIZE, 10); + erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); if (bss_conf->use_short_preamble) { erp.ack_timeout += SHORT_PREAMBLE; @@ -102,16 +103,18 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.ack_consume_time += PREAMBLE; } + erp.basic_rates = bss_conf->basic_rates; + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, enum antenna rx, enum antenna tx) { - struct rt2x00lib_conf libconf; + struct antenna_setup ant; - libconf.ant.rx = rx; - libconf.ant.tx = tx; + ant.rx = rx; + ant.tx = tx; if (rx == rt2x00dev->link.ant.active.rx && tx == rt2x00dev->link.ant.active.tx) @@ -129,111 +132,28 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA); + rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); + rt2x00lib_reset_link_tuner(rt2x00dev); rt2x00_reset_link_ant_rssi(&rt2x00dev->link); - rt2x00dev->link.ant.active.rx = libconf.ant.rx; - rt2x00dev->link.ant.active.tx = libconf.ant.tx; + memcpy(&rt2x00dev->link.ant.active, &ant, sizeof(ant)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); } -static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band) -{ - const struct rt2x00_rate *rate; - unsigned int i; - u32 mask = 0; - - for (i = 0; i < band->n_bitrates; i++) { - rate = rt2x00_get_rate(band->bitrates[i].hw_value); - if (rate->flags & DEV_RATE_BASIC) - mask |= rate->ratemask; - } - - return mask; -} - void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, const int force_config) + struct ieee80211_conf *conf, + unsigned int ieee80211_flags) { struct rt2x00lib_conf libconf; - struct ieee80211_supported_band *band; - struct antenna_setup *default_ant = &rt2x00dev->default_ant; - struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; - int flags = 0; - int short_slot_time; - - /* - * In some situations we want to force all configurations - * to be reloaded (When resuming for instance). - */ - if (force_config) { - flags = CONFIG_UPDATE_ALL; - goto config; - } - - /* - * Check which configuration options have been - * updated and should be send to the device. - */ - if (rt2x00dev->rx_status.band != conf->channel->band) - flags |= CONFIG_UPDATE_PHYMODE; - if (rt2x00dev->rx_status.freq != conf->channel->center_freq) - flags |= CONFIG_UPDATE_CHANNEL; - if (rt2x00dev->tx_power != conf->power_level) - flags |= CONFIG_UPDATE_TXPOWER; - - /* - * Determining changes in the antenna setups request several checks: - * antenna_sel_{r,t}x = 0 - * -> Does active_{r,t}x match default_{r,t}x - * -> Is default_{r,t}x SW_DIVERSITY - * antenna_sel_{r,t}x = 1/2 - * -> Does active_{r,t}x match antenna_sel_{r,t}x - * The reason for not updating the antenna while SW diversity - * should be used is simple: Software diversity means that - * we should switch between the antenna's based on the - * quality. This means that the current antenna is good enough - * to work with untill the link tuner decides that an antenna - * switch should be performed. - */ - if (default_ant->rx != ANTENNA_SW_DIVERSITY && - default_ant->rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (active_ant->rx == ANTENNA_SW_DIVERSITY) - flags |= CONFIG_UPDATE_ANTENNA; - - if (default_ant->tx != ANTENNA_SW_DIVERSITY && - default_ant->tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (active_ant->tx == ANTENNA_SW_DIVERSITY) - flags |= CONFIG_UPDATE_ANTENNA; - /* - * The following configuration options are never - * stored anywhere and will always be updated. - */ - flags |= CONFIG_UPDATE_SLOT_TIME; - flags |= CONFIG_UPDATE_BEACON_INT; - - /* - * We have determined what options should be updated, - * now precalculate device configuration values depending - * on what configuration options need to be updated. - */ -config: memset(&libconf, 0, sizeof(libconf)); - if (flags & CONFIG_UPDATE_PHYMODE) { - band = &rt2x00dev->bands[conf->channel->band]; - - libconf.band = conf->channel->band; - libconf.basic_rates = rt2x00lib_get_basic_rates(band); - } + libconf.conf = conf; - if (flags & CONFIG_UPDATE_CHANNEL) { + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); @@ -243,57 +163,21 @@ config: sizeof(libconf.channel)); } - if (flags & CONFIG_UPDATE_ANTENNA) { - if (default_ant->rx != ANTENNA_SW_DIVERSITY) - libconf.ant.rx = default_ant->rx; - else if (active_ant->rx == ANTENNA_SW_DIVERSITY) - libconf.ant.rx = ANTENNA_B; - else - libconf.ant.rx = active_ant->rx; - - if (default_ant->tx != ANTENNA_SW_DIVERSITY) - libconf.ant.tx = default_ant->tx; - else if (active_ant->tx == ANTENNA_SW_DIVERSITY) - libconf.ant.tx = ANTENNA_B; - else - libconf.ant.tx = active_ant->tx; - } - - if (flags & CONFIG_UPDATE_SLOT_TIME) { - short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - - libconf.slot_time = - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME; - libconf.sifs = SIFS; - libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; - libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; - libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS; - } - - libconf.conf = conf; - /* * Start configuration. */ - rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags); + rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags); /* * Some configuration changes affect the link quality * which means we need to reset the link tuner. */ - if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00lib_reset_link_tuner(rt2x00dev); - if (flags & CONFIG_UPDATE_PHYMODE) { - rt2x00dev->curr_band = conf->channel->band; - rt2x00dev->rx_status.band = conf->channel->band; - } - - rt2x00dev->rx_status.freq = conf->channel->center_freq; + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->tx_power = conf->power_level; - if (flags & CONFIG_UPDATE_ANTENNA) { - rt2x00dev->link.ant.active.rx = libconf.ant.rx; - rt2x00dev->link.ant.active.tx = libconf.ant.tx; - } + rt2x00dev->rx_status.band = conf->channel->band; + rt2x00dev->rx_status.freq = conf->channel->center_freq; } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 797eb61..9f214f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -96,7 +96,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, enum antenna rx, enum antenna tx); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, const int force_config); + struct ieee80211_conf *conf, + const unsigned int changed_flags); /** * DOC: Queue handlers diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index b32d59e..3a3b5ad 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -349,15 +349,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - rt2x00dev->ops->lib->set_retry_limit(hw, - conf->short_frame_max_tx_count, - conf->long_frame_max_tx_count); - } - changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; - if (!changed) - return 0; - /* * Only change device state when the radio is enabled. It does not * matter what parameters we have configured when the radio is disabled @@ -379,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) * When we've just turned on the radio, we want to reprogram * everything to ensure a consistent state */ - rt2x00lib_config(rt2x00dev, conf, !radio_on); + rt2x00lib_config(rt2x00dev, conf, changed); /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 921dcd5..bd4a6e1 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -643,95 +643,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); -} - - -static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain = 0; - - if (libconf->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); -} - -static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - u8 r3; - u8 r94; - u8 smart; - - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); - - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); - rt61pci_bbp_write(rt2x00dev, 3, r3); - - r94 = 6; - if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) - r94 += txpower - MAX_TXPOWER; - else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) - r94 += txpower; - rt61pci_bbp_write(rt2x00dev, 94, r94); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - msleep(1); -} -static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - struct rf_channel rf; + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); - rt61pci_config_channel(rt2x00dev, &rf, txpower); + rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -906,8 +829,8 @@ static const struct antenna_sel antenna_sel_bg[] = { { 98, { 0x48, 0x48 } }, }; -static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; @@ -954,20 +877,105 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, } } -static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, +static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt61pci_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt61pci_bbp_write(rt2x00dev, 94, r94); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + msleep(1); +} + +static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt61pci_config_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { u32 reg; - rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); +} - rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); - rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); +static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); @@ -990,16 +998,15 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, /* Always recalculate LNA gain before changing configuration */ rt61pci_config_lna_gain(rt2x00dev, libconf); - if (flags & CONFIG_UPDATE_PHYMODE) - rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt61pci_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt61pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt61pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt61pci_config_duration(rt2x00dev, libconf); } @@ -2628,20 +2635,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); - rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); - - return 0; -} - static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { @@ -2755,8 +2748,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .config_filter = rt61pci_config_filter, .config_intf = rt61pci_config_intf, .config_erp = rt61pci_config_erp, + .config_ant = rt61pci_config_ant, .config = rt61pci_config, - .set_retry_limit = rt61pci_set_retry_limit, }; static const struct data_queue_desc rt61pci_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 69a4931..5be49ed 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -669,87 +669,18 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); -} - -static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain = 0; - - if (libconf->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); - } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); -} - -static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - u8 r3; - u8 r94; - u8 smart; - - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); - - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); - rt73usb_bbp_write(rt2x00dev, 3, r3); - - r94 = 6; - if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) - r94 += txpower - MAX_TXPOWER; - else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) - r94 += txpower; - rt73usb_bbp_write(rt2x00dev, 94, r94); - - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); - - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(10); -} - -static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - struct rf_channel rf; + rt73usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); - rt73usb_config_channel(rt2x00dev, &rf, txpower); + rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); + rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -869,8 +800,8 @@ static const struct antenna_sel antenna_sel_bg[] = { { 98, { 0x48, 0x48 } }, }; -static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; @@ -912,20 +843,98 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt73usb_config_antenna_2x(rt2x00dev, ant); } -static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, +static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { + u16 eeprom; + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt73usb_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt73usb_bbp_write(rt2x00dev, 94, r94); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(10); +} + +static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt73usb_config_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ u32 reg; - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); +} - rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); - rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); - rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); +static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); @@ -948,16 +957,15 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, /* Always recalculate LNA gain before changing configuration */ rt73usb_config_lna_gain(rt2x00dev, libconf); - if (flags & CONFIG_UPDATE_PHYMODE) - rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt73usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt73usb_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt73usb_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt73usb_config_duration(rt2x00dev, libconf); } @@ -2209,20 +2217,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); - rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); - - return 0; -} - static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { @@ -2345,8 +2339,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .config_filter = rt73usb_config_filter, .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, + .config_ant = rt73usb_config_ant, .config = rt73usb_config, - .set_retry_limit = rt73usb_set_retry_limit, }; static const struct data_queue_desc rt73usb_queue_rx = { -- cgit v1.1 From c3fd7b41cae2fa213858d6501e6065f24097c0a8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 29 Oct 2008 17:18:22 +0100 Subject: rt2x00: Remove ieee80211_bss_conf from rt2x00_intf We can safely remove ieee80211_bss_conf from rt2x00_intf, it is provided by mac80211 in ieee80211_vif as well. (rt2x00_intf is the drv_priv field of ieee80211_vif). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 7 ------- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4d983e6..ca1f9fe 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -348,13 +348,6 @@ struct rt2x00_intf { spinlock_t lock; /* - * BSS configuration. Copied from the structure - * passed to us through the bss_info_changed() - * callback funtion. - */ - struct ieee80211_bss_conf conf; - - /* * MAC of the device. */ u8 mac[ETH_ALEN]; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1feab8..c42e4fd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -417,7 +417,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, */ spin_lock(&intf->lock); - memcpy(&conf, &intf->conf, sizeof(conf)); + memcpy(&conf, &vif->bss_conf, sizeof(conf)); delayed_flags = intf->delayed_flags; intf->delayed_flags = 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3a3b5ad..8fc2315 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -634,7 +634,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } spin_lock(&intf->lock); - memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); if (delayed) { intf->delayed_flags |= delayed; schedule_work(&rt2x00dev->intf_work); -- cgit v1.1 From 3514a441265c6788d85e8222dcca10cd66433123 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 29 Oct 2008 17:18:46 +0100 Subject: rt2x00: Improve interface_modes initialization All operating modes which require beaconing should depend on the availability of beacon entries from the hardware. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index c42e4fd..477a944 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1056,10 +1056,16 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); - rt2x00dev->hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + /* + * Determine which operating modes are supported, all modes + * which require beaconing, depend on the availability of + * beacon entries. + */ + rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + if (rt2x00dev->ops->bcn->entry_num > 0) + rt2x00dev->hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); /* * Let the driver probe the device to detect the capabilities. -- cgit v1.1 From 9344e86e577df483475845096dba07f2deb11ce3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 29 Oct 2008 17:19:29 +0100 Subject: rt2x00: Release rt2x00 2.2.2 Version bump. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ca1f9fe..f85eedb 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.1" +#define DRV_VERSION "2.2.2" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.1 From 2f20596b50ee964715f9ad44d848802f0baba5d8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:52:07 -0700 Subject: rtl8187: Remove large delays The rtl8187 driver contains 3 sleep statements that are longer than a second. Testing has shown no bad effects when they are removed. Signed-off-by: Larry Finger Tested-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 2 +- drivers/net/wireless/rtl8187_rtl8225.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 6260ed8..b4927d0 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -669,7 +669,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - msleep(1100); + msleep(100); priv->rf->init(dev); diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index b999f87..85965e0 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -862,10 +862,8 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) rtl8225_write(dev, 0x3, 0x080); msleep(1); rtl8225_write(dev, 0x5, 0x004); msleep(1); rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - msleep(3000); rtl8225_write(dev, 0x2, 0xC4D); msleep(1); - msleep(2000); rtl8225_write(dev, 0x2, 0x44D); msleep(1); rtl8225_write(dev, 0x0, 0x2BF); msleep(1); -- cgit v1.1 From 35cc988a5620cea03fd97e96c530e1f259ef913b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:52:39 -0700 Subject: rtl8187: Remove OFDM delays Routine rtl8225_write_phy_ofdm() calls rtl8225_write_phy(), which concludes with a sleep of 1 msec; therefore a call to rtl8225_write_phy_ofdm() immediately followed by an msleep(1) is not needed. Signed-off-by: Larry Finger Tested-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_rtl8225.c | 168 ++++++++++++++++----------------- 1 file changed, 82 insertions(+), 86 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 85965e0..7ae7b84 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -375,50 +375,48 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); } msleep(1); - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); @@ -459,7 +457,7 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) /* RX antenna default to A */ rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ msleep(1); @@ -736,53 +734,51 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); } msleep(1); - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed? - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x07); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x17); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x00); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]); rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]); @@ -823,7 +819,7 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) /* RX antenna default to A */ rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ msleep(1); @@ -889,10 +885,10 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); - rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x97, 0x46); + rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); + rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); + rtl8225_write_phy_cck(dev, 0xc1, 0x88); } static void rtl8225_rf_stop(struct ieee80211_hw *dev) -- cgit v1.1 From a3d67bc2e9e25f09151971192946fe3b68543649 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:52:58 -0700 Subject: rtl8187: Remove CCK delays Routine rtl8225_write_phy_cck() calls rtl8225_write_phy(), which concludes with a sleep of 1 msec; therefore a call to rtl8225_write_phy_cck() immediately followed by an msleep(1) is not needed. Signed-off-by: Larry Finger Tested-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_rtl8225.c | 92 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 7ae7b84..9ecac76 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -423,40 +423,40 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); rtl8225_write_phy_cck(dev, 0x13, 0xd0); rtl8225_write_phy_cck(dev, 0x19, 0x00); rtl8225_write_phy_cck(dev, 0x1a, 0xa0); rtl8225_write_phy_cck(dev, 0x1b, 0x08); rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); + rtl8225_write_phy_cck(dev, 0x47, 0x15); + rtl8225_write_phy_cck(dev, 0x48, 0x10); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); rtl8225_rf_set_tx_power(dev, 1); /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ @@ -785,40 +785,40 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]); rtl8225_write_phy_ofdm(dev, 0x21, 0x37); - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); rtl8225_write_phy_cck(dev, 0x13, 0xd0); rtl8225_write_phy_cck(dev, 0x19, 0x00); rtl8225_write_phy_cck(dev, 0x1a, 0xa0); rtl8225_write_phy_cck(dev, 0x1b, 0x08); rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x36); + rtl8225_write_phy_cck(dev, 0x45, 0x35); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); + rtl8225_write_phy_cck(dev, 0x47, 0x25); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); + rtl8225_write_phy_cck(dev, 0x49, 0x12); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1); rtl8225z2_rf_set_tx_power(dev, 1); /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ -- cgit v1.1 From 946d1c22644a5de07efc1c847fb64bb0cf8f82f2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:54:13 -0700 Subject: rtl8187: Remove msleep calls after calls to rtl8225_write Routine rtl8225_write() calls either rtl8225_write_bitbang() or rtl8225_write_8051(), both of which end with an msleep() command. As a result, a rtl8225_write() immediately followed by an msleep() is not needed. Signed-off-by: Larry Finger Tested-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_rtl8225.c | 117 +++++++++++++++++---------------- 1 file changed, 59 insertions(+), 58 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 9ecac76..053eb220a1 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -333,21 +333,21 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x067); msleep(1); - rtl8225_write(dev, 0x1, 0xFE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x486); msleep(1); - rtl8225_write(dev, 0x5, 0xBC0); msleep(1); - rtl8225_write(dev, 0x6, 0xAE6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x01F); msleep(1); - rtl8225_write(dev, 0x9, 0x334); msleep(1); - rtl8225_write(dev, 0xA, 0xFD4); msleep(1); - rtl8225_write(dev, 0xB, 0x391); msleep(1); - rtl8225_write(dev, 0xC, 0x050); msleep(1); - rtl8225_write(dev, 0xD, 0x6DB); msleep(1); - rtl8225_write(dev, 0xE, 0x029); msleep(1); + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x486); + rtl8225_write(dev, 0x5, 0xBC0); + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x01F); + rtl8225_write(dev, 0x9, 0x334); + rtl8225_write(dev, 0xA, 0xFD4); + rtl8225_write(dev, 0xB, 0x391); + rtl8225_write(dev, 0xC, 0x050); + rtl8225_write(dev, 0xD, 0x6DB); + rtl8225_write(dev, 0xE, 0x029); rtl8225_write(dev, 0xF, 0x914); msleep(100); rtl8225_write(dev, 0x2, 0xC4D); msleep(200); @@ -685,22 +685,23 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x2BF); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(100); + rtl8225_write(dev, 0x0, 0x2BF); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + msleep(100); rtl8225_write(dev, 0x0, 0x1B7); @@ -831,38 +832,38 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(1); - - rtl8225_write(dev, 0x0, 0x1B7); msleep(1); + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + + rtl8225_write(dev, 0x0, 0x1B7); for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); msleep(1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1); + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); } - rtl8225_write(dev, 0x3, 0x080); msleep(1); - rtl8225_write(dev, 0x5, 0x004); msleep(1); - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x2, 0xC4D); msleep(1); + rtl8225_write(dev, 0x2, 0xC4D); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x0, 0x2BF); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x0, 0x2BF); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07); @@ -896,7 +897,7 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev) u8 reg; struct rtl8187_priv *priv = dev->priv; - rtl8225_write(dev, 0x4, 0x1f); msleep(1); + rtl8225_write(dev, 0x4, 0x1f); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); -- cgit v1.1 From 94d4fe9824e5c62240f3ae2a33b2dd5a8a32a01b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:54:30 -0700 Subject: rtl8187: Remove primitive write delays Each of the primary write routines, rtl8187_write_phy(), rtl8225_write_bitbang(), and rtl8225_write_8051() all conclude with an msleep() command. Testing shows that these are not needed. Signed-off-by: Larry Finger Tested-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 2 -- drivers/net/wireless/rtl8187_rtl8225.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index b4927d0..892ad2d 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -152,8 +152,6 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); - - msleep(1); } static void rtl8187_tx_cb(struct urb *urb) diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 053eb220a1..38333b1 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -64,7 +64,6 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - msleep(2); } static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) @@ -98,7 +97,6 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - msleep(2); } static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) -- cgit v1.1 From 74508b29c51158e5b45bca13e702c68ef5c3b641 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:54:49 -0700 Subject: rtl8187: Reduce channel switch delay The latest vendor driver (rtl8187B_linux_26.1036.0708.2008) has a 10 msec delay after the call to set a new channel, but not before. Signed-off-by: Larry Finger Tested-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 892ad2d..66add5e 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -870,7 +870,6 @@ static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) */ rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg | RTL818X_TX_CONF_LOOPBACK_MAC); - msleep(10); priv->rf->set_chan(dev, conf); msleep(10); rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); -- cgit v1.1 From f161796700ed89b07dff2ad4ba3a932bc721af7e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 31 Oct 2008 16:45:15 -0400 Subject: ath9k: correct warning about unintialized variable 'tid' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/ath9k/xmit.c: In function ‘ath_tx_start’: drivers/net/wireless/ath9k/xmit.c:1858: warning: ‘tid’ may be used uninitialized in this function Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index fe386b6..8937728 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1859,11 +1859,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct ath_hal *ah = sc->sc_ah; int frm_type; - if (tx_info->control.sta) { - an = (struct ath_node *)tx_info->control.sta->drv_priv; - tid = ATH_AN_2_TID(an, bf->bf_tidno); - } - frm_type = get_hw_packet_type(skb); INIT_LIST_HEAD(&bf_head); @@ -1890,7 +1885,11 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, spin_lock_bh(&txctl->txq->axq_lock); - if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) { + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && + tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + if (ath_aggr_query(sc, an, bf->bf_tidno)) { /* * Try aggregation if it's a unicast data frame -- cgit v1.1 From 743b97caf98036ec8ee4bfc6fc6f85ad94e04783 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 29 Oct 2008 19:41:03 +0100 Subject: rt2x00: Remove debugfs CSR access wrappers Move calculation of CSR register offset into rt2x00debug.c and remove the wrapper functions from each individual driver. (Except rt2500usb, which still needs to wrap for the different value type argument). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 23 +++++++---------------- drivers/net/wireless/rt2x00/rt2400pci.h | 2 ++ drivers/net/wireless/rt2x00/rt2500pci.c | 23 +++++++---------------- drivers/net/wireless/rt2x00/rt2500pci.h | 2 ++ drivers/net/wireless/rt2x00/rt2500usb.c | 25 +++++++++++++++---------- drivers/net/wireless/rt2x00/rt2500usb.h | 2 ++ drivers/net/wireless/rt2x00/rt2x00debug.c | 22 ++++++++++++++++------ drivers/net/wireless/rt2x00/rt2x00debug.h | 13 +++++++++++++ drivers/net/wireless/rt2x00/rt2x00pci.h | 8 ++++---- drivers/net/wireless/rt2x00/rt61pci.c | 23 +++++++---------------- drivers/net/wireless/rt2x00/rt61pci.h | 2 ++ drivers/net/wireless/rt2x00/rt73usb.c | 23 +++++++---------------- drivers/net/wireless/rt2x00/rt73usb.h | 2 ++ 13 files changed, 86 insertions(+), 84 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index e1891eb..42bd38a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -188,43 +188,34 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt2400pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2400pci_read_csr, - .write = rt2400pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2400pci_bbp_read, .write = rt2400pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2400pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index bbff381..9aefda4 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -46,7 +46,9 @@ #define CSR_REG_SIZE 0x014c #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0020 +#define RF_BASE 0x0000 #define RF_SIZE 0x0010 /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 66a94c2..928452f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -188,43 +188,34 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt2500pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2500pci_read_csr, - .write = rt2500pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2500pci_bbp_read, .write = rt2500pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2500pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 8c26bef..e135247 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -57,7 +57,9 @@ #define CSR_REG_SIZE 0x0174 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0200 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0040 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 19970de..639d5a2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -245,43 +245,48 @@ rf_write: } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) ) - -static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) +static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) { - rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data); + rt2500usb_register_read(rt2x00dev, offset, (u16 *)value); } -static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) +static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) { - rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data); + rt2500usb_register_write(rt2x00dev, offset, value); } static const struct rt2x00debug rt2500usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2500usb_read_csr, - .write = rt2500usb_write_csr, + .read = _rt2500usb_register_read, + .write = _rt2500usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u16), .word_count = CSR_REG_SIZE / sizeof(u16), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2500usb_bbp_read, .write = rt2500usb_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2500usb_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 89e5ed2..dbb5d689 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -57,7 +57,9 @@ #define CSR_REG_SIZE 0x0100 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x006a +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0060 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index a31418a7..54dd100 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -424,16 +424,21 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ + unsigned int index = intf->offset_##__name; \ __type value; \ \ if (*offset) \ return 0; \ \ - if (intf->offset_##__name >= debug->__name.word_count) \ + if (index >= debug->__name.word_count) \ return -EINVAL; \ \ - debug->__name.read(intf->rt2x00dev, \ - intf->offset_##__name, &value); \ + if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ + index *= debug->__name.word_size; \ + \ + index += debug->__name.word_base; \ + \ + debug->__name.read(intf->rt2x00dev, index, &value); \ \ size = sprintf(line, __format, value); \ \ @@ -454,12 +459,13 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ + unsigned int index = intf->offset_##__name; \ __type value; \ \ if (*offset) \ return 0; \ \ - if (intf->offset_##__name >= debug->__name.word_count) \ + if (index >= debug->__name.word_count) \ return -EINVAL; \ \ if (copy_from_user(line, buf, length)) \ @@ -468,8 +474,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ size = strlen(line); \ value = simple_strtoul(line, NULL, 0); \ \ - debug->__name.write(intf->rt2x00dev, \ - intf->offset_##__name, value); \ + if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ + index *= debug->__name.word_size; \ + \ + index += debug->__name.word_base; \ + \ + debug->__name.write(intf->rt2x00dev, index, value); \ \ *offset += size; \ return size; \ diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index c4ce895..a92104d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -28,6 +28,16 @@ struct rt2x00_dev; +/** + * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry + * + * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset + * as argument when using the callback function read()/write() + */ +enum rt2x00debugfs_entry_flags { + RT2X00DEBUGFS_OFFSET = (1 << 0), +}; + #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ struct reg##__name { \ void (*read)(struct rt2x00_dev *rt2x00dev, \ @@ -35,6 +45,9 @@ struct reg##__name { \ void (*write)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type data); \ \ + unsigned int flags; \ + \ + unsigned int word_base; \ unsigned int word_size; \ unsigned int word_count; \ } __name diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 80bf97c..a83f45f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -58,7 +58,7 @@ * Register access. */ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, u32 *value) { *value = readl(rt2x00dev->csr.base + offset); @@ -66,14 +66,14 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, void *value, const u16 length) { memcpy_fromio(value, rt2x00dev->csr.base + offset, length); } static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, u32 value) { writel(value, rt2x00dev->csr.base + offset); @@ -81,7 +81,7 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, const void *value, const u16 length) { memcpy_toio(rt2x00dev->csr.base + offset, value, length); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index bd4a6e1..3f27279 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -228,43 +228,34 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt61pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt61pci_read_csr, - .write = rt61pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt61pci_bbp_read, .write = rt61pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt61pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 8ec1451..65fe333 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -48,7 +48,9 @@ #define CSR_REG_SIZE 0x04b0 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0080 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5be49ed..767e3c9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -249,43 +249,34 @@ rf_write: } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt73usb_read_csr, - .write = rt73usb_write_csr, + .read = rt73usb_register_read, + .write = rt73usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt73usb_bbp_read, .write = rt73usb_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt73usb_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 868386c..46e1405 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -48,7 +48,9 @@ #define CSR_REG_SIZE 0x04b0 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0080 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* -- cgit v1.1 From c7ab5ef9bcd281135c21b4732c9be779585181be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Oct 2008 20:02:12 +0100 Subject: b43: implement short slot and basic rate handling This implements proper short slot handling and adds code to program the hardware for the correct response rates derived from the basic rate set for the current BSS. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 1 - drivers/net/wireless/b43/main.c | 111 +++++++++++++++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 427b820..a53c378 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -718,7 +718,6 @@ struct b43_wldev { bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ - bool short_slot; /* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9d1768d..ba7a5ab 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) static void b43_short_slot_timing_enable(struct b43_wldev *dev) { b43_set_slot_time(dev, 9); - dev->short_slot = 1; } static void b43_short_slot_timing_disable(struct b43_wldev *dev) { b43_set_slot_time(dev, 20); - dev->short_slot = 0; } /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. @@ -3361,16 +3359,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (conf->channel->hw_value != phy->channel) b43_switch_channel(dev, conf->channel->hw_value); - /* Enable/Disable ShortSlot timing. */ - if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != - dev->short_slot) { - B43_WARN_ON(phy->type != B43_PHYTYPE_G); - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) - b43_short_slot_timing_enable(dev); - else - b43_short_slot_timing_disable(dev); - } - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); /* Adjust the desired TX power level. */ @@ -3421,6 +3409,104 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) return err; } +static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates) +{ + struct ieee80211_supported_band *sband = + dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)]; + struct ieee80211_rate *rate; + int i; + u16 basic, direct, offset, basic_offset, rateptr; + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + + if (b43_is_cck_rate(rate->hw_value)) { + direct = B43_SHM_SH_CCKDIRECT; + basic = B43_SHM_SH_CCKBASIC; + offset = b43_plcp_get_ratecode_cck(rate->hw_value); + offset &= 0xF; + } else { + direct = B43_SHM_SH_OFDMDIRECT; + basic = B43_SHM_SH_OFDMBASIC; + offset = b43_plcp_get_ratecode_ofdm(rate->hw_value); + offset &= 0xF; + } + + rate = ieee80211_get_response_rate(sband, brates, rate->bitrate); + + if (b43_is_cck_rate(rate->hw_value)) { + basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value); + basic_offset &= 0xF; + } else { + basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value); + basic_offset &= 0xF; + } + + /* + * Get the pointer that we need to point to + * from the direct map + */ + rateptr = b43_shm_read16(dev, B43_SHM_SHARED, + direct + 2 * basic_offset); + /* and write it to the basic map */ + b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset, + rateptr); + } +} + +static void b43_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + struct b43_phy *phy; + unsigned long flags; + u32 savedirqs; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43_status(dev) < B43_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_synchronize_irq(dev); + + b43_mac_suspend(dev); + + if (changed & BSS_CHANGED_BASIC_RATES) + b43_update_basic_rates(dev, conf->basic_rates); + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + b43_short_slot_timing_enable(dev); + else + b43_short_slot_timing_disable(dev); + } + + b43_mac_enable(dev); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_interrupt_enable(dev, savedirqs); + /* XXX: why? */ + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); + out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return; +} + static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) @@ -4210,6 +4296,7 @@ static const struct ieee80211_ops b43_hw_ops = { .add_interface = b43_op_add_interface, .remove_interface = b43_op_remove_interface, .config = b43_op_config, + .bss_info_changed = b43_op_bss_info_changed, .config_interface = b43_op_config_interface, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, -- cgit v1.1 From 9c80c50211d638555bc4b160d9ccd348e98eedad Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 29 Oct 2008 14:05:43 -0700 Subject: iwlwifi: reorganize flow handler bitology This patch cleans up FH bits and adds missing register values that will be used later in TX initialization rewrite Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++--- drivers/net/wireless/iwlwifi/iwl-fh.h | 52 ++++++++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 +-- 3 files changed, 35 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 4348c7d..1608b28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -535,7 +535,7 @@ static int iwl5000_load_section(struct iwl_priv *priv, iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); iwl_release_nic_access(priv); @@ -549,14 +549,13 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv, { int ret = 0; - ret = iwl5000_load_section( - priv, inst_image, RTC_INST_LOWER_BOUND); + ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND); if (ret) return ret; IWL_DEBUG_INFO("INST uCode section being loaded...\n"); ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); + priv->ucode_write_complete, 5 * HZ); if (ret == -ERESTARTSYS) { IWL_ERROR("Could not load the INST uCode section due " "to interrupt\n"); @@ -753,6 +752,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { int ac = iwl5000_default_queue_to_tx_fifo[i]; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index f2688d5..97e2cf4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -318,34 +318,40 @@ #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) +#define FH49_TCSR_CHNL_NUM (7) +#define FH50_TCSR_CHNL_NUM (8) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) +#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4) +#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001) -#define FH_TCSR_CHNL_NUM (7) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) -#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) -#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4) -#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) + +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) /** * Tx Shared Status Registers (TSSR) @@ -362,7 +368,7 @@ #define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) #define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) -#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) +#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 6008c0c..7d8b4e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -431,8 +431,8 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, /* Enable DMA channel, using same id as for TFD queue */ iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.1 From eb4779c40549f8e0dd45c9a30f279134c9a86131 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 29 Oct 2008 14:05:44 -0700 Subject: iwlwifi: trivial removal of some 4965 remaining from iwl-agn-rs.h This patch removes 4965 prefix from comments and one function in iwl-agn-rs.h Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index ccfafcf..adcbf53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -294,7 +294,7 @@ static inline u8 first_antenna(u8 mask) } -static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) +static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; @@ -304,11 +304,11 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) } /** - * iwl4965_rate_control_register - Register the rate control algorithm callbacks + * iwl_rate_control_register - Register the rate control algorithm callbacks * * Since the rate control algorithm is hardware specific, there is no need * or reason to place it as a stand alone module. The driver can call - * iwl4965_rate_control_register in order to register the rate control callbacks + * iwl_rate_control_register in order to register the rate control callbacks * with the mac80211 subsystem. This should be performed prior to calling * ieee80211_register_hw * @@ -316,7 +316,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) extern int iwlagn_rate_control_register(void); /** - * iwl4965_rate_control_unregister - Unregister the rate control callbacks + * iwl_rate_control_unregister - Unregister the rate control callbacks * * This should be called after calling ieee80211_unregister_hw, but before * the driver is unloaded. diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index bfc009c..0c5f122 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -870,7 +870,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) link_cmd.rs_table[i].rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - r = iwl4965_get_prev_ieee_rate(r); + r = iwl_get_prev_ieee_rate(r); } link_cmd.general_params.single_stream_ant_msk = -- cgit v1.1 From 60294de3af99586bb4a205274d02a7c8b910c0c3 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Wed, 29 Oct 2008 14:05:45 -0700 Subject: iwlwifi: fix priv->iw_mode setting when multiple vif are configured mac80211 supports multiple virtual interfaces for a single device. For example, a managed interface (wlan0) and a monitor interface (mon0) can exist at the same time. Thus priv->iw_mode is not sufficient to track the wireless mode any more. The patch redefines priv->iw_mode as the first interface mode (the same as priv->vif->type if priv->vif != NULL). If another monitor type interface is created later, we don't change priv->iw_mode into monitor. This way, the original interface still works. The patch also requests mac80211 to do reassociation after we change the Rx filter flags. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 15 +++++++-------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 18 +++++++++--------- 2 files changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ad186e1..ae30d495 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -726,13 +726,13 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) +static void iwl4965_connection_init_rx_config(struct iwl_priv *priv, int mode) { const struct iwl_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - switch (priv->iw_mode) { + switch (mode) { case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; @@ -755,7 +755,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + IWL_ERROR("Unsupported interface type %d\n", mode); break; } @@ -803,9 +803,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) static int iwl4965_set_mode(struct iwl_priv *priv, int mode) { - priv->iw_mode = mode; - - iwl4965_connection_init_rx_config(priv); + iwl4965_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl_clear_stations_table(priv); @@ -2056,7 +2054,7 @@ static void iwl_alive_start(struct iwl_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl4965_connection_init_rx_config(priv); + iwl4965_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } @@ -2380,7 +2378,6 @@ static void iwl4965_bg_set_monitor(struct work_struct *work) mutex_lock(&priv->mutex); ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR); - if (ret) { if (ret == -EAGAIN) IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); @@ -2389,6 +2386,7 @@ static void iwl4965_bg_set_monitor(struct work_struct *work) } mutex_unlock(&priv->mutex); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); } static void iwl_bg_run_time_calib_work(struct work_struct *work) @@ -2720,6 +2718,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); priv->vif = conf->vif; + priv->iw_mode = conf->type; spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9a4ffab..119185f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2175,13 +2175,14 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) +static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv, + int mode) { const struct iwl3945_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - switch (priv->iw_mode) { + switch (mode) { case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; @@ -2204,7 +2205,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + IWL_ERROR("Unsupported interface type %d\n", mode); break; } @@ -2227,8 +2228,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) * in some case A channels are all non IBSS * in this case force B/G channel */ - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && - !(is_channel_ibss(ch_info))) + if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); @@ -2261,9 +2261,7 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } } - priv->iw_mode = mode; - - iwl3945_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl3945_clear_stations_table(priv); @@ -5685,7 +5683,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl3945_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } @@ -6001,6 +5999,7 @@ static void iwl3945_bg_set_monitor(struct work_struct *work) IWL_ERROR("iwl3945_set_mode() failed\n"); mutex_unlock(&priv->mutex); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); } #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) @@ -6544,6 +6543,7 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); priv->vif = conf->vif; + priv->iw_mode = conf->type; spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.1 From 5b9f8cd3eea04770ff186b853bbde1741f321866 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 29 Oct 2008 14:05:46 -0700 Subject: iwlwifi: rename generic iwlagn functions that had a HW specific name This patch renames functions that are generic in iwl-agn and had a iwl4965 prefix. Signed-off-by: Emmanuel Grumbach Reviewed-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 402 ++++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +- 4 files changed, 207 insertions(+), 207 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0953a9c..157cad4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2323,7 +2323,7 @@ static struct iwl_lib_ops iwl4965_lib = { .reset = iwl4965_apm_reset, .stop = iwl4965_apm_stop, .config = iwl4965_nic_config, - .set_pwr_src = iwl4965_set_pwr_src, + .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -2342,7 +2342,7 @@ static struct iwl_lib_ops iwl4965_lib = { .query_addr = iwlcore_eeprom_query_addr, }, .send_tx_power = iwl4965_send_tx_power, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .temperature = iwl4965_temperature_calib, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1608b28..31e62a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1474,13 +1474,13 @@ static struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .temperature = iwl5000_temperature, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, .config = iwl5000_nic_config, - .set_pwr_src = iwl4965_set_pwr_src, + .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ae30d495..f3e4cf5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -96,7 +96,7 @@ MODULE_ALIAS("iwl4965"); -static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -108,13 +108,13 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } /** - * iwl4965_check_rxon_cmd - validate RXON structure is valid + * iwl_check_rxon_cmd - validate RXON structure is valid * * NOTE: This is really only useful during development and can eventually * be #ifdef'd out once the driver is stable and folks aren't actively * making changes */ -static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) { int error = 0; int counter = 1; @@ -174,7 +174,7 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) le16_to_cpu(rxon->channel)); if (error) { - IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); + IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); return -1; } return 0; @@ -228,14 +228,14 @@ static int iwl_full_rxon_required(struct iwl_priv *priv) } /** - * iwl4965_commit_rxon - commit staging_rxon to hardware + * iwl_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is committed to the hardware and * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl4965_commit_rxon(struct iwl_priv *priv) +static int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; @@ -252,14 +252,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * 5000, but will not damage 4965 */ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; - ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + ret = iwl_check_rxon_cmd(&priv->staging_rxon); if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } /* If we don't need to send a full RXON, we can use - * iwl4965_rxon_assoc_cmd which is used to reconfigure filter + * iwl_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv)) { ret = iwl_send_rxon_assoc(priv); @@ -304,7 +304,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) le16_to_cpu(priv->staging_rxon.channel), priv->staging_rxon.bssid_addr); - iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); /* Apply the new configuration * RXON unassoc clears the station table in uCode, send it before @@ -374,14 +374,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) return 0; } -void iwl4965_update_chain_flags(struct iwl_priv *priv) +void iwl_update_chain_flags(struct iwl_priv *priv) { iwl_set_rxon_chain(priv); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } -static int iwl4965_send_bt_config(struct iwl_priv *priv) +static int iwl_send_bt_config(struct iwl_priv *priv) { struct iwl4965_bt_cmd bt_cmd = { .flags = 3, @@ -459,7 +459,7 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) +static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) { int i; int rate_mask; @@ -484,7 +484,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) return IWL_RATE_6M_PLCP; } -static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, +static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; @@ -516,7 +516,7 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, return sizeof(*tx_beacon_cmd) + frame_size; } -static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) +static int iwl_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_frame *frame; unsigned int frame_size; @@ -531,9 +531,9 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) return -ENOMEM; } - rate = iwl4965_rate_get_lowest_plcp(priv); + rate = iwl_rate_get_lowest_plcp(priv); - frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); @@ -549,7 +549,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl4965_ht_conf(struct iwl_priv *priv, +static void iwl_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { struct ieee80211_sta_ht_cap *ht_conf; @@ -708,7 +708,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, | RXON_FLG_CCK_MSK); priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; } else { - /* Copied from iwl4965_post_associate() */ + /* Copied from iwl_post_associate() */ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; else @@ -726,7 +726,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl4965_connection_init_rx_config(struct iwl_priv *priv, int mode) +static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) { const struct iwl_channel_info *ch_info; @@ -801,9 +801,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv, int mode) iwl_set_rxon_chain(priv); } -static int iwl4965_set_mode(struct iwl_priv *priv, int mode) +static int iwl_set_mode(struct iwl_priv *priv, int mode) { - iwl4965_connection_init_rx_config(priv, mode); + iwl_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl_clear_stations_table(priv); @@ -819,12 +819,12 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) return -EAGAIN; } - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); return 0; } -static void iwl4965_set_rate(struct iwl_priv *priv) +static void iwl_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; @@ -886,7 +886,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv) * the lower 3 bytes is the time in usec within one beacon interval */ -static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) { u32 quot; u32 rem; @@ -905,7 +905,7 @@ static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) * the same as HW timer counter counting down */ -static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) { u32 base_low = base & BEACON_TIME_MASK_LOW; u32 addon_low = addon & BEACON_TIME_MASK_LOW; @@ -924,7 +924,7 @@ static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) return cpu_to_le32(res); } -static int iwl4965_get_measurement(struct iwl_priv *priv, +static int iwl_get_measurement(struct iwl_priv *priv, struct ieee80211_measurement_params *params, u8 type) { @@ -942,7 +942,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, if (iwl_is_associated(priv)) add_time = - iwl4965_usecs_to_beacons( + iwl_usecs_to_beacons( le64_to_cpu(params->start_time) - priv->last_tsf, le16_to_cpu(priv->rxon_timing.beacon_interval)); @@ -957,7 +957,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, if (iwl_is_associated(priv)) spectrum.start_time = - iwl4965_add_beacon_time(priv->last_beacon_time, + iwl_add_beacon_time(priv->last_beacon_time, add_time, le16_to_cpu(priv->rxon_timing.beacon_interval)); else @@ -1045,7 +1045,7 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl4965_rx_reply_error(struct iwl_priv *priv, +static void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1061,7 +1061,7 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; @@ -1072,7 +1072,7 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) priv->staging_rxon.channel = csa->channel; } -static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT @@ -1090,7 +1090,7 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, #endif } -static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG @@ -1101,7 +1101,7 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, #endif } -static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1111,7 +1111,7 @@ static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } -static void iwl4965_bg_beacon_update(struct work_struct *work) +static void iwl_bg_beacon_update(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, beacon_update); @@ -1133,11 +1133,11 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) priv->ibss_beacon = beacon; mutex_unlock(&priv->mutex); - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); } /** - * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * iwl_bg_statistics_periodic - Timer callback to queue statistics * * This callback is provided in order to send a statistics request. * @@ -1146,7 +1146,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) * was received. We need to ensure we receive the statistics in order * to update the temperature used for calibrating the TXPOWER. */ -static void iwl4965_bg_statistics_periodic(unsigned long data) +static void iwl_bg_statistics_periodic(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; @@ -1156,7 +1156,7 @@ static void iwl4965_bg_statistics_periodic(unsigned long data) iwl_send_statistics_request(priv, CMD_ASYNC); } -static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, +static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG @@ -1180,7 +1180,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, +static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1249,7 +1249,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; unsigned long flags; @@ -1281,7 +1281,7 @@ err: } /** - * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks + * iwl_setup_rx_handlers - Initialize Rx handler callbacks * * Setup the RX handlers for each of the reply types sent from the uCode * to the host. @@ -1292,14 +1292,14 @@ err: static void iwl_setup_rx_handlers(struct iwl_priv *priv) { priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl4965_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; + iwl_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl4965_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif; + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; /* * The same handler is used for both the REPLY to a discrete @@ -1312,7 +1312,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) iwl_setup_rx_scan_handlers(priv); /* status change handler */ - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; @@ -1396,7 +1396,7 @@ void iwl_rx_handle(struct iwl_priv *priv) /* Based on type of command response or notification, * handle those that need handling via function in - * rx_handlers table. See iwl4965_setup_rx_handlers() */ + * rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); @@ -1453,7 +1453,7 @@ void iwl_rx_handle(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) +static void iwl_print_rx_config_cmd(struct iwl_priv *priv) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1473,7 +1473,7 @@ static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) } #endif -static void iwl4965_enable_interrupts(struct iwl_priv *priv) +static void iwl_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR("Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &priv->status); @@ -1488,7 +1488,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) +static inline void iwl_disable_interrupts(struct iwl_priv *priv) { clear_bit(STATUS_INT_ENABLED, &priv->status); @@ -1504,11 +1504,11 @@ static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) /** - * iwl4965_irq_handle_error - called for HW or SW error interrupt from card + * iwl_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl4965_irq_handle_error(struct iwl_priv *priv) +static void iwl_irq_handle_error(struct iwl_priv *priv) { - /* Set the FW error flag -- cleared on iwl4965_down */ + /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->status); /* Cancel currently queued command. */ @@ -1518,7 +1518,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) if (priv->debug_level & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); - iwl4965_print_rx_config_cmd(priv); + iwl_print_rx_config_cmd(priv); } #endif @@ -1542,14 +1542,14 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) } } -static void iwl4965_error_recovery(struct iwl_priv *priv) +static void iwl_error_recovery(struct iwl_priv *priv) { unsigned long flags; memcpy(&priv->staging_rxon, &priv->recovery_rxon, sizeof(priv->staging_rxon)); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); iwl_rxon_add_station(priv, priv->bssid, 1); @@ -1559,7 +1559,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl4965_irq_tasklet(struct iwl_priv *priv) +static void iwl_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; u32 inta_fh; @@ -1605,9 +1605,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) IWL_ERROR("Microcode HW error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); - iwl4965_irq_handle_error(priv); + iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -1661,7 +1661,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", inta); - iwl4965_irq_handle_error(priv); + iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -1707,7 +1707,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) /* Re-enable all interrupts */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { @@ -1721,7 +1721,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static irqreturn_t iwl4965_isr(int irq, void *data) +static irqreturn_t iwl_isr(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; @@ -1762,7 +1762,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) inta &= ~CSR_INT_BIT_SCD; - /* iwl4965_irq_tasklet() will service interrupts and re-enable them */ + /* iwl_irq_tasklet() will service interrupts and re-enable them */ if (likely(inta || inta_fh)) tasklet_schedule(&priv->irq_tasklet); @@ -1774,7 +1774,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) /* re-enable interrupts here since we don't have anything to service. */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } @@ -1785,7 +1785,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) * ******************************************************************************/ -static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) { iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); @@ -1795,7 +1795,7 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -static void iwl4965_nic_start(struct iwl_priv *priv) +static void iwl_nic_start(struct iwl_priv *priv) { /* Remove all resets to allow NIC to operate */ iwl_write32(priv, CSR_RESET, 0); @@ -1803,11 +1803,11 @@ static void iwl4965_nic_start(struct iwl_priv *priv) /** - * iwl4965_read_ucode - Read uCode images from disk file. + * iwl_read_ucode - Read uCode images from disk file. * * Copy into buffers for card to fetch via bus-mastering */ -static int iwl4965_read_ucode(struct iwl_priv *priv) +static int iwl_read_ucode(struct iwl_priv *priv) { struct iwl_ucode *ucode; int ret; @@ -1951,7 +1951,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) - * NOTE: Copy into backup buffer will be done in iwl4965_up() */ + * NOTE: Copy into backup buffer will be done in iwl_up() */ src = &ucode->data[inst_size]; len = priv->ucode_data.len; IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); @@ -1989,7 +1989,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) err_pci_alloc: IWL_ERROR("failed to allocate pci memory\n"); ret = -ENOMEM; - iwl4965_dealloc_ucode_pci(priv); + iwl_dealloc_ucode_pci(priv); err_release: release_firmware(ucode_raw); @@ -2034,7 +2034,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - /* After the ALIVE response, we can send host commands to 4965 uCode */ + /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); if (iwl_is_rfkill(priv)) @@ -2054,17 +2054,17 @@ static void iwl_alive_start(struct iwl_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl4965_connection_init_rx_config(priv, priv->iw_mode); + iwl_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } /* Configure Bluetooth device coexistence support */ - iwl4965_send_bt_config(priv); + iwl_send_bt_config(priv); iwl_reset_run_time_calib(priv); /* Configure the adapter for unassociated operation */ - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); @@ -2076,12 +2076,12 @@ static void iwl_alive_start(struct iwl_priv *priv) wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) - iwl4965_error_recovery(priv); + iwl_error_recovery(priv); iwl_power_update_mode(priv, 1); if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) - iwl4965_set_mode(priv, priv->iw_mode); + iwl_set_mode(priv, priv->iw_mode); return; @@ -2091,7 +2091,7 @@ static void iwl_alive_start(struct iwl_priv *priv) static void iwl_cancel_deferred_work(struct iwl_priv *priv); -static void __iwl4965_down(struct iwl_priv *priv) +static void __iwl_down(struct iwl_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); @@ -2118,14 +2118,14 @@ static void __iwl4965_down(struct iwl_priv *priv) /* tell the device to stop sending interrupts */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_synchronize_irq(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl4965_init() then + /* If we have not previously called iwl_init() then * clear all bits but the RF Kill and SUSPEND bits and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << @@ -2192,10 +2192,10 @@ static void __iwl4965_down(struct iwl_priv *priv) iwl_clear_free_frames(priv); } -static void iwl4965_down(struct iwl_priv *priv) +static void iwl_down(struct iwl_priv *priv) { mutex_lock(&priv->mutex); - __iwl4965_down(priv); + __iwl_down(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); @@ -2203,7 +2203,7 @@ static void iwl4965_down(struct iwl_priv *priv) #define MAX_HW_RESTARTS 5 -static int __iwl4965_up(struct iwl_priv *priv) +static int __iwl_up(struct iwl_priv *priv) { int i; int ret; @@ -2225,7 +2225,7 @@ static int __iwl4965_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); IWL_WARNING("Radio disabled by %s RF Kill switch\n", test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); return 0; @@ -2252,7 +2252,7 @@ static int __iwl4965_up(struct iwl_priv *priv) /* clear (again), then enable host interrupts */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); @@ -2282,7 +2282,7 @@ static int __iwl4965_up(struct iwl_priv *priv) clear_bit(STATUS_FW_ERROR, &priv->status); /* start card; "initialize" will load runtime ucode */ - iwl4965_nic_start(priv); + iwl_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -2290,7 +2290,7 @@ static int __iwl4965_up(struct iwl_priv *priv) } set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl4965_down(priv); + __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our @@ -2333,7 +2333,7 @@ static void iwl_bg_alive_start(struct work_struct *data) ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); } -static void iwl4965_bg_rf_kill(struct work_struct *work) +static void iwl_bg_rf_kill(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); @@ -2367,7 +2367,7 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) iwl_rfkill_set_hw_state(priv); } -static void iwl4965_bg_set_monitor(struct work_struct *work) +static void iwl_bg_set_monitor(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, set_monitor); @@ -2377,12 +2377,12 @@ static void iwl4965_bg_set_monitor(struct work_struct *work) mutex_lock(&priv->mutex); - ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR); + ret = iwl_set_mode(priv, NL80211_IFTYPE_MONITOR); if (ret) { if (ret == -EAGAIN) IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); else - IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret); + IWL_ERROR("iwl_set_mode() failed ret = %d\n", ret); } mutex_unlock(&priv->mutex); @@ -2412,7 +2412,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) return; } -static void iwl4965_bg_up(struct work_struct *data) +static void iwl_bg_up(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, up); @@ -2420,23 +2420,23 @@ static void iwl4965_bg_up(struct work_struct *data) return; mutex_lock(&priv->mutex); - __iwl4965_up(priv); + __iwl_up(priv); mutex_unlock(&priv->mutex); iwl_rfkill_set_hw_state(priv); } -static void iwl4965_bg_restart(struct work_struct *data) +static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl4965_down(priv); + iwl_down(priv); queue_work(priv->workqueue, &priv->up); } -static void iwl4965_bg_rx_replenish(struct work_struct *data) +static void iwl_bg_rx_replenish(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rx_replenish); @@ -2451,7 +2451,7 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl4965_post_associate(struct iwl_priv *priv) +static void iwl_post_associate(struct iwl_priv *priv) { struct ieee80211_conf *conf = NULL; int ret = 0; @@ -2479,7 +2479,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, @@ -2514,7 +2514,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) } - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -2526,7 +2526,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->assoc_id = 1; iwl_rxon_add_station(priv, priv->bssid, 0); - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); break; @@ -2563,7 +2563,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) #define UCODE_READY_TIMEOUT (4 * HZ) -static int iwl4965_mac_start(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -2585,7 +2585,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); } - ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, + ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); if (ret) { IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -2600,7 +2600,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) * ucode filename and max sizes are card-specific. */ if (!priv->ucode_code.len) { - ret = iwl4965_read_ucode(priv); + ret = iwl_read_ucode(priv); if (ret) { IWL_ERROR("Could not read microcode: %d\n", ret); mutex_unlock(&priv->mutex); @@ -2608,7 +2608,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) } } - ret = __iwl4965_up(priv); + ret = __iwl_up(priv); mutex_unlock(&priv->mutex); @@ -2654,7 +2654,7 @@ out_disable_msi: return ret; } -static void iwl4965_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -2676,7 +2676,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); } - iwl4965_down(priv); + iwl_down(priv); flush_workqueue(priv->workqueue); free_irq(priv->pci_dev->irq, priv); @@ -2687,7 +2687,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -2703,7 +2703,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return 0; } -static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, +static int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; @@ -2729,7 +2729,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl4965_set_mode(priv, conf->type) == -EAGAIN) + if (iwl_set_mode(priv, conf->type) == -EAGAIN) /* we are not ready, will run again when ready */ set_bit(STATUS_MODE_PENDING, &priv->status); @@ -2740,13 +2740,13 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, } /** - * iwl4965_mac_config - mac80211 config callback + * iwl_mac_config - mac80211 config callback * * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed) +static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; @@ -2817,13 +2817,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed) /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists */ - iwl4965_set_rate(priv); + iwl_set_rate(priv); spin_unlock_irqrestore(&priv->lock, flags); #ifdef IEEE80211_CONF_CHANNEL_SWITCH if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl4965_hw_channel_switch(priv, conf->channel); + iwl_hw_channel_switch(priv, conf->channel); goto out; } #endif @@ -2851,11 +2851,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_tx_power(priv, conf->power_level, false); - iwl4965_set_rate(priv); + iwl_set_rate(priv); if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); else IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); @@ -2866,7 +2866,7 @@ out: return ret; } -static void iwl4965_config_ap(struct iwl_priv *priv) +static void iwl_config_ap(struct iwl_priv *priv) { int ret = 0; unsigned long flags; @@ -2879,7 +2879,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); /* RXON Timing */ iwl_setup_rxon_timing(priv); @@ -2915,13 +2915,13 @@ static void iwl4965_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); iwl_rxon_add_station(priv, iwl_bcast_addr, 0); } - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, @@ -2929,9 +2929,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv) } /* temporary */ -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); -static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, +static int iwl_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { @@ -2951,7 +2951,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; - rc = iwl4965_mac_beacon_update(hw, beacon); + rc = iwl_mac_beacon_update(hw, beacon); if (rc) return rc; } @@ -3007,9 +3007,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl4965_config_ap(priv); + iwl_config_ap(priv); else { - rc = iwl4965_commit_rxon(priv); + rc = iwl_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); @@ -3018,7 +3018,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, } else { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } done: @@ -3028,7 +3028,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return 0; } -static void iwl4965_configure_filter(struct ieee80211_hw *hw, +static void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) @@ -3047,7 +3047,7 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; @@ -3059,7 +3059,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, if (iwl_is_ready_rf(priv)) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } if (priv->vif == conf->vif) { priv->vif = NULL; @@ -3072,7 +3072,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, } #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, +static void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes) @@ -3099,7 +3099,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_HT) { - iwl4965_ht_conf(priv, bss_conf); + iwl_ht_conf(priv, bss_conf); iwl_set_rxon_chain(priv); } @@ -3122,7 +3122,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; mutex_lock(&priv->mutex); - iwl4965_post_associate(priv); + iwl_post_associate(priv); mutex_unlock(&priv->mutex); } else { priv->assoc_id = 0; @@ -3198,7 +3198,7 @@ out_unlock: return ret; } -static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, +static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) { @@ -3249,7 +3249,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { @@ -3320,7 +3320,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; @@ -3368,7 +3368,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, +static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { @@ -3400,7 +3400,7 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, } return 0; } -static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { struct iwl_priv *priv = hw->priv; @@ -3435,7 +3435,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, return 0; } -static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, +static int iwl_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct iwl_priv *priv = hw->priv; @@ -3447,7 +3447,7 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; unsigned long flags; @@ -3491,7 +3491,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } iwl_power_update_mode(priv, 0); @@ -3514,14 +3514,14 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) return; } - iwl4965_set_rate(priv); + iwl_set_rate(priv); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; unsigned long flags; @@ -3558,7 +3558,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl_reset_qos(priv); - iwl4965_post_associate(priv); + iwl_post_associate(priv); mutex_unlock(&priv->mutex); @@ -3712,7 +3712,7 @@ static ssize_t store_flags(struct device *d, else { IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3753,7 +3753,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3828,7 +3828,7 @@ static ssize_t store_measurement(struct device *d, IWL_DEBUG_INFO("Invoking measurement of type %d on " "channel %d (for '%s')\n", type, params.channel, buf); - iwl4965_get_measurement(priv, ¶ms, type); + iwl_get_measurement(priv, ¶ms, type); return count; } @@ -4048,12 +4048,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl4965_bg_up); - INIT_WORK(&priv->restart, iwl4965_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); - INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); + INIT_WORK(&priv->set_monitor, iwl_bg_set_monitor); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); @@ -4066,10 +4066,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_timer(&priv->statistics_periodic); priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; + priv->statistics_periodic.function = iwl_bg_statistics_periodic; tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl4965_irq_tasklet, (unsigned long)priv); + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -4085,7 +4085,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) del_timer_sync(&priv->statistics_periodic); } -static struct attribute *iwl4965_sysfs_entries[] = { +static struct attribute *iwl_sysfs_entries[] = { &dev_attr_channels.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, @@ -4106,32 +4106,32 @@ static struct attribute *iwl4965_sysfs_entries[] = { NULL }; -static struct attribute_group iwl4965_attribute_group = { +static struct attribute_group iwl_attribute_group = { .name = NULL, /* put in device directory */ - .attrs = iwl4965_sysfs_entries, + .attrs = iwl_sysfs_entries, }; -static struct ieee80211_ops iwl4965_hw_ops = { - .tx = iwl4965_mac_tx, - .start = iwl4965_mac_start, - .stop = iwl4965_mac_stop, - .add_interface = iwl4965_mac_add_interface, - .remove_interface = iwl4965_mac_remove_interface, - .config = iwl4965_mac_config, - .config_interface = iwl4965_mac_config_interface, - .configure_filter = iwl4965_configure_filter, - .set_key = iwl4965_mac_set_key, - .update_tkip_key = iwl4965_mac_update_tkip_key, - .get_stats = iwl4965_mac_get_stats, - .get_tx_stats = iwl4965_mac_get_tx_stats, - .conf_tx = iwl4965_mac_conf_tx, - .reset_tsf = iwl4965_mac_reset_tsf, - .bss_info_changed = iwl4965_bss_info_changed, - .ampdu_action = iwl4965_mac_ampdu_action, +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .start = iwl_mac_start, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, + .set_key = iwl_mac_set_key, + .update_tkip_key = iwl_mac_update_tkip_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .reset_tsf = iwl_mac_reset_tsf, + .bss_info_changed = iwl_bss_info_changed, + .ampdu_action = iwl_mac_ampdu_action, .hw_scan = iwl_mac_hw_scan }; -static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; struct iwl_priv *priv; @@ -4149,10 +4149,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (cfg->mod_params->debug & IWL_DL_INFO) dev_printk(KERN_DEBUG, &(pdev->dev), "Disabling hw_scan\n"); - iwl4965_hw_ops.hw_scan = NULL; + iwl_hw_ops.hw_scan = NULL; } - hw = iwl_alloc_all(cfg, &iwl4965_hw_ops); + hw = iwl_alloc_all(cfg, &iwl_hw_ops); if (!hw) { err = -ENOMEM; goto out; @@ -4280,10 +4280,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * 8. Setup services ********************/ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); - err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); goto out_uninit_drv; @@ -4319,7 +4319,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); out_uninit_drv: iwl_uninit_drv(priv); out_free_eeprom: @@ -4337,7 +4337,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return err; } -static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) +static void __devexit iwl_pci_remove(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); unsigned long flags; @@ -4348,10 +4348,10 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); iwl_dbgfs_unregister(priv); - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); - /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to - * to be called and iwl4965_down since we are removing the device + /* ieee80211_unregister_hw call wil cause iwl_mac_stop to + * to be called and iwl_down since we are removing the device * we need to set STATUS_EXIT_PENDING bit. */ set_bit(STATUS_EXIT_PENDING, &priv->status); @@ -4359,20 +4359,20 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; } else { - iwl4965_down(priv); + iwl_down(priv); } /* make sure we flush any pending irq or * tasklet for the driver */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_synchronize_irq(priv); iwl_rfkill_unregister(priv); - iwl4965_dealloc_ucode_pci(priv); + iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) iwl_rx_queue_free(priv, &priv->rxq); @@ -4385,7 +4385,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); - /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes * priv->workqueue... so we can't take down the workqueue * until now... */ destroy_workqueue(priv->workqueue); @@ -4406,13 +4406,13 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM -static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct iwl_priv *priv = pci_get_drvdata(pdev); if (priv->is_open) { set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl4965_mac_stop(priv->hw); + iwl_mac_stop(priv->hw); priv->is_open = 1; } @@ -4421,14 +4421,14 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int iwl4965_pci_resume(struct pci_dev *pdev) +static int iwl_pci_resume(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); if (priv->is_open) - iwl4965_mac_start(priv->hw); + iwl_mac_start(priv->hw); clear_bit(STATUS_IN_SUSPEND, &priv->status); return 0; @@ -4471,15 +4471,15 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); static struct pci_driver iwl_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, - .probe = iwl4965_pci_probe, - .remove = __devexit_p(iwl4965_pci_remove), + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), #ifdef CONFIG_PM - .suspend = iwl4965_pci_suspend, - .resume = iwl4965_pci_resume, + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, #endif }; -static int __init iwl4965_init(void) +static int __init iwl_init(void) { int ret; @@ -4505,11 +4505,11 @@ error_register: return ret; } -static void __exit iwl4965_exit(void) +static void __exit iwl_exit(void) { pci_unregister_driver(&iwl_driver); iwlagn_rate_control_unregister(); } -module_exit(iwl4965_exit); -module_init(iwl4965_init); +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 358ea74..eb396f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -576,8 +576,8 @@ extern int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); -extern void iwl4965_update_chain_flags(struct iwl_priv *priv); -extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); +extern void iwl_update_chain_flags(struct iwl_priv *priv); +extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); extern const u8 iwl_bcast_addr[ETH_ALEN]; extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); -- cgit v1.1 From 6a63578ddf6148927a80c07a73b40ccc8f3ac8e2 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 29 Oct 2008 14:05:47 -0700 Subject: iwlwifi: rename double inclusion protection name in iwl-commands.h This patch change the name of the double inclusion protection in iwl-commands.h Signed-off-by: Emmanuel Grumbach Reviewed-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 5ab74fc..8aade00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -66,8 +66,8 @@ * Please use iwl-dev.h for driver implementation definitions. */ -#ifndef __iwl4965_commands_h__ -#define __iwl4965_commands_h__ +#ifndef __iwl_commands_h__ +#define __iwl_commands_h__ enum { REPLY_ALIVE = 0x1, @@ -3064,4 +3064,4 @@ struct iwl_rx_packet { #define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) -#endif /* __iwl4965_commands_h__ */ +#endif /* __iwl_commands_h__ */ -- cgit v1.1 From eb48dcaf57d4e9b6521aeb593fe95a36db6c2109 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 29 Oct 2008 14:05:48 -0700 Subject: iwlwifi: iwl-agn-rs: initialize rs with valid antenna This patch fix rate scaling initialization. Rate scaling was initialized always with B antenna. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index f5e94b6..0332805 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2071,15 +2071,13 @@ static void rs_initialize_lq(struct iwl_priv *priv, if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - /* FIXME:RS: This is also wrong in 4965 */ rate = iwl_rates[i].plcp; - rate |= RATE_MCS_ANT_B_MSK; - rate &= ~RATE_MCS_ANT_A_MSK; + tbl->ant_type = first_antenna(valid_tx_ant); + rate |= tbl->ant_type << RATE_MCS_ANT_POS; if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) rate |= RATE_MCS_CCK_MSK; - tbl->ant_type = ANT_B; rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) rs_toggle_antenna(valid_tx_ant, &rate, tbl); -- cgit v1.1 From 61780ee313846b29bfb06dfcb2f3bdf0b7ba3f66 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Wed, 29 Oct 2008 14:05:49 -0700 Subject: iwlwifi: do not call statistics from rfkill Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f3e4cf5..8264d37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1153,6 +1153,10 @@ static void iwl_bg_statistics_periodic(unsigned long data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + /* dont send host command if rf-kill is on */ + if (!iwl_is_ready_rf(priv)) + return; + iwl_send_statistics_request(priv, CMD_ASYNC); } -- cgit v1.1 From c8034c44851ba4c6b55ec6e6b60573cf51589be3 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 29 Oct 2008 17:31:43 -0400 Subject: p54: don't report known but unhandled EEPROM codes as unknown Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index a2e2150..6f0aa79 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -420,6 +420,30 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) /* make it overrun */ entry_len = len; break; + case PDR_MANUFACTURING_PART_NUMBER: + case PDR_PDA_VERSION: + case PDR_NIC_SERIAL_NUMBER: + case PDR_REGULATORY_DOMAIN_LIST: + case PDR_TEMPERATURE_TYPE: + case PDR_PRISM_PCI_IDENTIFIER: + case PDR_COUNTRY_INFORMATION: + case PDR_OEM_NAME: + case PDR_PRODUCT_NAME: + case PDR_UTF8_OEM_NAME: + case PDR_UTF8_PRODUCT_NAME: + case PDR_COUNTRY_LIST: + case PDR_DEFAULT_COUNTRY: + case PDR_ANTENNA_GAIN: + case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_REGULATORY_POWER_LIMITS: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + case PDR_RADIATED_TRANSMISSION_CORRECTION: + case PDR_PRISM_TX_IQ_CALIBRATION: + case PDR_BASEBAND_REGISTERS: + case PDR_PER_CHANNEL_BASEBAND_REGISTERS: + break; default: printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", le16_to_cpu(entry->code)); -- cgit v1.1 From 9483407d09077c0bfc612c72835b1e9bbdda0a10 Mon Sep 17 00:00:00 2001 From: Chr Date: Wed, 29 Oct 2008 22:39:50 +0100 Subject: p54: initialize all deprecated fields The new mechanism for allocing space for control frames, didn't "zero" out the payload data... However I haven't heard of any hiccups so far... Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6f0aa79..1796b8c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -9,7 +9,7 @@ * - the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note , et al. * - stlc45xx driver - * C Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1241,8 +1241,10 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) else memcpy(setup->bssid, bssid, ETH_ALEN); setup->rx_antenna = priv->rx_antenna; + setup->rx_align = 0; if (priv->fw_var < 0x500) { setup->v1.basic_rate_mask = cpu_to_le32(0x15f); + memset(setup->v1.rts_rates, 0, 8); setup->v1.rx_addr = cpu_to_le32(priv->rx_end); setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); setup->v1.rxhw = cpu_to_le16(priv->rxhw); @@ -1326,11 +1328,11 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) } 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); + chan->pa_points_per_curve = 8; + memset(chan->curve_data, 0, sizeof(*chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, priv->curve_data->points_per_channel)); break; } @@ -1406,6 +1408,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev) /* (see prism54/isl_oid.h for further details) */ edcf->frameburst = cpu_to_le16(0); edcf->round_trip_delay = cpu_to_le16(0); + edcf->flags = 0; memset(edcf->mapping, 0, sizeof(edcf->mapping)); memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); priv->tx(dev, skb, 1); -- cgit v1.1 From ccf5dd14f8a4273f40d8319e75b377edb1f5220d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Oct 2008 23:24:14 +0100 Subject: libertas_tf: fix skb tail pointer skb->tail can't be meant here because it's not the same across 32/64 bit compilations. This means there's no way the current driver can work on 64-bit architectures. Signed-off-by: Johannes Berg Cc: stable@kernel.org [2.6.27] Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/if_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index 1cc03a8..59634c3 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -331,7 +331,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, /* Fill the receive configuration URB and initialise the Rx call back */ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, usb_rcvbulkpipe(cardp->udev, cardp->ep_in), - (void *) (skb->tail), + skb_tail_pointer(skb), MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; -- cgit v1.1 From 95f8e38deffc55f7108bcfa3e180bd5b3d53fc04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Thu, 30 Oct 2008 13:43:41 +0200 Subject: b43legacy: reindent misleading statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Järvinen Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 308c264..3649fc3 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -919,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = ssb_dma_map_single(dev->dev, + dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache, sizeof(struct b43legacy_txhdr_fw3), DMA_TO_DEVICE); -- cgit v1.1 From fe63bfa3669dbdd4985ed35d9a0ed08881f62516 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 16:59:21 +0200 Subject: mac80211_hwsim: Debug info for BSS config changes Provide detailed information on BSS configuration changes to make it easier to debug mac80211 functionality. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c576523..6671592 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -413,6 +413,43 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { hwsim_check_magic(vif); + + printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", + wiphy_name(hw->wiphy), __func__, changed); + + if (changed & BSS_CHANGED_ASSOC) { + printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", + wiphy_name(hw->wiphy), info->assoc, info->aid); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", + wiphy_name(hw->wiphy), info->use_cts_prot); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", + wiphy_name(hw->wiphy), info->use_short_preamble); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", + wiphy_name(hw->wiphy), info->use_short_slot); + } + + if (changed & BSS_CHANGED_HT) { + printk(KERN_DEBUG " %s: HT: sec_ch_offs=%d width_40_ok=%d " + "op_mode=%d\n", + wiphy_name(hw->wiphy), + info->ht.secondary_channel_offset, + info->ht.width_40_ok, info->ht.operation_mode); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", + wiphy_name(hw->wiphy), + (unsigned long long) info->basic_rates); + } } static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, -- cgit v1.1 From 1e898ff83c31c303f73c3893d1ac519e4d9b59e5 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 16:59:23 +0200 Subject: mac80211_hwsim: Debug info for TX queue parameters Provide detailed information on TX queue parameter changes to make it easier to debug mac80211 functionality. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6671592..2b07d4b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -476,6 +476,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, return 0; } +static int mac80211_hwsim_conf_tx( + struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " + "aifs=%d)\n", + wiphy_name(hw->wiphy), __func__, queue, + params->txop, params->cw_min, params->cw_max, params->aifs); + return 0; +} + static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -489,6 +500,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .bss_info_changed = mac80211_hwsim_bss_info_changed, .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, + .conf_tx = mac80211_hwsim_conf_tx, }; -- cgit v1.1 From ab1ef980504ca7f17b675b3a53a88956f800fce3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 16:59:25 +0200 Subject: mac80211_hwsim: Make sure beacon_timer gets deleted It was possible to trigger a kernel panic because beacon_timer may not have been deleted in all cases when the kernel module was removed while hostapd was still running. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 2b07d4b..bc9da939 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -290,6 +290,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *data = hw->priv; data->started = 0; + del_timer(&data->beacon_timer); printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); } -- cgit v1.1 From fc6971d491517ba15e800540ff88caa55dc65b01 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 19:59:05 +0200 Subject: mac80211_hwsim: Add support for client PS mode This introduces a debugfs file (ieee80211/phy#/hwsim/ps) that can be used to force a simulated radio into power save mode. Following values can be written into this file to change PS mode: 0 = power save disabled (constantly awake) 1 = power save enabled (drop all frames; do not send PS-Poll) 2 = power save enabled (send PS-Poll frames automatically to receive buffered unicast frames); not yet fully implemented 3 = manual PS-Poll trigger (send a single PS-Poll frame) Two different behavior for power save mode processing can be tested: - move between modes 1 and 0 (i.e., receive all buffered frames at a time) - move to mode 1 and use manual PS-Poll frames (write 3 to the 'ps' debugfs file) to fetch power save buffered frames one at a time Mode 2 (automatic PS-Poll) does not yet parse Beacon frames, but eventually, it should take a look at TIM IE and send PS-Poll if a traffic bit is set for our AID. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 184 ++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bc9da939..b9230da 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -21,6 +21,7 @@ #include #include #include +#include MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); @@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios"); struct hwsim_vif_priv { u32 magic; + u8 bssid[ETH_ALEN]; + bool assoc; + u16 aid; }; #define HWSIM_VIF_MAGIC 0x69537748 @@ -132,6 +136,12 @@ struct mac80211_hwsim_data { unsigned int rx_filter; int started; struct timer_list beacon_timer; + enum ps_mode { + PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL + } ps; + bool ps_poll_pending; + struct dentry *debugfs; + struct dentry *debugfs_ps; }; @@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } +static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, + struct sk_buff *skb) +{ + switch (data->ps) { + case PS_DISABLED: + return true; + case PS_ENABLED: + return false; + case PS_AUTO_POLL: + /* TODO: accept (some) Beacons by default and other frames only + * if pending PS-Poll has been sent */ + return true; + case PS_MANUAL_POLL: + /* Allow unicast frames to own address if there is a pending + * PS-Poll */ + if (data->ps_poll_pending && + memcmp(data->hw->wiphy->perm_addr, skb->data + 4, + ETH_ALEN) == 0) { + data->ps_poll_pending = false; + return true; + } + return false; + } + + return true; +} + + static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -212,6 +250,9 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, rx_status.rate_idx = info->control.rates[0].idx; /* TODO: simulate signal strength (and optional packet drop) */ + if (data->ps != PS_DISABLED) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + /* Copy skb to all enabled radios that are on the current frequency */ spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { @@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, continue; if (!data2->started || !data2->radio_enabled || + !hwsim_ps_rx_ok(data2, skb) || data->channel->center_freq != data2->channel->center_freq) continue; @@ -404,7 +446,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + hwsim_check_magic(vif); + if (conf->changed & IEEE80211_IFCC_BSSID) { + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n", + wiphy_name(hw->wiphy), __func__, + print_mac(mac, conf->bssid)); + memcpy(vp->bssid, conf->bssid, ETH_ALEN); + } return 0; } @@ -413,6 +464,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u32 changed) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + hwsim_check_magic(vif); printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", @@ -421,6 +474,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", wiphy_name(hw->wiphy), info->assoc, info->aid); + vp->assoc = info->assoc; + vp->aid = info->aid; } if (changed & BSS_CHANGED_ERP_CTS_PROT) { @@ -518,6 +573,8 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry(data, &tmplist, list) { + debugfs_remove(data->debugfs_ps); + debugfs_remove(data->debugfs); ieee80211_unregister_hw(data->hw); device_unregister(data->dev); ieee80211_free_hw(data->hw); @@ -543,6 +600,127 @@ static void hwsim_mon_setup(struct net_device *dev) } +static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + DECLARE_MAC_BUF(buf); + struct sk_buff *skb; + struct ieee80211_pspoll *pspoll; + + if (!vp->assoc) + return; + + printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n", + wiphy_name(data->hw->wiphy), __func__, + print_mac(buf, vp->bssid), vp->aid); + + skb = dev_alloc_skb(sizeof(*pspoll)); + if (!skb) + return; + pspoll = (void *) skb_put(skb, sizeof(*pspoll)); + pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_PSPOLL | + IEEE80211_FCTL_PM); + pspoll->aid = cpu_to_le16(0xc000 | vp->aid); + memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); + memcpy(pspoll->ta, mac, ETH_ALEN); + if (data->radio_enabled && + !mac80211_hwsim_tx_frame(data->hw, skb)) + printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); + dev_kfree_skb(skb); +} + + +static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, + struct ieee80211_vif *vif, int ps) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + DECLARE_MAC_BUF(buf); + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + + if (!vp->assoc) + return; + + printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n", + wiphy_name(data->hw->wiphy), __func__, + print_mac(buf, vp->bssid), ps); + + skb = dev_alloc_skb(sizeof(*hdr)); + if (!skb) + return; + hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + (ps ? IEEE80211_FCTL_PM : 0)); + hdr->duration_id = cpu_to_le16(0); + memcpy(hdr->addr1, vp->bssid, ETH_ALEN); + memcpy(hdr->addr2, mac, ETH_ALEN); + memcpy(hdr->addr3, vp->bssid, ETH_ALEN); + if (data->radio_enabled && + !mac80211_hwsim_tx_frame(data->hw, skb)) + printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); + dev_kfree_skb(skb); +} + + +static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 1); +} + + +static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 0); +} + + +static int hwsim_fops_ps_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->ps; + return 0; +} + +static int hwsim_fops_ps_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + enum ps_mode old_ps; + + if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && + val != PS_MANUAL_POLL) + return -EINVAL; + + old_ps = data->ps; + data->ps = val; + + if (val == PS_MANUAL_POLL) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_ps_poll, data); + data->ps_poll_pending = true; + } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_nullfunc_ps, + data); + } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_nullfunc_no_ps, + data); + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, + "%llu\n"); + + static int __init init_mac80211_hwsim(void) { int i, err = 0; @@ -634,6 +812,12 @@ static int __init init_mac80211_hwsim(void) wiphy_name(hw->wiphy), hw->wiphy->perm_addr); + data->debugfs = debugfs_create_dir("hwsim", + hw->wiphy->debugfsdir); + data->debugfs_ps = debugfs_create_file("ps", 0666, + data->debugfs, data, + &hwsim_fops_ps); + setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); -- cgit v1.1 From b2e53b338b7b4608372d070bb477f3bae3971e5a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Fri, 31 Oct 2008 13:35:21 +0000 Subject: orinoco: Move sources to a subdirectory Keeping all the orinoco drivers in a common directory will make maintenance easier. Signed-off by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/Makefile | 9 +- drivers/net/wireless/airport.c | 286 -- drivers/net/wireless/hermes.c | 544 --- drivers/net/wireless/hermes.h | 494 -- drivers/net/wireless/hermes_dld.c | 730 --- drivers/net/wireless/hermes_dld.h | 48 - drivers/net/wireless/hermes_rid.h | 165 - drivers/net/wireless/orinoco.c | 6032 ------------------------- drivers/net/wireless/orinoco.h | 218 - drivers/net/wireless/orinoco/Makefile | 12 + drivers/net/wireless/orinoco/airport.c | 286 ++ drivers/net/wireless/orinoco/hermes.c | 544 +++ drivers/net/wireless/orinoco/hermes.h | 494 ++ drivers/net/wireless/orinoco/hermes_dld.c | 730 +++ drivers/net/wireless/orinoco/hermes_dld.h | 48 + drivers/net/wireless/orinoco/hermes_rid.h | 165 + drivers/net/wireless/orinoco/orinoco.c | 6032 +++++++++++++++++++++++++ drivers/net/wireless/orinoco/orinoco.h | 218 + drivers/net/wireless/orinoco/orinoco_cs.c | 533 +++ drivers/net/wireless/orinoco/orinoco_nortel.c | 324 ++ drivers/net/wireless/orinoco/orinoco_pci.c | 264 ++ drivers/net/wireless/orinoco/orinoco_pci.h | 109 + drivers/net/wireless/orinoco/orinoco_plx.c | 371 ++ drivers/net/wireless/orinoco/orinoco_tmd.c | 248 + drivers/net/wireless/orinoco/spectrum_cs.c | 507 +++ drivers/net/wireless/orinoco_cs.c | 533 --- drivers/net/wireless/orinoco_nortel.c | 324 -- drivers/net/wireless/orinoco_pci.c | 264 -- drivers/net/wireless/orinoco_pci.h | 109 - drivers/net/wireless/orinoco_plx.c | 371 -- drivers/net/wireless/orinoco_tmd.c | 248 - drivers/net/wireless/spectrum_cs.c | 507 --- 32 files changed, 10886 insertions(+), 10881 deletions(-) delete mode 100644 drivers/net/wireless/airport.c delete mode 100644 drivers/net/wireless/hermes.c delete mode 100644 drivers/net/wireless/hermes.h delete mode 100644 drivers/net/wireless/hermes_dld.c delete mode 100644 drivers/net/wireless/hermes_dld.h delete mode 100644 drivers/net/wireless/hermes_rid.h delete mode 100644 drivers/net/wireless/orinoco.c delete mode 100644 drivers/net/wireless/orinoco.h create mode 100644 drivers/net/wireless/orinoco/Makefile create mode 100644 drivers/net/wireless/orinoco/airport.c create mode 100644 drivers/net/wireless/orinoco/hermes.c create mode 100644 drivers/net/wireless/orinoco/hermes.h create mode 100644 drivers/net/wireless/orinoco/hermes_dld.c create mode 100644 drivers/net/wireless/orinoco/hermes_dld.h create mode 100644 drivers/net/wireless/orinoco/hermes_rid.h create mode 100644 drivers/net/wireless/orinoco/orinoco.c create mode 100644 drivers/net/wireless/orinoco/orinoco.h create mode 100644 drivers/net/wireless/orinoco/orinoco_cs.c create mode 100644 drivers/net/wireless/orinoco/orinoco_nortel.c create mode 100644 drivers/net/wireless/orinoco/orinoco_pci.c create mode 100644 drivers/net/wireless/orinoco/orinoco_pci.h create mode 100644 drivers/net/wireless/orinoco/orinoco_plx.c create mode 100644 drivers/net/wireless/orinoco/orinoco_tmd.c create mode 100644 drivers/net/wireless/orinoco/spectrum_cs.c delete mode 100644 drivers/net/wireless/orinoco_cs.c delete mode 100644 drivers/net/wireless/orinoco_nortel.c delete mode 100644 drivers/net/wireless/orinoco_pci.c delete mode 100644 drivers/net/wireless/orinoco_pci.h delete mode 100644 drivers/net/wireless/orinoco_plx.c delete mode 100644 drivers/net/wireless/orinoco_tmd.c delete mode 100644 drivers/net/wireless/spectrum_cs.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 59d2d80..7882084 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -16,14 +16,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o -obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o -obj-$(CONFIG_APPLE_AIRPORT) += airport.o -obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o -obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o -obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o -obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o -obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o +obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c deleted file mode 100644 index ce03a2e..0000000 --- a/drivers/net/wireless/airport.c +++ /dev/null @@ -1,286 +0,0 @@ -/* airport.c - * - * A driver for "Hermes" chipset based Apple Airport wireless - * card. - * - * Copyright notice & release notes in file orinoco.c - * - * Note specific to airport stub: - * - * 0.05 : first version of the new split driver - * 0.06 : fix possible hang on powerup, add sleep support - */ - -#define DRIVER_NAME "airport" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include - -#include "orinoco.h" - -#define AIRPORT_IO_LEN (0x1000) /* one page */ - -struct airport { - struct macio_dev *mdev; - void __iomem *vaddr; - int irq_requested; - int ndev_registered; -}; - -static int -airport_suspend(struct macio_dev *mdev, pm_message_t state) -{ - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", - dev->name); - return 0; - } - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - - orinoco_unlock(priv, &flags); - - disable_irq(dev->irq); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); - - return 0; -} - -static int -airport_resume(struct macio_dev *mdev) -{ - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); - msleep(200); - - enable_irq(dev->irq); - - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", - dev->name, err); - return 0; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - - priv->hw_unavailable--; - - if (priv->open && (! priv->hw_unavailable)) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", - dev->name, err); - } - - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static int -airport_detach(struct macio_dev *mdev) -{ - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); - struct airport *card = priv->card; - - if (card->ndev_registered) - unregister_netdev(dev); - card->ndev_registered = 0; - - if (card->irq_requested) - free_irq(dev->irq, dev); - card->irq_requested = 0; - - if (card->vaddr) - iounmap(card->vaddr); - card->vaddr = NULL; - - macio_release_resource(mdev, 0); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); - ssleep(1); - - macio_set_drvdata(mdev, NULL); - free_orinocodev(dev); - - return 0; -} - -static int airport_hard_reset(struct orinoco_private *priv) -{ - /* It would be nice to power cycle the Airport for a real hard - * reset, but for some reason although it appears to - * re-initialize properly, it falls in a screaming heap - * shortly afterwards. */ -#if 0 - struct net_device *dev = priv->ndev; - struct airport *card = priv->card; - - /* Vitally important. If we don't do this it seems we get an - * interrupt somewhere during the power cycle, since - * hw_unavailable is already set it doesn't get ACKed, we get - * into an interrupt loop and the PMU decides to turn us - * off. */ - disable_irq(dev->irq); - - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); - ssleep(1); - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1); - ssleep(1); - - enable_irq(dev->irq); - ssleep(1); -#endif - - return 0; -} - -static int -airport_attach(struct macio_dev *mdev, const struct of_device_id *match) -{ - struct orinoco_private *priv; - struct net_device *dev; - struct airport *card; - unsigned long phys_addr; - hermes_t *hw; - - if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { - printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); - return -ENODEV; - } - - /* Allocate space for private device-specific data */ - dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, - airport_hard_reset, NULL); - if (! dev) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - return -ENODEV; - } - priv = netdev_priv(dev); - card = priv->card; - - hw = &priv->hw; - card->mdev = mdev; - - if (macio_request_resource(mdev, 0, "airport")) { - printk(KERN_ERR PFX "can't request IO resource !\n"); - free_orinocodev(dev); - return -EBUSY; - } - - SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - - macio_set_drvdata(mdev, dev); - - /* Setup interrupts & base address */ - dev->irq = macio_irq(mdev, 0); - phys_addr = macio_resource_start(mdev, 0); /* Physical address */ - printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); - dev->base_addr = phys_addr; - card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); - if (!card->vaddr) { - printk(KERN_ERR PFX "ioremap() failed\n"); - goto failed; - } - - hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); - - /* Power up card */ - pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); - ssleep(1); - - /* Reset it before we get the interrupt */ - hermes_init(hw); - - if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); - goto failed; - } - card->irq_requested = 1; - - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); - goto failed; - } - printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name); - card->ndev_registered = 1; - return 0; - failed: - airport_detach(mdev); - return -ENODEV; -} /* airport_attach */ - - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Benjamin Herrenschmidt )"; -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); -MODULE_LICENSE("Dual MPL/GPL"); - -static struct of_device_id airport_match[] = -{ - { - .name = "radio", - }, - {}, -}; - -MODULE_DEVICE_TABLE (of, airport_match); - -static struct macio_driver airport_driver = -{ - .name = DRIVER_NAME, - .match_table = airport_match, - .probe = airport_attach, - .remove = airport_detach, - .suspend = airport_suspend, - .resume = airport_resume, -}; - -static int __init -init_airport(void) -{ - printk(KERN_DEBUG "%s\n", version); - - return macio_register_driver(&airport_driver); -} - -static void __exit -exit_airport(void) -{ - return macio_unregister_driver(&airport_driver); -} - -module_init(init_airport); -module_exit(exit_airport); diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c deleted file mode 100644 index bfa3753..0000000 --- a/drivers/net/wireless/hermes.c +++ /dev/null @@ -1,544 +0,0 @@ -/* hermes.c - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no - * particular order). - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include -#include -#include -#include - -#include "hermes.h" - -MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); -MODULE_AUTHOR("Pavel Roskin " - " & David Gibson "); -MODULE_LICENSE("Dual MPL/GPL"); - -/* These are maximum timeouts. Most often, card wil react much faster */ -#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ -#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ -#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ -#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ - -/* - * Debugging helpers - */ - -#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ - printk(stuff);} while (0) - -#undef HERMES_DEBUG -#ifdef HERMES_DEBUG -#include - -#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff) - -#else /* ! HERMES_DEBUG */ - -#define DEBUG(lvl, stuff...) do { } while (0) - -#endif /* ! HERMES_DEBUG */ - - -/* - * Internal functions - */ - -/* Issue a command to the chip. Waiting for it to complete is the caller's - problem. - - Returns -EBUSY if the command register is busy, 0 on success. - - Callable from any context. -*/ -static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0, - u16 param1, u16 param2) -{ - int k = CMD_BUSY_TIMEOUT; - u16 reg; - - /* First wait for the command register to unbusy */ - reg = hermes_read_regn(hw, CMD); - while ( (reg & HERMES_CMD_BUSY) && k ) { - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - if (reg & HERMES_CMD_BUSY) { - return -EBUSY; - } - - hermes_write_regn(hw, PARAM2, param2); - hermes_write_regn(hw, PARAM1, param1); - hermes_write_regn(hw, PARAM0, param0); - hermes_write_regn(hw, CMD, cmd); - - return 0; -} - -/* - * Function definitions - */ - -/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ -int hermes_doicmd_wait(hermes_t *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp) -{ - int err = 0; - int k; - u16 status, reg; - - err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ((!(reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (!hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (!(reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; -out: - return err; -} -EXPORT_SYMBOL(hermes_doicmd_wait); - -void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) -{ - hw->iobase = address; - hw->reg_spacing = reg_spacing; - hw->inten = 0x0; -} -EXPORT_SYMBOL(hermes_struct_init); - -int hermes_init(hermes_t *hw) -{ - u16 reg; - int err = 0; - int k; - - /* We don't want to be interrupted while resetting the chipset */ - hw->inten = 0x0; - hermes_write_regn(hw, INTEN, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - /* Normally it's a "can't happen" for the command register to - be busy when we go to issue a command because we are - serializing all commands. However we want to have some - chance of resetting the card even if it gets into a stupid - state, so we actually wait to see if the command register - will unbusy itself here. */ - k = CMD_BUSY_TIMEOUT; - reg = hermes_read_regn(hw, CMD); - while (k && (reg & HERMES_CMD_BUSY)) { - if (reg == 0xffff) /* Special case - the card has probably been removed, - so don't wait for the timeout */ - return -ENODEV; - - k--; - udelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* No need to explicitly handle the timeout - if we've timed - out hermes_issue_cmd() will probably return -EBUSY below */ - - /* According to the documentation, EVSTAT may contain - obsolete event occurrence information. We have to acknowledge - it by writing EVACK. */ - reg = hermes_read_regn(hw, EVSTAT); - hermes_write_regn(hw, EVACK, reg); - - /* We don't use hermes_docmd_wait here, because the reset wipes - the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); - - return err; -} -EXPORT_SYMBOL(hermes_init); - -/* Issue a command to the chip, and (busy!) wait for it to - * complete. - * - * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware - * - * Callable from any context, but locking is your problem. */ -int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, - struct hermes_response *resp) -{ - int err; - int k; - u16 reg; - u16 status; - - err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); - if (err) { - if (! hermes_present(hw)) { - if (net_ratelimit()) - printk(KERN_WARNING "hermes @ %p: " - "Card removed while issuing command " - "0x%04x.\n", hw->iobase, cmd); - err = -ENODEV; - } else - if (net_ratelimit()) - printk(KERN_ERR "hermes @ %p: " - "Error %d issuing command 0x%04x.\n", - hw->iobase, err, cmd); - goto out; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: Card removed " - "while waiting for command 0x%04x completion.\n", - hw->iobase, cmd); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: Timeout waiting for " - "command 0x%04x completion.\n", hw->iobase, cmd); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - if (resp) { - resp->status = status; - resp->resp0 = hermes_read_regn(hw, RESP0); - resp->resp1 = hermes_read_regn(hw, RESP1); - resp->resp2 = hermes_read_regn(hw, RESP2); - } - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); - - if (status & HERMES_STATUS_RESULT) - err = -EIO; - - out: - return err; -} -EXPORT_SYMBOL(hermes_docmd_wait); - -int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) -{ - int err = 0; - int k; - u16 reg; - - if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); - if (err) { - return err; - } - - reg = hermes_read_regn(hw, EVSTAT); - k = ALLOC_COMPL_TIMEOUT; - while ( (! (reg & HERMES_EV_ALLOC)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - if (! hermes_present(hw)) { - printk(KERN_WARNING "hermes @ %p: " - "Card removed waiting for frame allocation.\n", - hw->iobase); - return -ENODEV; - } - - if (! (reg & HERMES_EV_ALLOC)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for frame allocation\n", - hw->iobase); - return -ETIMEDOUT; - } - - *fid = hermes_read_regn(hw, ALLOCFID); - hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); - - return 0; -} -EXPORT_SYMBOL(hermes_allocate); - -/* Set up a BAP to read a particular chunk of data from card's internal buffer. - * - * Returns: < 0 on internal failure (errno), 0 on success, >0 on error - * from firmware - * - * Callable from any context */ -static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset) -{ - int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; - int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; - int k; - u16 reg; - - /* Paranoia.. */ - if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) - return -EINVAL; - - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ((reg & HERMES_OFFSET_BUSY) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg & HERMES_OFFSET_BUSY) - return -ETIMEDOUT; - - /* Now we actually set up the transfer */ - hermes_write_reg(hw, sreg, id); - hermes_write_reg(hw, oreg, offset); - - /* Wait for the BAP to be ready */ - k = HERMES_BAP_BUSY_TIMEOUT; - reg = hermes_read_reg(hw, oreg); - while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { - k--; - udelay(1); - reg = hermes_read_reg(hw, oreg); - } - - if (reg != offset) { - printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " - "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, - (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", - reg, id, offset); - - if (reg & HERMES_OFFSET_BUSY) { - return -ETIMEDOUT; - } - - return -EIO; /* error or wrong offset */ - } - - return 0; -} - -/* Read a block of data from the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. len - * must be even. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, - u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if ( (len < 0) || (len % 2) ) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_read_words(hw, dreg, buf, len/2); - - out: - return err; -} -EXPORT_SYMBOL(hermes_bap_pread); - -/* Write a block of data to the chip's buffer, via the - * BAP. Synchronization/serialization is the caller's problem. - * - * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware - */ -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, - u16 id, u16 offset) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - - if (len < 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, id, offset); - if (err) - goto out; - - /* Actually do the transfer */ - hermes_write_bytes(hw, dreg, buf, len); - - out: - return err; -} -EXPORT_SYMBOL(hermes_bap_pwrite); - -/* Read a Length-Type-Value record from the card. - * - * If length is NULL, we ignore the length read from the card, and - * read the entire buffer regardless. This is useful because some of - * the configuration records appear to have incorrect lengths in - * practice. - * - * Callable from user or bh context. */ -int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, - u16 *length, void *buf) -{ - int err = 0; - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - u16 rlength, rtype; - unsigned nwords; - - if ( (bufsize < 0) || (bufsize % 2) ) - return -EINVAL; - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); - if (err) - return err; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - rlength = hermes_read_reg(hw, dreg); - - if (! rlength) - return -ENODATA; - - rtype = hermes_read_reg(hw, dreg); - - if (length) - *length = rlength; - - if (rtype != rid) - printk(KERN_WARNING "hermes @ %p: %s(): " - "rid (0x%04x) does not match type (0x%04x)\n", - hw->iobase, __func__, rid, rtype); - if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) - printk(KERN_WARNING "hermes @ %p: " - "Truncating LTV record from %d to %d bytes. " - "(rid=0x%04x, len=0x%04x)\n", hw->iobase, - HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); - - nwords = min((unsigned)rlength - 1, bufsize / 2); - hermes_read_words(hw, dreg, buf, nwords); - - return 0; -} -EXPORT_SYMBOL(hermes_read_ltv); - -int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, - u16 length, const void *value) -{ - int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; - int err = 0; - unsigned count; - - if (length == 0) - return -EINVAL; - - err = hermes_bap_seek(hw, bap, rid, 0); - if (err) - return err; - - hermes_write_reg(hw, dreg, length); - hermes_write_reg(hw, dreg, rid); - - count = length - 1; - - hermes_write_bytes(hw, dreg, value, count << 1); - - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, - rid, NULL); - - return err; -} -EXPORT_SYMBOL(hermes_write_ltv); - -static int __init init_hermes(void) -{ - return 0; -} - -static void __exit exit_hermes(void) -{ -} - -module_init(init_hermes); -module_exit(exit_hermes); diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h deleted file mode 100644 index 8b13c8f..0000000 --- a/drivers/net/wireless/hermes.h +++ /dev/null @@ -1,494 +0,0 @@ -/* hermes.h - * - * Driver core for the "Hermes" wireless MAC controller, as used in - * the Lucent Orinoco and Cabletron RoamAbout cards. It should also - * work on the hfa3841 and hfa3842 MAC controller chips used in the - * Prism I & II chipsets. - * - * This is not a complete driver, just low-level access routines for - * the MAC controller itself. - * - * Based on the prism2 driver from Absolute Value Systems' linux-wlan - * project, the Linux wvlan_cs driver, Lucent's HCF-Light - * (wvlan_hcf.c) library, and the NetBSD wireless driver. - * - * Copyright (C) 2000, David Gibson, Linuxcare Australia. - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * - * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * This file distributed under the GPL, version 2. - */ - -#ifndef _HERMES_H -#define _HERMES_H - -/* Notes on locking: - * - * As a module of low level hardware access routines, there is no - * locking. Users of this module should ensure that they serialize - * access to the hermes_t structure, and to the hardware -*/ - -#include -#include - -/* - * Limits and constants - */ -#define HERMES_ALLOC_LEN_MIN (4) -#define HERMES_ALLOC_LEN_MAX (2400) -#define HERMES_LTV_LEN_MAX (34) -#define HERMES_BAP_DATALEN_MAX (4096) -#define HERMES_BAP_OFFSET_MAX (4096) -#define HERMES_PORTID_MAX (7) -#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) -#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ -#define HERMES_PDA_RECS_MAX (200) /* a guess */ -#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ -#define HERMES_SCANRESULT_MAX (35) -#define HERMES_CHINFORESULT_MAX (8) -#define HERMES_MAX_MULTICAST (16) -#define HERMES_MAGIC (0x7d1f) - -/* - * Hermes register offsets - */ -#define HERMES_CMD (0x00) -#define HERMES_PARAM0 (0x02) -#define HERMES_PARAM1 (0x04) -#define HERMES_PARAM2 (0x06) -#define HERMES_STATUS (0x08) -#define HERMES_RESP0 (0x0A) -#define HERMES_RESP1 (0x0C) -#define HERMES_RESP2 (0x0E) -#define HERMES_INFOFID (0x10) -#define HERMES_RXFID (0x20) -#define HERMES_ALLOCFID (0x22) -#define HERMES_TXCOMPLFID (0x24) -#define HERMES_SELECT0 (0x18) -#define HERMES_OFFSET0 (0x1C) -#define HERMES_DATA0 (0x36) -#define HERMES_SELECT1 (0x1A) -#define HERMES_OFFSET1 (0x1E) -#define HERMES_DATA1 (0x38) -#define HERMES_EVSTAT (0x30) -#define HERMES_INTEN (0x32) -#define HERMES_EVACK (0x34) -#define HERMES_CONTROL (0x14) -#define HERMES_SWSUPPORT0 (0x28) -#define HERMES_SWSUPPORT1 (0x2A) -#define HERMES_SWSUPPORT2 (0x2C) -#define HERMES_AUXPAGE (0x3A) -#define HERMES_AUXOFFSET (0x3C) -#define HERMES_AUXDATA (0x3E) - -/* - * CMD register bitmasks - */ -#define HERMES_CMD_BUSY (0x8000) -#define HERMES_CMD_AINFO (0x7f00) -#define HERMES_CMD_MACPORT (0x0700) -#define HERMES_CMD_RECL (0x0100) -#define HERMES_CMD_WRITE (0x0100) -#define HERMES_CMD_PROGMODE (0x0300) -#define HERMES_CMD_CMDCODE (0x003f) - -/* - * STATUS register bitmasks - */ -#define HERMES_STATUS_RESULT (0x7f00) -#define HERMES_STATUS_CMDCODE (0x003f) - -/* - * OFFSET register bitmasks - */ -#define HERMES_OFFSET_BUSY (0x8000) -#define HERMES_OFFSET_ERR (0x4000) -#define HERMES_OFFSET_DATAOFF (0x0ffe) - -/* - * Event register bitmasks (INTEN, EVSTAT, EVACK) - */ -#define HERMES_EV_TICK (0x8000) -#define HERMES_EV_WTERR (0x4000) -#define HERMES_EV_INFDROP (0x2000) -#define HERMES_EV_INFO (0x0080) -#define HERMES_EV_DTIM (0x0020) -#define HERMES_EV_CMD (0x0010) -#define HERMES_EV_ALLOC (0x0008) -#define HERMES_EV_TXEXC (0x0004) -#define HERMES_EV_TX (0x0002) -#define HERMES_EV_RX (0x0001) - -/* - * Command codes - */ -/*--- Controller Commands ----------------------------*/ -#define HERMES_CMD_INIT (0x0000) -#define HERMES_CMD_ENABLE (0x0001) -#define HERMES_CMD_DISABLE (0x0002) -#define HERMES_CMD_DIAG (0x0003) - -/*--- Buffer Mgmt Commands ---------------------------*/ -#define HERMES_CMD_ALLOC (0x000A) -#define HERMES_CMD_TX (0x000B) - -/*--- Regulate Commands ------------------------------*/ -#define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQUIRE (0x0011) - -/*--- Configure Commands -----------------------------*/ -#define HERMES_CMD_ACCESS (0x0021) -#define HERMES_CMD_DOWNLD (0x0022) - -/*--- Serial I/O Commands ----------------------------*/ -#define HERMES_CMD_READMIF (0x0030) -#define HERMES_CMD_WRITEMIF (0x0031) - -/*--- Debugging Commands -----------------------------*/ -#define HERMES_CMD_TEST (0x0038) - - -/* Test command arguments */ -#define HERMES_TEST_SET_CHANNEL 0x0800 -#define HERMES_TEST_MONITOR 0x0b00 -#define HERMES_TEST_STOP 0x0f00 - -/* Authentication algorithms */ -#define HERMES_AUTH_OPEN 1 -#define HERMES_AUTH_SHARED_KEY 2 - -/* WEP settings */ -#define HERMES_WEP_PRIVACY_INVOKED 0x0001 -#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 -#define HERMES_WEP_HOST_ENCRYPT 0x0010 -#define HERMES_WEP_HOST_DECRYPT 0x0080 - -/* Symbol hostscan options */ -#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 -#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 -#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 -#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 - -/* - * Frame structures and constants - */ - -#define HERMES_DESCRIPTOR_OFFSET 0 -#define HERMES_802_11_OFFSET (14) -#define HERMES_802_3_OFFSET (14+32) -#define HERMES_802_2_OFFSET (14+32+14) -#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) -#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ -#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ -#define HERMES_RXSTAT_MSGTYPE (0xE000) -#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ - -/* Shift amount for key ID in RXSTAT and TXCTRL */ -#define HERMES_MIC_KEY_ID_SHIFT 11 - -struct hermes_tx_descriptor { - __le16 status; - __le16 reserved1; - __le16 reserved2; - __le32 sw_support; - u8 retry_count; - u8 tx_rate; - __le16 tx_control; -} __attribute__ ((packed)); - -#define HERMES_TXSTAT_RETRYERR (0x0001) -#define HERMES_TXSTAT_AGEDERR (0x0002) -#define HERMES_TXSTAT_DISCON (0x0004) -#define HERMES_TXSTAT_FORMERR (0x0008) - -#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ -#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ -#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ -#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ -#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ -#define HERMES_TXCTRL_ALT_RTRY (0x0020) - -/* Inquiry constants and data types */ - -#define HERMES_INQ_TALLIES (0xF100) -#define HERMES_INQ_SCAN (0xF101) -#define HERMES_INQ_CHANNELINFO (0xF102) -#define HERMES_INQ_HOSTSCAN (0xF103) -#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) -#define HERMES_INQ_LINKSTATUS (0xF200) -#define HERMES_INQ_SEC_STAT_AGERE (0xF202) - -struct hermes_tallies_frame { - __le16 TxUnicastFrames; - __le16 TxMulticastFrames; - __le16 TxFragments; - __le16 TxUnicastOctets; - __le16 TxMulticastOctets; - __le16 TxDeferredTransmissions; - __le16 TxSingleRetryFrames; - __le16 TxMultipleRetryFrames; - __le16 TxRetryLimitExceeded; - __le16 TxDiscards; - __le16 RxUnicastFrames; - __le16 RxMulticastFrames; - __le16 RxFragments; - __le16 RxUnicastOctets; - __le16 RxMulticastOctets; - __le16 RxFCSErrors; - __le16 RxDiscards_NoBuffer; - __le16 TxDiscardsWrongSA; - __le16 RxWEPUndecryptable; - __le16 RxMsgInMsgFragments; - __le16 RxMsgInBadMsgFragments; - /* Those last are probably not available in very old firmwares */ - __le16 RxDiscards_WEPICVError; - __le16 RxDiscards_WEPExcluded; -} __attribute__ ((packed)); - -/* Grabbed from wlan-ng - Thanks Mark... - Jean II - * This is the result of a scan inquiry command */ -/* Structure describing info about an Access Point */ -struct prism2_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - u8 rates[10]; /* Bit rate supported */ - __le16 proberesp_rate; /* Data rate of the response frame */ - __le16 atim; /* ATIM window time, Kus (hostscan only) */ -} __attribute__ ((packed)); - -/* Same stuff for the Lucent/Agere card. - * Thanks to h1kari - Jean II */ -struct agere_scan_apinfo { - __le16 channel; /* Channel where the AP sits */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ -} __attribute__ ((packed)); - -/* Moustafa: Scan structure for Symbol cards */ -struct symbol_scan_apinfo { - u8 channel; /* Channel where the AP sits */ - u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ - __le16 noise; /* Noise level */ - __le16 level; /* Signal level */ - u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ - __le16 beacon_interv; /* Beacon interval */ - __le16 capabilities; /* Capabilities */ - /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ - __le16 essid_len; /* ESSID length */ - u8 essid[32]; /* ESSID of the network */ - __le16 rates[5]; /* Bit rate supported */ - __le16 basic_rates; /* Basic rates bitmask */ - u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ - u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ -} __attribute__ ((packed)); - -union hermes_scan_info { - struct agere_scan_apinfo a; - struct prism2_scan_apinfo p; - struct symbol_scan_apinfo s; -}; - -/* Extended scan struct for HERMES_INQ_CHANNELINFO. - * wl_lkm calls this an ACS scan (Automatic Channel Select). - * Keep out of union hermes_scan_info because it is much bigger than - * the older scan structures. */ -struct agere_ext_scan_info { - __le16 reserved0; - - u8 noise; - u8 level; - u8 rx_flow; - u8 rate; - __le16 reserved1[2]; - - __le16 frame_control; - __le16 dur_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - __le16 sequence; - u8 addr4[ETH_ALEN]; - - __le16 data_length; - - /* Next 3 fields do not get filled in. */ - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - __le16 len_type; - - __le64 timestamp; - __le16 beacon_interval; - __le16 capabilities; - u8 data[316]; -} __attribute__ ((packed)); - -#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) -#define HERMES_LINKSTATUS_CONNECTED (0x0001) -#define HERMES_LINKSTATUS_DISCONNECTED (0x0002) -#define HERMES_LINKSTATUS_AP_CHANGE (0x0003) -#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004) -#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005) -#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) - -struct hermes_linkstatus { - __le16 linkstatus; /* Link status */ -} __attribute__ ((packed)); - -struct hermes_response { - u16 status, resp0, resp1, resp2; -}; - -/* "ID" structure - used for ESSID and station nickname */ -struct hermes_idstring { - __le16 len; - __le16 val[16]; -} __attribute__ ((packed)); - -struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)); - -/* Timeouts */ -#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ - -/* Basic control structure */ -typedef struct hermes { - void __iomem *iobase; - int reg_spacing; -#define HERMES_16BIT_REGSPACING 0 -#define HERMES_32BIT_REGSPACING 1 - u16 inten; /* Which interrupts should be enabled? */ -} hermes_t; - -/* Register access convenience macros */ -#define hermes_read_reg(hw, off) \ - (ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing ))) -#define hermes_write_reg(hw, off, val) \ - (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) -#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) -#define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) - -/* Function prototypes */ -void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing); -int hermes_init(hermes_t *hw); -int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, - struct hermes_response *resp); -int hermes_doicmd_wait(hermes_t *hw, u16 cmd, - u16 parm0, u16 parm1, u16 parm2, - struct hermes_response *resp); -int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); - -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, - u16 id, u16 offset); -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, - u16 id, u16 offset); -int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, - u16 *length, void *buf); -int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, - u16 length, const void *value); - -/* Inline functions */ - -static inline int hermes_present(hermes_t *hw) -{ - return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; -} - -static inline void hermes_set_irqmask(hermes_t *hw, u16 events) -{ - hw->inten = events; - hermes_write_regn(hw, INTEN, events); -} - -static inline int hermes_enable_port(hermes_t *hw, int port) -{ - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), - 0, NULL); -} - -static inline int hermes_disable_port(hermes_t *hw, int port) -{ - return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), - 0, NULL); -} - -/* Initiate an INQUIRE command (tallies or scan). The result will come as an - * information frame in __orinoco_ev_info() */ -static inline int hermes_inquire(hermes_t *hw, u16 rid) -{ - return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL); -} - -#define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 ) -#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) - -/* Note that for the next two, the count is in 16-bit words, not bytes */ -static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count) -{ - off = off << hw->reg_spacing; - ioread16_rep(hw->iobase + off, buf, count); -} - -static inline void hermes_write_bytes(struct hermes *hw, int off, - const char *buf, unsigned count) -{ - off = off << hw->reg_spacing; - iowrite16_rep(hw->iobase + off, buf, count >> 1); - if (unlikely(count & 1)) - iowrite8(buf[count - 1], hw->iobase + off); -} - -static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) -{ - unsigned i; - - off = off << hw->reg_spacing; - - for (i = 0; i < count; i++) - iowrite16(0, hw->iobase + off); -} - -#define HERMES_READ_RECORD(hw, bap, rid, buf) \ - (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) -#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ - (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) - -static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) -{ - __le16 rec; - int err; - - err = HERMES_READ_RECORD(hw, bap, rid, &rec); - *word = le16_to_cpu(rec); - return err; -} - -static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word) -{ - __le16 rec = cpu_to_le16(word); - return HERMES_WRITE_RECORD(hw, bap, rid, &rec); -} - -#endif /* _HERMES_H */ diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c deleted file mode 100644 index d8c626e..0000000 --- a/drivers/net/wireless/hermes_dld.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Hermes download helper driver. - * - * This could be entirely merged into hermes.c. - * - * I'm keeping it separate to minimise the amount of merging between - * kernel upgrades. It also means the memory overhead for drivers that - * don't need firmware download low. - * - * This driver: - * - is capable of writing to the volatile area of the hermes device - * - is currently not capable of writing to non-volatile areas - * - provide helpers to identify and update plugin data - * - is not capable of interpreting a fw image directly. That is up to - * the main card driver. - * - deals with Hermes I devices. It can probably be modified to deal - * with Hermes II devices - * - * Copyright (C) 2007, David Kilroy - * - * Plug data code slightly modified from spectrum_cs driver - * Copyright (C) 2002-2005 Pavel Roskin - * Portions based on information in wl_lkm_718 Agere driver - * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#include -#include -#include "hermes.h" -#include "hermes_dld.h" - -MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset"); -MODULE_AUTHOR("David Kilroy "); -MODULE_LICENSE("Dual MPL/GPL"); - -#define PFX "hermes_dld: " - -/* - * AUX port access. To unlock the AUX port write the access keys to the - * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL - * register. Then read it and make sure it's HERMES_AUX_ENABLED. - */ -#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ -#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ -#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ -#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ - -#define HERMES_AUX_PW0 0xFE01 -#define HERMES_AUX_PW1 0xDC23 -#define HERMES_AUX_PW2 0xBA45 - -/* HERMES_CMD_DOWNLD */ -#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) -#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) - -/* End markers used in dblocks */ -#define PDI_END 0x00000000 /* End of PDA */ -#define BLOCK_END 0xFFFFFFFF /* Last image block */ -#define TEXT_END 0x1A /* End of text header */ - -/* - * PDA == Production Data Area - * - * In principle, the max. size of the PDA is is 4096 words. Currently, - * however, only about 500 bytes of this area are used. - * - * Some USB implementations can't handle sizes in excess of 1016. Note - * that PDA is not actually used in those USB environments, but may be - * retrieved by common code. - */ -#define MAX_PDA_SIZE 1000 - -/* Limit the amout we try to download in a single shot. - * Size is in bytes. - */ -#define MAX_DL_SIZE 1024 -#define LIMIT_PROGRAM_SIZE 0 - -/* - * The following structures have little-endian fields denoted by - * the leading underscore. Don't access them directly - use inline - * functions defined below. - */ - -/* - * The binary image to be downloaded consists of series of data blocks. - * Each block has the following structure. - */ -struct dblock { - __le32 addr; /* adapter address where to write the block */ - __le16 len; /* length of the data only, in bytes */ - char data[0]; /* data to be written */ -} __attribute__ ((packed)); - -/* - * Plug Data References are located in in the image after the last data - * block. They refer to areas in the adapter memory where the plug data - * items with matching ID should be written. - */ -struct pdr { - __le32 id; /* record ID */ - __le32 addr; /* adapter address where to write the data */ - __le32 len; /* expected length of the data, in bytes */ - char next[0]; /* next PDR starts here */ -} __attribute__ ((packed)); - -/* - * Plug Data Items are located in the EEPROM read from the adapter by - * primary firmware. They refer to the device-specific data that should - * be plugged into the secondary firmware. - */ -struct pdi { - __le16 len; /* length of ID and data, in words */ - __le16 id; /* record ID */ - char data[0]; /* plug data */ -} __attribute__ ((packed)); - -/*** FW data block access functions ***/ - -static inline u32 -dblock_addr(const struct dblock *blk) -{ - return le32_to_cpu(blk->addr); -} - -static inline u32 -dblock_len(const struct dblock *blk) -{ - return le16_to_cpu(blk->len); -} - -/*** PDR Access functions ***/ - -static inline u32 -pdr_id(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->id); -} - -static inline u32 -pdr_addr(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->addr); -} - -static inline u32 -pdr_len(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->len); -} - -/*** PDI Access functions ***/ - -static inline u32 -pdi_id(const struct pdi *pdi) -{ - return le16_to_cpu(pdi->id); -} - -/* Return length of the data only, in bytes */ -static inline u32 -pdi_len(const struct pdi *pdi) -{ - return 2 * (le16_to_cpu(pdi->len) - 1); -} - -/*** Hermes AUX control ***/ - -static inline void -hermes_aux_setaddr(hermes_t *hw, u32 addr) -{ - hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); - hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); -} - -static inline int -hermes_aux_control(hermes_t *hw, int enabled) -{ - int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; - int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; - int i; - - /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) - return 0; - - hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); - hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); - hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, action); - - for (i = 0; i < 20; i++) { - udelay(10); - if (hermes_read_reg(hw, HERMES_CONTROL) == - desired_state) - return 0; - } - - return -EBUSY; -} - -/*** Plug Data Functions ***/ - -/* - * Scan PDR for the record with the specified RECORD_ID. - * If it's not found, return NULL. - */ -static struct pdr * -hermes_find_pdr(struct pdr *first_pdr, u32 record_id) -{ - struct pdr *pdr = first_pdr; - void *end = (void *)first_pdr + MAX_PDA_SIZE; - - while (((void *)pdr < end) && - (pdr_id(pdr) != PDI_END)) { - /* - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - return NULL; - - /* If the record ID matches, we are done */ - if (pdr_id(pdr) == record_id) - return pdr; - - pdr = (struct pdr *) pdr->next; - } - return NULL; -} - -/* Scan production data items for a particular entry */ -static struct pdi * -hermes_find_pdi(struct pdi *first_pdi, u32 record_id) -{ - struct pdi *pdi = first_pdi; - - while (pdi_id(pdi) != PDI_END) { - - /* If the record ID matches, we are done */ - if (pdi_id(pdi) == record_id) - return pdi; - - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return NULL; -} - -/* Process one Plug Data Item - find corresponding PDR and plug it */ -static int -hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) -{ - struct pdr *pdr; - - /* Find the PDR corresponding to this PDI */ - pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); - - /* No match is found, safe to ignore */ - if (!pdr) - return 0; - - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) != pdr_len(pdr)) - return -EINVAL; - - /* do the actual plugging */ - hermes_aux_setaddr(hw, pdr_addr(pdr)); - hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); - - return 0; -} - -/* Read PDA from the adapter */ -int hermes_read_pda(hermes_t *hw, - __le16 *pda, - u32 pda_addr, - u16 pda_len, - int use_eeprom) /* can we get this into hw? */ -{ - int ret; - u16 pda_size; - u16 data_len = pda_len; - __le16 *data = pda; - - if (use_eeprom) { - /* PDA of spectrum symbol is in eeprom */ - - /* Issue command to read EEPROM */ - ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; - } else { - /* wl_lkm does not include PDA size in the PDA area. - * We will pad the information into pda, so other routines - * don't have to be modified */ - pda[0] = cpu_to_le16(pda_len - 2); - /* Includes CFG_PROD_DATA but not itself */ - pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ - data_len = pda_len - 4; - data = pda + 2; - } - - /* Open auxiliary port */ - ret = hermes_aux_control(hw, 1); - printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret); - if (ret) - return ret; - - /* read PDA from EEPROM */ - hermes_aux_setaddr(hw, pda_addr); - hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); - - /* Close aux port */ - ret = hermes_aux_control(hw, 0); - printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret); - - /* Check PDA length */ - pda_size = le16_to_cpu(pda[0]); - printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n", - pda_size, pda_len); - if (pda_size > pda_len) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL(hermes_read_pda); - -/* Parse PDA and write the records into the adapter - * - * Attempt to write every records that is in the specified pda - * which also has a valid production data record for the firmware. - */ -int hermes_apply_pda(hermes_t *hw, - const char *first_pdr, - const __le16 *pda) -{ - int ret; - const struct pdi *pdi; - struct pdr *pdr; - - pdr = (struct pdr *) first_pdr; - - /* Go through every PDI and plug them into the adapter */ - pdi = (const struct pdi *) (pda + 2); - while (pdi_id(pdi) != PDI_END) { - ret = hermes_plug_pdi(hw, pdr, pdi); - if (ret) - return ret; - - /* Increment to the next PDI */ - pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return 0; -} -EXPORT_SYMBOL(hermes_apply_pda); - -/* Identify the total number of bytes in all blocks - * including the header data. - */ -size_t -hermes_blocks_length(const char *first_block) -{ - const struct dblock *blk = (const struct dblock *) first_block; - int total_len = 0; - int len; - - /* Skip all blocks to locate Plug Data References - * (Spectrum CS) */ - while (dblock_addr(blk) != BLOCK_END) { - len = dblock_len(blk); - total_len += sizeof(*blk) + len; - blk = (struct dblock *) &blk->data[len]; - } - - return total_len; -} -EXPORT_SYMBOL(hermes_blocks_length); - -/*** Hermes programming ***/ - -/* About to start programming data (Hermes I) - * offset is the entry point - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -int hermesi_program_init(hermes_t *hw, u32 offset) -{ - int err; - - /* Disable interrupts?*/ - /*hw->inten = 0x0;*/ - /*hermes_write_regn(hw, INTEN, 0);*/ - /*hermes_set_irqmask(hw, 0);*/ - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Using doicmd_wait rather than docmd_wait */ - err = hermes_doicmd_wait(hw, - 0x0100 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hermes_doicmd_wait(hw, - 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - if (err) - return err; - - err = hermes_aux_control(hw, 1); - printk(KERN_DEBUG PFX "AUX enable returned %d\n", err); - - if (err) - return err; - - printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); - err = hermes_doicmd_wait(hw, - HERMES_PROGRAM_ENABLE_VOLATILE, - offset & 0xFFFFu, - offset >> 16, - 0, - NULL); - printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n", - err); - - return err; -} -EXPORT_SYMBOL(hermesi_program_init); - -/* Done programming data (Hermes I) - * - * Spectrum_cs' Symbol fw does not require this - * wl_lkm Agere fw does - * Don't know about intersil - */ -int hermesi_program_end(hermes_t *hw) -{ - struct hermes_response resp; - int rc = 0; - int err; - - rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); - - printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, " - "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", - rc, resp.resp0, resp.resp1, resp.resp2); - - if ((rc == 0) && - ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) - rc = -EIO; - - err = hermes_aux_control(hw, 0); - printk(KERN_DEBUG PFX "AUX disable returned %d\n", err); - - /* Acknowledge any outstanding command */ - hermes_write_regn(hw, EVACK, 0xFFFF); - - /* Reinitialise, ignoring return */ - (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT, - 0, 0, 0, NULL); - - return rc ? rc : err; -} -EXPORT_SYMBOL(hermesi_program_end); - -/* Program the data blocks */ -int hermes_program(hermes_t *hw, const char *first_block, const char *end) -{ - const struct dblock *blk; - u32 blkaddr; - u32 blklen; -#if LIMIT_PROGRAM_SIZE - u32 addr; - u32 len; -#endif - - blk = (const struct dblock *) first_block; - - if ((const char *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - - while ((blkaddr != BLOCK_END) && - (((const char *) blk + blklen) <= end)) { - printk(KERN_DEBUG PFX - "Programming block of length %d to address 0x%08x\n", - blklen, blkaddr); - -#if !LIMIT_PROGRAM_SIZE - /* wl_lkm driver splits this into writes of 2000 bytes */ - hermes_aux_setaddr(hw, blkaddr); - hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, - blklen); -#else - len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE; - addr = blkaddr; - - while (addr < (blkaddr + blklen)) { - printk(KERN_DEBUG PFX - "Programming subblock of length %d " - "to address 0x%08x. Data @ %p\n", - len, addr, &blk->data[addr - blkaddr]); - - hermes_aux_setaddr(hw, addr); - hermes_write_bytes(hw, HERMES_AUXDATA, - &blk->data[addr - blkaddr], - len); - - addr += len; - len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ? - (blkaddr + blklen - addr) : MAX_DL_SIZE; - } -#endif - blk = (const struct dblock *) &blk->data[blklen]; - - if ((const char *) blk > (end - sizeof(*blk))) - return -EIO; - - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - } - return 0; -} -EXPORT_SYMBOL(hermes_program); - -static int __init init_hermes_dld(void) -{ - return 0; -} - -static void __exit exit_hermes_dld(void) -{ -} - -module_init(init_hermes_dld); -module_exit(exit_hermes_dld); - -/*** Default plugging data for Hermes I ***/ -/* Values from wl_lkm_718/hcf/dhf.c */ - -#define DEFINE_DEFAULT_PDR(pid, length, data) \ -static const struct { \ - __le16 len; \ - __le16 id; \ - u8 val[length]; \ -} __attribute__ ((packed)) default_pdr_data_##pid = { \ - __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ - sizeof(__le16)) - 1), \ - __constant_cpu_to_le16(pid), \ - data \ -} - -#define DEFAULT_PDR(pid) default_pdr_data_##pid - -/* HWIF Compatiblity */ -DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); - -/* PPPPSign */ -DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); - -/* PPPPProf */ -DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); - -/* Antenna diversity */ -DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); - -/* Modem VCO band Set-up */ -DEFINE_DEFAULT_PDR(0x0160, 28, - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00"); - -/* Modem Rx Gain Table Values */ -DEFINE_DEFAULT_PDR(0x0161, 256, - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3F\01\x3F\x01\x3F\x01" - "\x3F\x01\x3E\01\x3E\x01\x3D\x01" - "\x3D\x01\x3C\01\x3C\x01\x3B\x01" - "\x3B\x01\x3A\01\x3A\x01\x39\x01" - "\x39\x01\x38\01\x38\x01\x37\x01" - "\x37\x01\x36\01\x36\x01\x35\x01" - "\x35\x01\x34\01\x34\x01\x33\x01" - "\x33\x01\x32\x01\x32\x01\x31\x01" - "\x31\x01\x30\x01\x30\x01\x7B\x01" - "\x7B\x01\x7A\x01\x7A\x01\x79\x01" - "\x79\x01\x78\x01\x78\x01\x77\x01" - "\x77\x01\x76\x01\x76\x01\x75\x01" - "\x75\x01\x74\x01\x74\x01\x73\x01" - "\x73\x01\x72\x01\x72\x01\x71\x01" - "\x71\x01\x70\x01\x70\x01\x68\x01" - "\x68\x01\x67\x01\x67\x01\x66\x01" - "\x66\x01\x65\x01\x65\x01\x57\x01" - "\x57\x01\x56\x01\x56\x01\x55\x01" - "\x55\x01\x54\x01\x54\x01\x53\x01" - "\x53\x01\x52\x01\x52\x01\x51\x01" - "\x51\x01\x50\x01\x50\x01\x48\x01" - "\x48\x01\x47\x01\x47\x01\x46\x01" - "\x46\x01\x45\x01\x45\x01\x44\x01" - "\x44\x01\x43\x01\x43\x01\x42\x01" - "\x42\x01\x41\x01\x41\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01" - "\x40\x01\x40\x01\x40\x01\x40\x01"); - -/* Write PDA according to certain rules. - * - * For every production data record, look for a previous setting in - * the pda, and use that. - * - * For certain records, use defaults if they are not found in pda. - */ -int hermes_apply_pda_with_defaults(hermes_t *hw, - const char *first_pdr, - const __le16 *pda) -{ - const struct pdr *pdr = (const struct pdr *) first_pdr; - struct pdi *first_pdi = (struct pdi *) &pda[2]; - struct pdi *pdi; - struct pdi *default_pdi = NULL; - struct pdi *outdoor_pdi; - void *end = (void *)first_pdr + MAX_PDA_SIZE; - int record_id; - - while (((void *)pdr < end) && - (pdr_id(pdr) != PDI_END)) { - /* - * For spectrum_cs firmwares, - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - break; - record_id = pdr_id(pdr); - - pdi = hermes_find_pdi(first_pdi, record_id); - if (pdi) - printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", - record_id, pdi); - - switch (record_id) { - case 0x110: /* Modem REFDAC values */ - case 0x120: /* Modem VGDAC values */ - outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); - default_pdi = NULL; - if (outdoor_pdi) { - pdi = outdoor_pdi; - printk(KERN_DEBUG PFX - "Using outdoor record 0x%04x at %p\n", - record_id + 1, pdi); - } - break; - case 0x5: /* HWIF Compatiblity */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); - break; - case 0x108: /* PPPPSign */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); - break; - case 0x109: /* PPPPProf */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); - break; - case 0x150: /* Antenna diversity */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); - break; - case 0x160: /* Modem VCO band Set-up */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); - break; - case 0x161: /* Modem Rx Gain Table Values */ - default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); - break; - default: - default_pdi = NULL; - break; - } - if (!pdi && default_pdi) { - /* Use default */ - pdi = default_pdi; - printk(KERN_DEBUG PFX - "Using default record 0x%04x at %p\n", - record_id, pdi); - } - - if (pdi) { - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) == pdr_len(pdr)) { - /* do the actual plugging */ - hermes_aux_setaddr(hw, pdr_addr(pdr)); - hermes_write_bytes(hw, HERMES_AUXDATA, - pdi->data, pdi_len(pdi)); - } - } - - pdr++; - } - return 0; -} -EXPORT_SYMBOL(hermes_apply_pda_with_defaults); diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h deleted file mode 100644 index 6fcb262..0000000 --- a/drivers/net/wireless/hermes_dld.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007, David Kilroy - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ -#ifndef _HERMES_DLD_H -#define _HERMES_DLD_H - -#include "hermes.h" - -int hermesi_program_init(hermes_t *hw, u32 offset); -int hermesi_program_end(hermes_t *hw); -int hermes_program(hermes_t *hw, const char *first_block, const char *end); - -int hermes_read_pda(hermes_t *hw, - __le16 *pda, - u32 pda_addr, - u16 pda_len, - int use_eeprom); -int hermes_apply_pda(hermes_t *hw, - const char *first_pdr, - const __le16 *pda); -int hermes_apply_pda_with_defaults(hermes_t *hw, - const char *first_pdr, - const __le16 *pda); - -size_t hermes_blocks_length(const char *first_block); - -#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h deleted file mode 100644 index 42eb67d..0000000 --- a/drivers/net/wireless/hermes_rid.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _HERMES_RID_H -#define _HERMES_RID_H - -/* - * Configuration RIDs - */ -#define HERMES_RID_CNFPORTTYPE 0xFC00 -#define HERMES_RID_CNFOWNMACADDR 0xFC01 -#define HERMES_RID_CNFDESIREDSSID 0xFC02 -#define HERMES_RID_CNFOWNCHANNEL 0xFC03 -#define HERMES_RID_CNFOWNSSID 0xFC04 -#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 -#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 -#define HERMES_RID_CNFMAXDATALEN 0xFC07 -#define HERMES_RID_CNFWDSADDRESS 0xFC08 -#define HERMES_RID_CNFPMENABLED 0xFC09 -#define HERMES_RID_CNFPMEPS 0xFC0A -#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B -#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C -#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D -#define HERMES_RID_CNFOWNNAME 0xFC0E -#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 -#define HERMES_RID_CNFWDSADDRESS1 0xFC11 -#define HERMES_RID_CNFWDSADDRESS2 0xFC12 -#define HERMES_RID_CNFWDSADDRESS3 0xFC13 -#define HERMES_RID_CNFWDSADDRESS4 0xFC14 -#define HERMES_RID_CNFWDSADDRESS5 0xFC15 -#define HERMES_RID_CNFWDSADDRESS6 0xFC16 -#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 -#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 -#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 -#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 -#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 -#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 -#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 -#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 -#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 -#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 -#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 -#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 -#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 -#define HERMES_RID_CNFAUTHENTICATION 0xFC2A -#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B -#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B -#define HERMES_RID_CNFTXCONTROL 0xFC2C -#define HERMES_RID_CNFROAMINGMODE 0xFC2D -#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E -#define HERMES_RID_CNFRCVCRCERROR 0xFC30 -#define HERMES_RID_CNFMMLIFE 0xFC31 -#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 -#define HERMES_RID_CNFBEACONINT 0xFC33 -#define HERMES_RID_CNFAPPCFINFO 0xFC34 -#define HERMES_RID_CNFSTAPCFINFO 0xFC35 -#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 -#define HERMES_RID_CNFTIMCTRL 0xFC40 -#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 -#define HERMES_RID_CNFENHSECURITY 0xFC43 -#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 -#define HERMES_RID_CNFCREATEIBSS 0xFC81 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 -#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 -#define HERMES_RID_CNFTXRATECONTROL 0xFC84 -#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 -#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A -#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 -#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 -#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 -#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 -#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 -#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A -#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B -#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C -#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D -#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB -#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 -#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 -#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 -#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 -#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 -#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 -#define HERMES_RID_CNFBASICRATES 0xFCB3 -#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 -#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 -#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 -#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 -#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 -#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 -#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 -#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA -#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB -#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 -#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 -#define HERMES_RID_CNFTICKTIME 0xFCE0 -#define HERMES_RID_CNFSCANREQUEST 0xFCE1 -#define HERMES_RID_CNFJOINREQUEST 0xFCE2 -#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 -#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 -#define HERMES_RID_CNFHOSTSCAN 0xFCE5 - -/* - * Information RIDs - */ -#define HERMES_RID_MAXLOADTIME 0xFD00 -#define HERMES_RID_DOWNLOADBUFFER 0xFD01 -#define HERMES_RID_PRIID 0xFD02 -#define HERMES_RID_PRISUPRANGE 0xFD03 -#define HERMES_RID_CFIACTRANGES 0xFD04 -#define HERMES_RID_NICSERNUM 0xFD0A -#define HERMES_RID_NICID 0xFD0B -#define HERMES_RID_MFISUPRANGE 0xFD0C -#define HERMES_RID_CFISUPRANGE 0xFD0D -#define HERMES_RID_CHANNELLIST 0xFD10 -#define HERMES_RID_REGULATORYDOMAINS 0xFD11 -#define HERMES_RID_TEMPTYPE 0xFD12 -#define HERMES_RID_CIS 0xFD13 -#define HERMES_RID_STAID 0xFD20 -#define HERMES_RID_STASUPRANGE 0xFD21 -#define HERMES_RID_MFIACTRANGES 0xFD22 -#define HERMES_RID_CFIACTRANGES2 0xFD23 -#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 -#define HERMES_RID_PORTSTATUS 0xFD40 -#define HERMES_RID_CURRENTSSID 0xFD41 -#define HERMES_RID_CURRENTBSSID 0xFD42 -#define HERMES_RID_COMMSQUALITY 0xFD43 -#define HERMES_RID_CURRENTTXRATE 0xFD44 -#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 -#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 -#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 -#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 -#define HERMES_RID_LONGRETRYLIMIT 0xFD49 -#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A -#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B -#define HERMES_RID_CFPOLLABLE 0xFD4C -#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D -#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F -#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 -#define HERMES_RID_CURRENTTXRATE1 0xFD80 -#define HERMES_RID_CURRENTTXRATE2 0xFD81 -#define HERMES_RID_CURRENTTXRATE3 0xFD82 -#define HERMES_RID_CURRENTTXRATE4 0xFD83 -#define HERMES_RID_CURRENTTXRATE5 0xFD84 -#define HERMES_RID_CURRENTTXRATE6 0xFD85 -#define HERMES_RID_OWNMACADDR 0xFD86 -#define HERMES_RID_SCANRESULTSTABLE 0xFD88 -#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 -#define HERMES_RID_CURRENT_WPA_IE 0xFD8A -#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B -#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C -#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D -#define HERMES_RID_TXQUEUEEMPTY 0xFD91 -#define HERMES_RID_PHYTYPE 0xFDC0 -#define HERMES_RID_CURRENTCHANNEL 0xFDC1 -#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 -#define HERMES_RID_CCAMODE 0xFDC3 -#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 -#define HERMES_RID_BUILDSEQ 0xFFFE -#define HERMES_RID_FWID 0xFFFF - -#endif diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c deleted file mode 100644 index f4ea08f..0000000 --- a/drivers/net/wireless/orinoco.c +++ /dev/null @@ -1,6032 +0,0 @@ -/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c) - * - * A driver for Hermes or Prism 2 chipset based PCMCIA wireless - * adaptors, with Lucent/Agere, Intersil or Symbol firmware. - * - * Current maintainers (as of 29 September 2003) are: - * Pavel Roskin - * and David Gibson - * - * (C) Copyright David Gibson, IBM Corporation 2001-2003. - * Copyright (C) 2000 David Gibson, Linuxcare Australia. - * With some help from : - * Copyright (C) 2001 Jean Tourrilhes, HP Labs - * Copyright (C) 2001 Benjamin Herrenschmidt - * - * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 - * - * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus - * http://www.stud.fh-dortmund.de/~andy/wvlan/ - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David - * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights - * Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. */ - -/* - * TODO - * o Handle de-encapsulation within network layer, provide 802.11 - * headers (patch from Thomas 'Dent' Mirlacher) - * o Fix possible races in SPY handling. - * o Disconnect wireless extensions from fundamental configuration. - * o (maybe) Software WEP support (patch from Stano Meduna). - * o (maybe) Use multiple Tx buffers - driver handling queue - * rather than firmware. - */ - -/* Locking and synchronization: - * - * The basic principle is that everything is serialized through a - * single spinlock, priv->lock. The lock is used in user, bh and irq - * context, so when taken outside hardirq context it should always be - * taken with interrupts disabled. The lock protects both the - * hardware and the struct orinoco_private. - * - * Another flag, priv->hw_unavailable indicates that the hardware is - * unavailable for an extended period of time (e.g. suspended, or in - * the middle of a hard reset). This flag is protected by the - * spinlock. All code which touches the hardware should check the - * flag after taking the lock, and if it is set, give up on whatever - * they are doing and drop the lock again. The orinoco_lock() - * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is non-zero). - */ - -#define DRIVER_NAME "orinoco" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "hermes_rid.h" -#include "hermes_dld.h" -#include "orinoco.h" - -/********************************************************************/ -/* Module information */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin & David Gibson "); -MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Level of debugging. Used in the macros in orinoco.h */ -#ifdef ORINOCO_DEBUG -int orinoco_debug = ORINOCO_DEBUG; -module_param(orinoco_debug, int, 0644); -MODULE_PARM_DESC(orinoco_debug, "Debug level"); -EXPORT_SYMBOL(orinoco_debug); -#endif - -static int suppress_linkstatus; /* = 0 */ -module_param(suppress_linkstatus, bool, 0644); -MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); -static int ignore_disconnect; /* = 0 */ -module_param(ignore_disconnect, int, 0644); -MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer"); - -static int force_monitor; /* = 0 */ -module_param(force_monitor, int, 0644); -MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); - -/********************************************************************/ -/* Compile time configuration and compatibility stuff */ -/********************************************************************/ - -/* We do this this way to avoid ifdefs in the actual code */ -#ifdef WIRELESS_SPY -#define SPY_NUMBER(priv) (priv->spy_data.spy_number) -#else -#define SPY_NUMBER(priv) 0 -#endif /* WIRELESS_SPY */ - -/********************************************************************/ -/* Internal constants */ -/********************************************************************/ - -/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ -static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) - -#define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) - -#define SYMBOL_MAX_VER_LEN (14) -#define USER_BAP 0 -#define IRQ_BAP 1 -#define MAX_IRQLOOPS_PER_IRQ 10 -#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of - * how many events the - * device could - * legitimately generate */ -#define SMALL_KEY_SIZE 5 -#define LARGE_KEY_SIZE 13 -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ - -#define DUMMY_FID 0xFFFF - -/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ - HERMES_MAX_MULTICAST : 0)*/ -#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) - -#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ - | HERMES_EV_TX | HERMES_EV_TXEXC \ - | HERMES_EV_WTERR | HERMES_EV_INFO \ - | HERMES_EV_INFDROP ) - -#define MAX_RID_LEN 1024 - -static const struct iw_handler_def orinoco_handler_def; -static const struct ethtool_ops orinoco_ethtool_ops; - -/********************************************************************/ -/* Data tables */ -/********************************************************************/ - -/* The frequency of each channel in MHz */ -static const long channel_frequency[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 -}; -#define NUM_CHANNELS ARRAY_SIZE(channel_frequency) - -/* This tables gives the actual meanings of the bitrate IDs returned - * by the firmware. */ -static struct { - int bitrate; /* in 100s of kilobits */ - int automatic; - u16 agere_txratectrl; - u16 intersil_txratectrl; -} bitrate_table[] = { - {110, 1, 3, 15}, /* Entry 0 is the default */ - {10, 0, 1, 1}, - {10, 1, 1, 1}, - {20, 0, 2, 2}, - {20, 1, 6, 3}, - {55, 0, 4, 4}, - {55, 1, 7, 7}, - {110, 0, 5, 8}, -}; -#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) - -/********************************************************************/ -/* Data types */ -/********************************************************************/ - -/* Beginning of the Tx descriptor, used in TxExc handling */ -struct hermes_txexc_data { - struct hermes_tx_descriptor desc; - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; -} __attribute__ ((packed)); - -/* Rx frame header except compatibility 802.3 header */ -struct hermes_rx_descriptor { - /* Control */ - __le16 status; - __le32 time; - u8 silence; - u8 signal; - u8 rate; - u8 rxflow; - __le32 reserved; - - /* 802.11 header */ - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - - /* Data length */ - __le16 data_len; -} __attribute__ ((packed)); - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int __orinoco_program_rids(struct net_device *dev); -static void __orinoco_set_multicast_list(struct net_device *dev); - -/********************************************************************/ -/* Michael MIC crypto setup */ -/********************************************************************/ -#define MICHAEL_MIC_LEN 8 -static int orinoco_mic_init(struct orinoco_private *priv) -{ - priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); - if (IS_ERR(priv->tx_tfm_mic)) { - printk(KERN_DEBUG "orinoco_mic_init: could not allocate " - "crypto API michael_mic\n"); - priv->tx_tfm_mic = NULL; - return -ENOMEM; - } - - priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); - if (IS_ERR(priv->rx_tfm_mic)) { - printk(KERN_DEBUG "orinoco_mic_init: could not allocate " - "crypto API michael_mic\n"); - priv->rx_tfm_mic = NULL; - return -ENOMEM; - } - - return 0; -} - -static void orinoco_mic_free(struct orinoco_private *priv) -{ - if (priv->tx_tfm_mic) - crypto_free_hash(priv->tx_tfm_mic); - if (priv->rx_tfm_mic) - crypto_free_hash(priv->rx_tfm_mic); -} - -static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, - u8 *da, u8 *sa, u8 priority, - u8 *data, size_t data_len, u8 *mic) -{ - struct hash_desc desc; - struct scatterlist sg[2]; - u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ - - if (tfm_michael == NULL) { - printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); - return -1; - } - - /* Copy header into buffer. We need the padding on the end zeroed */ - memcpy(&hdr[0], da, ETH_ALEN); - memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); - hdr[ETH_ALEN*2] = priority; - hdr[ETH_ALEN*2+1] = 0; - hdr[ETH_ALEN*2+2] = 0; - hdr[ETH_ALEN*2+3] = 0; - - /* Use scatter gather to MIC header and data in one go */ - sg_init_table(sg, 2); - sg_set_buf(&sg[0], hdr, sizeof(hdr)); - sg_set_buf(&sg[1], data, data_len); - - if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN)) - return -1; - - desc.tfm = tfm_michael; - desc.flags = 0; - return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr), - mic); -} - -/********************************************************************/ -/* Internal helper functions */ -/********************************************************************/ - -static inline void set_port_type(struct orinoco_private *priv) -{ - switch (priv->iw_mode) { - case IW_MODE_INFRA: - priv->port_type = 1; - priv->createibss = 0; - break; - case IW_MODE_ADHOC: - if (priv->prefer_port3) { - priv->port_type = 3; - priv->createibss = 0; - } else { - priv->port_type = priv->ibss_port; - priv->createibss = 1; - } - break; - case IW_MODE_MONITOR: - priv->port_type = 3; - priv->createibss = 0; - break; - default: - printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", - priv->ndev->name); - } -} - -#define ORINOCO_MAX_BSS_COUNT 64 -static int orinoco_bss_data_allocate(struct orinoco_private *priv) -{ - if (priv->bss_xbss_data) - return 0; - - if (priv->has_ext_scan) - priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * - sizeof(struct xbss_element), - GFP_KERNEL); - else - priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * - sizeof(struct bss_element), - GFP_KERNEL); - - if (!priv->bss_xbss_data) { - printk(KERN_WARNING "Out of memory allocating beacons"); - return -ENOMEM; - } - return 0; -} - -static void orinoco_bss_data_free(struct orinoco_private *priv) -{ - kfree(priv->bss_xbss_data); - priv->bss_xbss_data = NULL; -} - -#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) -#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) -static void orinoco_bss_data_init(struct orinoco_private *priv) -{ - int i; - - INIT_LIST_HEAD(&priv->bss_free_list); - INIT_LIST_HEAD(&priv->bss_list); - if (priv->has_ext_scan) - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&(PRIV_XBSS[i].list), - &priv->bss_free_list); - else - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&(PRIV_BSS[i].list), - &priv->bss_free_list); - -} - -static inline u8 *orinoco_get_ie(u8 *data, size_t len, - enum ieee80211_eid eid) -{ - u8 *p = data; - while ((p + 2) < (data + len)) { - if (p[0] == eid) - return p; - p += p[1] + 2; - } - return NULL; -} - -#define WPA_OUI_TYPE "\x00\x50\xF2\x01" -#define WPA_SELECTOR_LEN 4 -static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) -{ - u8 *p = data; - while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == WLAN_EID_GENERIC) && - (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) - return p; - p += p[1] + 2; - } - return NULL; -} - - -/********************************************************************/ -/* Download functionality */ -/********************************************************************/ - -struct fw_info { - char *pri_fw; - char *sta_fw; - char *ap_fw; - u32 pda_addr; - u16 pda_size; -}; - -const static struct fw_info orinoco_fw[] = { - { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } -}; - -/* Structure used to access fields in FW - * Make sure LE decoding macros are used - */ -struct orinoco_fw_header { - char hdr_vers[6]; /* ASCII string for header version */ - __le16 headersize; /* Total length of header */ - __le32 entry_point; /* NIC entry point */ - __le32 blocks; /* Number of blocks to program */ - __le32 block_offset; /* Offset of block data from eof header */ - __le32 pdr_offset; /* Offset to PDR data from eof header */ - __le32 pri_offset; /* Offset to primary plug data */ - __le32 compat_offset; /* Offset to compatibility data*/ - char signature[0]; /* FW signature length headersize-20 */ -} __attribute__ ((packed)); - -/* Download either STA or AP firmware into the card. */ -static int -orinoco_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw, - int ap) -{ - /* Plug Data Area (PDA) */ - __le16 *pda; - - hermes_t *hw = &priv->hw; - const struct firmware *fw_entry; - const struct orinoco_fw_header *hdr; - const unsigned char *first_block; - const unsigned char *end; - const char *firmware; - struct net_device *dev = priv->ndev; - int err = 0; - - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - if (ap) - firmware = fw->ap_fw; - else - firmware = fw->sta_fw; - - printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", - dev->name, firmware); - - /* Read current plug data */ - err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); - printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); - if (err) - goto free; - - if (priv->cached_fw) - fw_entry = priv->cached_fw; - else { - err = request_firmware(&fw_entry, firmware, priv->dev); - if (err) { - printk(KERN_ERR "%s: Cannot find firmware %s\n", - dev->name, firmware); - err = -ENOENT; - goto free; - } - priv->cached_fw = fw_entry; - } - - hdr = (const struct orinoco_fw_header *) fw_entry->data; - - /* Enable aux port to allow programming */ - err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); - printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); - if (err != 0) - goto abort; - - /* Program data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->block_offset)); - end = fw_entry->data + fw_entry->size; - - err = hermes_program(hw, first_block, end); - printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); - if (err != 0) - goto abort; - - /* Update production data */ - first_block = (fw_entry->data + - le16_to_cpu(hdr->headersize) + - le32_to_cpu(hdr->pdr_offset)); - - err = hermes_apply_pda_with_defaults(hw, first_block, pda); - printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); - if (err) - goto abort; - - /* Tell card we've finished */ - err = hermesi_program_end(hw); - printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); - if (err != 0) - goto abort; - - /* Check if we're running */ - printk(KERN_DEBUG "%s: hermes_present returned %d\n", - dev->name, hermes_present(hw)); - -abort: - /* In case of error, assume firmware was bogus and release it */ - if (err) { - priv->cached_fw = NULL; - release_firmware(fw_entry); - } - -free: - kfree(pda); - return err; -} - -/* End markers */ -#define TEXT_END 0x1A /* End of text header */ - -/* - * Process a firmware image - stop the card, load the firmware, reset - * the card and make sure it responds. For the secondary firmware take - * care of the PDA - read it and then write it on top of the firmware. - */ -static int -symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, - const unsigned char *image, const unsigned char *end, - int secondary) -{ - hermes_t *hw = &priv->hw; - int ret = 0; - const unsigned char *ptr; - const unsigned char *first_block; - - /* Plug Data Area (PDA) */ - __le16 *pda = NULL; - - /* Binary block begins after the 0x1A marker */ - ptr = image; - while (*ptr++ != TEXT_END); - first_block = ptr; - - /* Read the PDA from EEPROM */ - if (secondary) { - pda = kzalloc(fw->pda_size, GFP_KERNEL); - if (!pda) - return -ENOMEM; - - ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); - if (ret) - goto free; - } - - /* Stop the firmware, so that it can be safely rewritten */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 1); - if (ret) - goto free; - } - - /* Program the adapter with new firmware */ - ret = hermes_program(hw, first_block, end); - if (ret) - goto free; - - /* Write the PDA to the adapter */ - if (secondary) { - size_t len = hermes_blocks_length(first_block); - ptr = first_block + len; - ret = hermes_apply_pda(hw, ptr, pda); - kfree(pda); - if (ret) - return ret; - } - - /* Run the firmware */ - if (priv->stop_fw) { - ret = priv->stop_fw(priv, 0); - if (ret) - return ret; - } - - /* Reset hermes chip and make sure it responds */ - ret = hermes_init(hw); - - /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; - - /* And this should work with any firmware */ - if (!hermes_present(hw)) - return -ENODEV; - - return 0; - -free: - kfree(pda); - return ret; -} - - -/* - * Download the firmware into the card, this also does a PCMCIA soft - * reset on the card, to make sure it's in a sane state. - */ -static int -symbol_dl_firmware(struct orinoco_private *priv, - const struct fw_info *fw) -{ - struct net_device *dev = priv->ndev; - int ret; - const struct firmware *fw_entry; - - if (request_firmware(&fw_entry, fw->pri_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->pri_fw); - return -ENOENT; - } - - /* Load primary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 0); - release_firmware(fw_entry); - if (ret) { - printk(KERN_ERR "%s: Primary firmware download failed\n", - dev->name); - return ret; - } - - if (request_firmware(&fw_entry, fw->sta_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->sta_fw); - return -ENOENT; - } - - /* Load secondary firmware */ - ret = symbol_dl_image(priv, fw, fw_entry->data, - fw_entry->data + fw_entry->size, 1); - release_firmware(fw_entry); - if (ret) { - printk(KERN_ERR "%s: Secondary firmware download failed\n", - dev->name); - } - - return ret; -} - -static int orinoco_download(struct orinoco_private *priv) -{ - int err = 0; - /* Reload firmware */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* case FIRMWARE_TYPE_INTERSIL: */ - err = orinoco_dl_firmware(priv, - &orinoco_fw[priv->firmware_type], 0); - break; - - case FIRMWARE_TYPE_SYMBOL: - err = symbol_dl_firmware(priv, - &orinoco_fw[priv->firmware_type]); - break; - case FIRMWARE_TYPE_INTERSIL: - break; - } - /* TODO: if we fail we probably need to reinitialise - * the driver */ - - return err; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int orinoco_open(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = __orinoco_up(dev); - - if (! err) - priv->open = 1; - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_stop(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = 0; - - /* We mustn't use orinoco_lock() here, because we need to be - able to close the interface even if hw_unavailable is set - (e.g. as we're released after a PC Card removal) */ - spin_lock_irq(&priv->lock); - - priv->open = 0; - - err = __orinoco_down(dev); - - spin_unlock_irq(&priv->lock); - - return err; -} - -static struct net_device_stats *orinoco_get_stats(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - - return &priv->stats; -} - -static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_statistics *wstats = &priv->wstats; - int err; - unsigned long flags; - - if (! netif_device_present(dev)) { - printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", - dev->name); - return NULL; /* FIXME: Can we do better than this? */ - } - - /* If busy, return the old stats. Returning NULL may cause - * the interface to disappear from /proc/net/wireless */ - if (orinoco_lock(priv, &flags) != 0) - return wstats; - - /* We can't really wait for the tallies inquiry command to - * complete, so we just use the previous results and trigger - * a new tallies inquiry command for next time - Jean II */ - /* FIXME: Really we should wait for the inquiry to come back - - * as it is the stats we give don't make a whole lot of sense. - * Unfortunately, it's not clear how to do that within the - * wireless extensions framework: I think we're in user - * context, but a lock seems to be held by the time we get in - * here so we're not safe to sleep here. */ - hermes_inquire(hw, HERMES_INQ_TALLIES); - - if (priv->iw_mode == IW_MODE_ADHOC) { - memset(&wstats->qual, 0, sizeof(wstats->qual)); - /* If a spy address is defined, we report stats of the - * first spy address - Jean II */ - if (SPY_NUMBER(priv)) { - wstats->qual.qual = priv->spy_data.spy_stat[0].qual; - wstats->qual.level = priv->spy_data.spy_stat[0].level; - wstats->qual.noise = priv->spy_data.spy_stat[0].noise; - wstats->qual.updated = priv->spy_data.spy_stat[0].updated; - } - } else { - struct { - __le16 qual, signal, noise, unused; - } __attribute__ ((packed)) cq; - - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_COMMSQUALITY, &cq); - - if (!err) { - wstats->qual.qual = (int)le16_to_cpu(cq.qual); - wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; - wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = 7; - } - } - - orinoco_unlock(priv, &flags); - return wstats; -} - -static void orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " - "called when hw_unavailable\n", dev->name); - return; - } - - __orinoco_set_multicast_list(dev); - orinoco_unlock(priv, &flags); -} - -static int orinoco_change_mtu(struct net_device *dev, int new_mtu) -{ - struct orinoco_private *priv = netdev_priv(dev); - - if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) - return -EINVAL; - - /* MTU + encapsulation + header length */ - if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > - (priv->nicbuf_size - ETH_HLEN) ) - return -EINVAL; - - dev->mtu = new_mtu; - - return 0; -} - -/********************************************************************/ -/* Tx path */ -/********************************************************************/ - -static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - hermes_t *hw = &priv->hw; - int err = 0; - u16 txfid = priv->txfid; - struct ethhdr *eh; - int tx_control; - unsigned long flags; - - if (! netif_running(dev)) { - printk(KERN_ERR "%s: Tx on stopped device!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (netif_queue_stopped(dev)) { - printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (orinoco_lock(priv, &flags) != 0) { - printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", - dev->name); - return NETDEV_TX_BUSY; - } - - if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) { - /* Oops, the firmware hasn't established a connection, - silently drop the packet (this seems to be the - safest approach). */ - goto drop; - } - - /* Check packet length */ - if (skb->len < ETH_HLEN) - goto drop; - - tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - - if (priv->encode_alg == IW_ENCODE_ALG_TKIP) - tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | - HERMES_TXCTRL_MIC; - - if (priv->has_alt_txcntl) { - /* WPA enabled firmwares have tx_cntl at the end of - * the 802.11 header. So write zeroed descriptor and - * 802.11 header at the same time - */ - char desc[HERMES_802_3_OFFSET]; - __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; - - memset(&desc, 0, sizeof(desc)); - - *txcntl = cpu_to_le16(tx_control); - err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - } else { - struct hermes_tx_descriptor desc; - - memset(&desc, 0, sizeof(desc)); - - desc.tx_control = cpu_to_le16(tx_control); - err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), - txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx " - "descriptor to BAP\n", dev->name, err); - goto busy; - } - - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); - } - - eh = (struct ethhdr *)skb->data; - - /* Encapsulate Ethernet-II frames */ - if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ - struct header_struct { - struct ethhdr eth; /* 802.3 header */ - u8 encap[6]; /* 802.2 header */ - } __attribute__ ((packed)) hdr; - - /* Strip destination and source from the data */ - skb_pull(skb, 2 * ETH_ALEN); - - /* And move them to a separate header */ - memcpy(&hdr.eth, eh, 2 * ETH_ALEN); - hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len); - memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); - - /* Insert the SNAP header */ - if (skb_headroom(skb) < sizeof(hdr)) { - printk(KERN_ERR - "%s: Not enough headroom for 802.2 headers %d\n", - dev->name, skb_headroom(skb)); - goto drop; - } - eh = (struct ethhdr *) skb_push(skb, sizeof(hdr)); - memcpy(eh, &hdr, sizeof(hdr)); - } - - err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len, - txfid, HERMES_802_3_OFFSET); - if (err) { - printk(KERN_ERR "%s: Error %d writing packet to BAP\n", - dev->name, err); - goto busy; - } - - /* Calculate Michael MIC */ - if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { - u8 mic_buf[MICHAEL_MIC_LEN + 1]; - u8 *mic; - size_t offset; - size_t len; - - if (skb->len % 2) { - /* MIC start is on an odd boundary */ - mic_buf[0] = skb->data[skb->len - 1]; - mic = &mic_buf[1]; - offset = skb->len - 1; - len = MICHAEL_MIC_LEN + 1; - } else { - mic = &mic_buf[0]; - offset = skb->len; - len = MICHAEL_MIC_LEN; - } - - michael_mic(priv->tx_tfm_mic, - priv->tkip_key[priv->tx_key].tx_mic, - eh->h_dest, eh->h_source, 0 /* priority */, - skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); - - /* Write the MIC */ - err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len, - txfid, HERMES_802_3_OFFSET + offset); - if (err) { - printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", - dev->name, err); - goto busy; - } - } - - /* Finally, we actually initiate the send */ - netif_stop_queue(dev); - - err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, - txfid, NULL); - if (err) { - netif_start_queue(dev); - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d transmitting packet\n", - dev->name, err); - goto busy; - } - - dev->trans_start = jiffies; - stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; - goto ok; - - drop: - stats->tx_errors++; - stats->tx_dropped++; - - ok: - orinoco_unlock(priv, &flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - - busy: - if (err == -EIO) - schedule_work(&priv->reset_work); - orinoco_unlock(priv, &flags); - return NETDEV_TX_BUSY; -} - -static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - u16 fid = hermes_read_regn(hw, ALLOCFID); - - if (fid != priv->txfid) { - if (fid != DUMMY_FID) - printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", - dev->name, fid); - return; - } - - hermes_write_regn(hw, ALLOCFID, DUMMY_FID); -} - -static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - - stats->tx_packets++; - - netif_wake_queue(dev); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); -} - -static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - u16 fid = hermes_read_regn(hw, TXCOMPLFID); - u16 status; - struct hermes_txexc_data hdr; - int err = 0; - - if (fid == DUMMY_FID) - return; /* Nothing's really happened */ - - /* Read part of the frame header - we need status and addr1 */ - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, - sizeof(struct hermes_txexc_data), - fid, 0); - - hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); - stats->tx_errors++; - - if (err) { - printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " - "(FID=%04X error %d)\n", - dev->name, fid, err); - return; - } - - DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, - err, fid); - - /* We produce a TXDROP event only for retry or lifetime - * exceeded, because that's the only status that really mean - * that this particular node went away. - * Other errors means that *we* screwed up. - Jean II */ - status = le16_to_cpu(hdr.desc.status); - if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { - union iwreq_data wrqu; - - /* Copy 802.11 dest address. - * We use the 802.11 header because the frame may - * not be 802.3 or may be mangled... - * In Ad-Hoc mode, it will be the node address. - * In managed mode, it will be most likely the AP addr - * User space will figure out how to convert it to - * whatever it needs (IP address or else). - * - Jean II */ - memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); - } - - netif_wake_queue(dev); -} - -static void orinoco_tx_timeout(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - struct hermes *hw = &priv->hw; - - printk(KERN_WARNING "%s: Tx timeout! " - "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", - dev->name, hermes_read_regn(hw, ALLOCFID), - hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); - - stats->tx_errors++; - - schedule_work(&priv->reset_work); -} - -/********************************************************************/ -/* Rx path (data frames) */ -/********************************************************************/ - -/* Does the frame have a SNAP header indicating it should be - * de-encapsulated to Ethernet-II? */ -static inline int is_ethersnap(void *_hdr) -{ - u8 *hdr = _hdr; - - /* We de-encapsulate all packets which, a) have SNAP headers - * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header - * and where b) the OUI of the SNAP header is 00:00:00 or - * 00:00:f8 - we need both because different APs appear to use - * different OUIs for some reason */ - return (memcmp(hdr, &encaps_hdr, 5) == 0) - && ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) ); -} - -static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, - int level, int noise) -{ - struct iw_quality wstats; - wstats.level = level - 0x95; - wstats.noise = noise - 0x95; - wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = 7; - /* Update spy records */ - wireless_spy_update(dev, mac, &wstats); -} - -static void orinoco_stat_gather(struct net_device *dev, - struct sk_buff *skb, - struct hermes_rx_descriptor *desc) -{ - struct orinoco_private *priv = netdev_priv(dev); - - /* Using spy support with lots of Rx packets, like in an - * infrastructure (AP), will really slow down everything, because - * the MAC address must be compared to each entry of the spy list. - * If the user really asks for it (set some address in the - * spy list), we do it, but he will pay the price. - * Note that to get here, you need both WIRELESS_SPY - * compiled in AND some addresses in the list !!! - */ - /* Note : gcc will optimise the whole section away if - * WIRELESS_SPY is not defined... - Jean II */ - if (SPY_NUMBER(priv)) { - orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN, - desc->signal, desc->silence); - } -} - -/* - * orinoco_rx_monitor - handle received monitor frames. - * - * Arguments: - * dev network device - * rxfid received FID - * desc rx descriptor of the frame - * - * Call context: interrupt - */ -static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, - struct hermes_rx_descriptor *desc) -{ - u32 hdrlen = 30; /* return full header by default */ - u32 datalen = 0; - u16 fc; - int err; - int len; - struct sk_buff *skb; - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - hermes_t *hw = &priv->hw; - - len = le16_to_cpu(desc->data_len); - - /* Determine the size of the header and the data */ - fc = le16_to_cpu(desc->frame_ctl); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_TODS) - && (fc & IEEE80211_FCTL_FROMDS)) - hdrlen = 30; - else - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_MGMT: - hdrlen = 24; - datalen = len; - break; - case IEEE80211_FTYPE_CTL: - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PSPOLL: - case IEEE80211_STYPE_RTS: - case IEEE80211_STYPE_CFEND: - case IEEE80211_STYPE_CFENDACK: - hdrlen = 16; - break; - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = 10; - break; - } - break; - default: - /* Unknown frame type */ - break; - } - - /* sanity check the length */ - if (datalen > IEEE80211_MAX_DATA_LEN + 12) { - printk(KERN_DEBUG "%s: oversized monitor frame, " - "data length = %d\n", dev->name, datalen); - stats->rx_length_errors++; - goto update_stats; - } - - skb = dev_alloc_skb(hdrlen + datalen); - if (!skb) { - printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n", - dev->name); - goto update_stats; - } - - /* Copy the 802.11 header to the skb */ - memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen); - skb_reset_mac_header(skb); - - /* If any, copy the data from the card to the skb */ - if (datalen > 0) { - err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen), - ALIGN(datalen, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading monitor frame\n", - dev->name, err); - goto drop; - } - } - - skb->dev = dev; - skb->ip_summed = CHECKSUM_NONE; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = __constant_htons(ETH_P_802_2); - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - netif_rx(skb); - return; - - drop: - dev_kfree_skb_irq(skb); - update_stats: - stats->rx_errors++; - stats->rx_dropped++; -} - -/* Get tsc from the firmware */ -static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, - u8 *tsc) -{ - hermes_t *hw = &priv->hw; - int err = 0; - u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; - - if ((key < 0) || (key > 4)) - return -EINVAL; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, - sizeof(tsc_arr), NULL, &tsc_arr); - if (!err) - memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); - - return err; -} - -static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - struct iw_statistics *wstats = &priv->wstats; - struct sk_buff *skb = NULL; - u16 rxfid, status; - int length; - struct hermes_rx_descriptor *desc; - struct orinoco_rx_data *rx_data; - int err; - - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if (!desc) { - printk(KERN_WARNING - "%s: Can't allocate space for RX descriptor\n", - dev->name); - goto update_stats; - } - - rxfid = hermes_read_regn(hw, RXFID); - - err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), - rxfid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading Rx descriptor. " - "Frame dropped.\n", dev->name, err); - goto update_stats; - } - - status = le16_to_cpu(desc->status); - - if (status & HERMES_RXSTAT_BADCRC) { - DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", - dev->name); - stats->rx_crc_errors++; - goto update_stats; - } - - /* Handle frames in monitor mode */ - if (priv->iw_mode == IW_MODE_MONITOR) { - orinoco_rx_monitor(dev, rxfid, desc); - goto out; - } - - if (status & HERMES_RXSTAT_UNDECRYPTABLE) { - DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", - dev->name); - wstats->discard.code++; - goto update_stats; - } - - length = le16_to_cpu(desc->data_len); - - /* Sanity checks */ - if (length < 3) { /* No for even an 802.2 LLC header */ - /* At least on Symbol firmware with PCF we get quite a - lot of these legitimately - Poll frames with no - data. */ - goto out; - } - if (length > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", - dev->name, length); - stats->rx_length_errors++; - goto update_stats; - } - - /* Payload size does not include Michael MIC. Increase payload - * size to read it together with the data. */ - if (status & HERMES_RXSTAT_MIC) - length += MICHAEL_MIC_LEN; - - /* We need space for the packet data itself, plus an ethernet - header, plus 2 bytes so we can align the IP header on a - 32bit boundary, plus 1 byte so we can read in odd length - packets from the card, which has an IO granularity of 16 - bits */ - skb = dev_alloc_skb(length+ETH_HLEN+2+1); - if (!skb) { - printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", - dev->name); - goto update_stats; - } - - /* We'll prepend the header, so reserve space for it. The worst - case is no decapsulation, when 802.3 header is prepended and - nothing is removed. 2 is for aligning the IP header. */ - skb_reserve(skb, ETH_HLEN + 2); - - err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length), - ALIGN(length, 2), rxfid, - HERMES_802_2_OFFSET); - if (err) { - printk(KERN_ERR "%s: error %d reading frame. " - "Frame dropped.\n", dev->name, err); - goto drop; - } - - /* Add desc and skb to rx queue */ - rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); - if (!rx_data) { - printk(KERN_WARNING "%s: Can't allocate RX packet\n", - dev->name); - goto drop; - } - rx_data->desc = desc; - rx_data->skb = skb; - list_add_tail(&rx_data->list, &priv->rx_list); - tasklet_schedule(&priv->rx_tasklet); - - return; - -drop: - dev_kfree_skb_irq(skb); -update_stats: - stats->rx_errors++; - stats->rx_dropped++; -out: - kfree(desc); -} - -static void orinoco_rx(struct net_device *dev, - struct hermes_rx_descriptor *desc, - struct sk_buff *skb) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &priv->stats; - u16 status, fc; - int length; - struct ethhdr *hdr; - - status = le16_to_cpu(desc->status); - length = le16_to_cpu(desc->data_len); - fc = le16_to_cpu(desc->frame_ctl); - - /* Calculate and check MIC */ - if (status & HERMES_RXSTAT_MIC) { - int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> - HERMES_MIC_KEY_ID_SHIFT); - u8 mic[MICHAEL_MIC_LEN]; - u8 *rxmic; - u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? - desc->addr3 : desc->addr2; - - /* Extract Michael MIC from payload */ - rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; - - skb_trim(skb, skb->len - MICHAEL_MIC_LEN); - length -= MICHAEL_MIC_LEN; - - michael_mic(priv->rx_tfm_mic, - priv->tkip_key[key_id].rx_mic, - desc->addr1, - src, - 0, /* priority or QoS? */ - skb->data, - skb->len, - &mic[0]); - - if (memcmp(mic, rxmic, - MICHAEL_MIC_LEN)) { - union iwreq_data wrqu; - struct iw_michaelmicfailure wxmic; - - printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %pM, " - "using key %i\n", - dev->name, src, key_id); - - /* TODO: update stats */ - - /* Notify userspace */ - memset(&wxmic, 0, sizeof(wxmic)); - wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; - wxmic.flags |= (desc->addr1[0] & 1) ? - IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; - wxmic.src_addr.sa_family = ARPHRD_ETHER; - memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); - - (void) orinoco_hw_get_tkip_iv(priv, key_id, - &wxmic.tsc[0]); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(wxmic); - wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, - (char *) &wxmic); - - goto drop; - } - } - - /* Handle decapsulation - * In most cases, the firmware tell us about SNAP frames. - * For some reason, the SNAP frames sent by LinkSys APs - * are not properly recognised by most firmwares. - * So, check ourselves */ - if (length >= ENCAPS_OVERHEAD && - (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || - ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_ethersnap(skb->data))) { - /* These indicate a SNAP within 802.2 LLC within - 802.11 frame which we'll need to de-encapsulate to - the original EthernetII frame. */ - hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); - } else { - /* 802.3 frame - prepend 802.3 header as is */ - hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); - hdr->h_proto = htons(length); - } - memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); - if (fc & IEEE80211_FCTL_FROMDS) - memcpy(hdr->h_source, desc->addr3, ETH_ALEN); - else - memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - if (fc & IEEE80211_FCTL_TODS) - skb->pkt_type = PACKET_OTHERHOST; - - /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, desc); - - /* Pass the packet to the networking stack */ - netif_rx(skb); - stats->rx_packets++; - stats->rx_bytes += length; - - return; - - drop: - dev_kfree_skb(skb); - stats->rx_errors++; - stats->rx_dropped++; -} - -static void orinoco_rx_isr_tasklet(unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_rx_data *rx_data, *temp; - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - - /* extract desc and skb from queue */ - list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { - desc = rx_data->desc; - skb = rx_data->skb; - list_del(&rx_data->list); - kfree(rx_data); - - orinoco_rx(dev, desc, skb); - - kfree(desc); - } -} - -/********************************************************************/ -/* Rx path (info frames) */ -/********************************************************************/ - -static void print_linkstatus(struct net_device *dev, u16 status) -{ - char * s; - - if (suppress_linkstatus) - return; - - switch (status) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } - - printk(KERN_INFO "%s: New link status: %s (%04x)\n", - dev->name, s, status); -} - -/* Search scan results for requested BSSID, join it if found */ -static void orinoco_join_ap(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, join_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - struct join_req { - u8 bssid[ETH_ALEN]; - __le16 channel; - } __attribute__ ((packed)) req; - const int atom_len = offsetof(struct prism2_scan_apinfo, atim); - struct prism2_scan_apinfo *atom = NULL; - int offset = 4; - int found = 0; - u8 *buf; - u16 len; - - /* Allocate buffer for scan results */ - buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL); - if (! buf) - return; - - if (orinoco_lock(priv, &flags) != 0) - goto fail_lock; - - /* Sanity checks in case user changed something in the meantime */ - if (! priv->bssid_fixed) - goto out; - - if (strlen(priv->desired_essid) == 0) - goto out; - - /* Read scan results from the firmware */ - err = hermes_read_ltv(hw, USER_BAP, - HERMES_RID_SCANRESULTSTABLE, - MAX_SCAN_LEN, &len, buf); - if (err) { - printk(KERN_ERR "%s: Cannot read scan results\n", - dev->name); - goto out; - } - - len = HERMES_RECLEN_TO_BYTES(len); - - /* Go through the scan results looking for the channel of the AP - * we were requested to join */ - for (; offset + atom_len <= len; offset += atom_len) { - atom = (struct prism2_scan_apinfo *) (buf + offset); - if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) { - found = 1; - break; - } - } - - if (! found) { - DEBUG(1, "%s: Requested AP not found in scan results\n", - dev->name); - goto out; - } - - memcpy(req.bssid, priv->desired_bssid, ETH_ALEN); - req.channel = atom->channel; /* both are little-endian */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST, - &req); - if (err) - printk(KERN_ERR "%s: Error issuing join request\n", dev->name); - - out: - orinoco_unlock(priv, &flags); - - fail_lock: - kfree(buf); -} - -/* Send new BSSID to userspace */ -static void orinoco_send_bssid_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, wrqu.ap_addr.sa_data); - if (err != 0) - return; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); - } -} - -static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) -{ - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - union iwreq_data wrqu; - int err; - u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ - u8 *ie; - - if (!priv->has_wpa) - return; - - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, - sizeof(buf), NULL, &buf); - if (err != 0) - return; - - ie = orinoco_get_wpa_ie(buf, sizeof(buf)); - if (ie) { - int rem = sizeof(buf) - (ie - &buf[0]); - wrqu.data.length = ie[1] + 2; - if (wrqu.data.length > rem) - wrqu.data.length = rem; - - if (wrqu.data.length) - /* Send event to user space */ - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); - } -} - -static void orinoco_send_wevents(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, wevent_work); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return; - - orinoco_send_assocreqie_wevent(priv); - orinoco_send_assocrespie_wevent(priv); - orinoco_send_bssid_wevent(priv); - - orinoco_unlock(priv, &flags); -} - -static inline void orinoco_clear_scan_results(struct orinoco_private *priv, - unsigned long scan_age) -{ - if (priv->has_ext_scan) { - struct xbss_element *bss; - struct xbss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, - &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(&bss->bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; - } - } - } else { - struct bss_element *bss; - struct bss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, - &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(&bss->bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; - } - } - } -} - -static void orinoco_add_ext_scan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom) -{ - struct xbss_element *bss = NULL; - int found = 0; - - /* Try to update an existing bss first */ - list_for_each_entry(bss, &priv->bss_list, list) { - if (compare_ether_addr(bss->bss.bssid, atom->bssid)) - continue; - /* ESSID lengths */ - if (bss->bss.data[1] != atom->data[1]) - continue; - if (memcmp(&bss->bss.data[2], &atom->data[2], - atom->data[1])) - continue; - found = 1; - break; - } - - /* Grab a bss off the free list */ - if (!found && !list_empty(&priv->bss_free_list)) { - bss = list_entry(priv->bss_free_list.next, - struct xbss_element, list); - list_del(priv->bss_free_list.next); - - list_add_tail(&bss->list, &priv->bss_list); - } - - if (bss) { - /* Always update the BSS to get latest beacon info */ - memcpy(&bss->bss, atom, sizeof(bss->bss)); - bss->last_scanned = jiffies; - } -} - -static int orinoco_process_scan_results(struct net_device *dev, - unsigned char *buf, - int len) -{ - struct orinoco_private *priv = netdev_priv(dev); - int offset; /* In the scan data */ - union hermes_scan_info *atom; - int atom_len; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - atom_len = sizeof(struct agere_scan_apinfo); - offset = 0; - break; - case FIRMWARE_TYPE_SYMBOL: - /* Lack of documentation necessitates this hack. - * Different firmwares have 68 or 76 byte long atoms. - * We try modulo first. If the length divides by both, - * we check what would be the channel in the second - * frame for a 68-byte atom. 76-byte atoms have 0 there. - * Valid channel cannot be 0. */ - if (len % 76) - atom_len = 68; - else if (len % 68) - atom_len = 76; - else if (len >= 1292 && buf[68] == 0) - atom_len = 76; - else - atom_len = 68; - offset = 0; - break; - case FIRMWARE_TYPE_INTERSIL: - offset = 4; - if (priv->has_hostscan) { - atom_len = le16_to_cpup((__le16 *)buf); - /* Sanity check for atom_len */ - if (atom_len < sizeof(struct prism2_scan_apinfo)) { - printk(KERN_ERR "%s: Invalid atom_len in scan " - "data: %d\n", dev->name, atom_len); - return -EIO; - } - } else - atom_len = offsetof(struct prism2_scan_apinfo, atim); - break; - default: - return -EOPNOTSUPP; - } - - /* Check that we got an whole number of atoms */ - if ((len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %d, " - "atom_len %d, offset %d\n", dev->name, len, - atom_len, offset); - return -EIO; - } - - orinoco_clear_scan_results(priv, msecs_to_jiffies(15000)); - - /* Read the entries one by one */ - for (; offset + atom_len <= len; offset += atom_len) { - int found = 0; - struct bss_element *bss = NULL; - - /* Get next atom */ - atom = (union hermes_scan_info *) (buf + offset); - - /* Try to update an existing bss first */ - list_for_each_entry(bss, &priv->bss_list, list) { - if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid)) - continue; - if (le16_to_cpu(bss->bss.a.essid_len) != - le16_to_cpu(atom->a.essid_len)) - continue; - if (memcmp(bss->bss.a.essid, atom->a.essid, - le16_to_cpu(atom->a.essid_len))) - continue; - found = 1; - break; - } - - /* Grab a bss off the free list */ - if (!found && !list_empty(&priv->bss_free_list)) { - bss = list_entry(priv->bss_free_list.next, - struct bss_element, list); - list_del(priv->bss_free_list.next); - - list_add_tail(&bss->list, &priv->bss_list); - } - - if (bss) { - /* Always update the BSS to get latest beacon info */ - memcpy(&bss->bss, atom, sizeof(bss->bss)); - bss->last_scanned = jiffies; - } - } - - return 0; -} - -static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) -{ - struct orinoco_private *priv = netdev_priv(dev); - u16 infofid; - struct { - __le16 len; - __le16 type; - } __attribute__ ((packed)) info; - int len, type; - int err; - - /* This is an answer to an INQUIRE command that we did earlier, - * or an information "event" generated by the card - * The controller return to us a pseudo frame containing - * the information in question - Jean II */ - infofid = hermes_read_regn(hw, INFOFID); - - /* Read the info frame header - don't try too hard */ - err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), - infofid, 0); - if (err) { - printk(KERN_ERR "%s: error %d reading info frame. " - "Frame dropped.\n", dev->name, err); - return; - } - - len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); - type = le16_to_cpu(info.type); - - switch (type) { - case HERMES_INQ_TALLIES: { - struct hermes_tallies_frame tallies; - struct iw_statistics *wstats = &priv->wstats; - - if (len > sizeof(tallies)) { - printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", - dev->name, len); - len = sizeof(tallies); - } - - err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len, - infofid, sizeof(info)); - if (err) - break; - - /* Increment our various counters */ - /* wstats->discard.nwid - no wrong BSSID stuff */ - wstats->discard.code += - le16_to_cpu(tallies.RxWEPUndecryptable); - if (len == sizeof(tallies)) - wstats->discard.code += - le16_to_cpu(tallies.RxDiscards_WEPICVError) + - le16_to_cpu(tallies.RxDiscards_WEPExcluded); - wstats->discard.misc += - le16_to_cpu(tallies.TxDiscardsWrongSA); - wstats->discard.fragment += - le16_to_cpu(tallies.RxMsgInBadMsgFragments); - wstats->discard.retries += - le16_to_cpu(tallies.TxRetryLimitExceeded); - /* wstats->miss.beacon - no match */ - } - break; - case HERMES_INQ_LINKSTATUS: { - struct hermes_linkstatus linkstatus; - u16 newstatus; - int connected; - - if (priv->iw_mode == IW_MODE_MONITOR) - break; - - if (len != sizeof(linkstatus)) { - printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", - dev->name, len); - break; - } - - err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len, - infofid, sizeof(info)); - if (err) - break; - newstatus = le16_to_cpu(linkstatus.linkstatus); - - /* Symbol firmware uses "out of range" to signal that - * the hostscan frame can be requested. */ - if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && - priv->firmware_type == FIRMWARE_TYPE_SYMBOL && - priv->has_hostscan && priv->scan_inprogress) { - hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); - break; - } - - connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); - - if (connected) - netif_carrier_on(dev); - else if (!ignore_disconnect) - netif_carrier_off(dev); - - if (newstatus != priv->last_linkstatus) { - priv->last_linkstatus = newstatus; - print_linkstatus(dev, newstatus); - /* The info frame contains only one word which is the - * status (see hermes.h). The status is pretty boring - * in itself, that's why we export the new BSSID... - * Jean II */ - schedule_work(&priv->wevent_work); - } - } - break; - case HERMES_INQ_SCAN: - if (!priv->scan_inprogress && priv->bssid_fixed && - priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { - schedule_work(&priv->join_work); - break; - } - /* fall through */ - case HERMES_INQ_HOSTSCAN: - case HERMES_INQ_HOSTSCAN_SYMBOL: { - /* Result of a scanning. Contains information about - * cells in the vicinity - Jean II */ - union iwreq_data wrqu; - unsigned char *buf; - - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; - - /* Sanity check */ - if (len > 4096) { - printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", - dev->name, len); - break; - } - - /* Allocate buffer for results */ - buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) - /* No memory, so can't printk()... */ - break; - - /* Read scan data */ - err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, - infofid, sizeof(info)); - if (err) { - kfree(buf); - break; - } - -#ifdef ORINOCO_DEBUG - { - int i; - printk(KERN_DEBUG "Scan result [%02X", buf[0]); - for(i = 1; i < (len * 2); i++) - printk(":%02X", buf[i]); - printk("]\n"); - } -#endif /* ORINOCO_DEBUG */ - - if (orinoco_process_scan_results(dev, buf, len) == 0) { - /* Send an empty event to user space. - * We don't send the received data on the event because - * it would require us to do complex transcoding, and - * we want to minimise the work done in the irq handler - * Use a request to extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - } - kfree(buf); - } - break; - case HERMES_INQ_CHANNELINFO: - { - struct agere_ext_scan_info *bss; - - if (!priv->scan_inprogress) { - printk(KERN_DEBUG "%s: Got chaninfo without scan, " - "len=%d\n", dev->name, len); - break; - } - - /* An empty result indicates that the scan is complete */ - if (len == 0) { - union iwreq_data wrqu; - - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - break; - } - - /* Sanity check */ - else if (len > sizeof(*bss)) { - printk(KERN_WARNING - "%s: Ext scan results too large (%d bytes). " - "Truncating results to %zd bytes.\n", - dev->name, len, sizeof(*bss)); - len = sizeof(*bss); - } else if (len < (offsetof(struct agere_ext_scan_info, - data) + 2)) { - /* Drop this result now so we don't have to - * keep checking later */ - printk(KERN_WARNING - "%s: Ext scan results too short (%d bytes)\n", - dev->name, len); - break; - } - - bss = kmalloc(sizeof(*bss), GFP_ATOMIC); - if (bss == NULL) - break; - - /* Read scan data */ - err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, - infofid, sizeof(info)); - if (err) { - kfree(bss); - break; - } - - orinoco_add_ext_scan_result(priv, bss); - - kfree(bss); - break; - } - case HERMES_INQ_SEC_STAT_AGERE: - /* Security status (Agere specific) */ - /* Ignore this frame for now */ - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - break; - /* fall through */ - default: - printk(KERN_DEBUG "%s: Unknown information frame received: " - "type 0x%04x, length %d\n", dev->name, type, len); - /* We don't actually do anything about it */ - break; - } -} - -static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) -{ - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); -} - -/********************************************************************/ -/* Internal hardware control routines */ -/********************************************************************/ - -int __orinoco_up(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - netif_carrier_off(dev); /* just to make sure */ - - err = __orinoco_program_rids(dev); - if (err) { - printk(KERN_ERR "%s: Error %d configuring card\n", - dev->name, err); - return err; - } - - /* Fire things up again */ - hermes_set_irqmask(hw, ORINOCO_INTEN); - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d enabling MAC port\n", - dev->name, err); - return err; - } - - netif_start_queue(dev); - - return 0; -} - -int __orinoco_down(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - netif_stop_queue(dev); - - if (! priv->hw_unavailable) { - if (! priv->broken_disableport) { - err = hermes_disable_port(hw, 0); - if (err) { - /* Some firmwares (e.g. Intersil 1.3.x) seem - * to have problems disabling the port, oh - * well, too bad. */ - printk(KERN_WARNING "%s: Error %d disabling MAC port\n", - dev->name, err); - priv->broken_disableport = 1; - } - } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - } - - /* firmware will have to reassociate */ - netif_carrier_off(dev); - priv->last_linkstatus = 0xffff; - - return 0; -} - -static int orinoco_allocate_fid(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { - /* Try workaround for old Symbol firmware bug */ - printk(KERN_WARNING "%s: firmware ALLOC bug detected " - "(old Symbol firmware?). Trying to work around... ", - dev->name); - - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err) - printk("failed!\n"); - else - printk("ok.\n"); - } - - return err; -} - -int orinoco_reinit_firmware(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - err = hermes_init(hw); - if (priv->do_fw_download && !err) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - if (!err) - err = orinoco_allocate_fid(dev); - - return err; -} - -static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - - if (priv->bitratemode >= BITRATE_TABLE_SIZE) { - printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", - priv->ndev->name, priv->bitratemode); - return -EINVAL; - } - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[priv->bitratemode].agere_txratectrl); - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXRATECONTROL, - bitrate_table[priv->bitratemode].intersil_txratectrl); - break; - default: - BUG(); - } - - return err; -} - -/* Set fixed AP address */ -static int __orinoco_hw_set_wap(struct orinoco_private *priv) -{ - int roaming_flag; - int err = 0; - hermes_t *hw = &priv->hw; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* not supported */ - break; - case FIRMWARE_TYPE_INTERSIL: - if (priv->bssid_fixed) - roaming_flag = 2; - else - roaming_flag = 1; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFROAMINGMODE, - roaming_flag); - break; - case FIRMWARE_TYPE_SYMBOL: - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFMANDATORYBSSID_SYMBOL, - &priv->desired_bssid); - break; - } - return err; -} - -/* Change the WEP keys and/or the current keys. Can be called - * either from __orinoco_hw_setup_enc() or directly from - * orinoco_ioctl_setiwencode(). In the later case the association - * with the AP is not broken (if the firmware can handle it), - * which is needed for 802.1x implementations. */ -static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFWEPKEYS_AGERE, - &priv->keys); - if (err) - return err; - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFTXKEY_AGERE, - priv->tx_key); - if (err) - return err; - break; - case FIRMWARE_TYPE_INTERSIL: - case FIRMWARE_TYPE_SYMBOL: - { - int keylen; - int i; - - /* Force uniform key length to work around firmware bugs */ - keylen = le16_to_cpu(priv->keys[priv->tx_key].len); - - if (keylen > LARGE_KEY_SIZE) { - printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", - priv->ndev->name, priv->tx_key, keylen); - return -E2BIG; - } - - /* Write all 4 keys */ - for(i = 0; i < ORINOCO_MAX_KEYS; i++) { - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFDEFAULTKEY0 + i, - HERMES_BYTES_TO_RECLEN(keylen), - priv->keys[i].data); - if (err) - return err; - } - - /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPDEFAULTKEYID, - priv->tx_key); - if (err) - return err; - } - break; - } - - return 0; -} - -static int __orinoco_hw_setup_enc(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - int err = 0; - int master_wep_flag; - int auth_flag; - int enc_flag; - - /* Setup WEP keys for WEP and WPA */ - if (priv->encode_alg) - __orinoco_hw_setup_wepkeys(priv); - - if (priv->wep_restrict) - auth_flag = HERMES_AUTH_SHARED_KEY; - else - auth_flag = HERMES_AUTH_OPEN; - - if (priv->wpa_enabled) - enc_flag = 2; - else if (priv->encode_alg == IW_ENCODE_ALG_WEP) - enc_flag = 1; - else - enc_flag = 0; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->encode_alg == IW_ENCODE_ALG_WEP) { - /* Enable the shared-key authentication. */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION_AGERE, - auth_flag); - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPENABLED_AGERE, - enc_flag); - if (err) - return err; - - if (priv->has_wpa) { - /* Set WPA key management */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, - priv->key_mgmt); - if (err) - return err; - } - - break; - - case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->encode_alg == IW_ENCODE_ALG_WEP) { - if (priv->wep_restrict || - (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | - HERMES_WEP_EXCL_UNENCRYPTED; - else - master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFAUTHENTICATION, - auth_flag); - if (err) - return err; - } else - master_wep_flag = 0; - - if (priv->iw_mode == IW_MODE_MONITOR) - master_wep_flag |= HERMES_WEP_HOST_DECRYPT; - - /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFWEPFLAGS_INTERSIL, - master_wep_flag); - if (err) - return err; - - break; - } - - return 0; -} - -/* key must be 32 bytes, including the tx and rx MIC keys. - * rsc must be 8 bytes - * tsc must be 8 bytes or NULL - */ -static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, - u8 *key, u8 *rsc, u8 *tsc) -{ - struct { - __le16 idx; - u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; - u8 key[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; - u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; - } __attribute__ ((packed)) buf; - int ret; - int err; - int k; - u16 xmitting; - - key_idx &= 0x3; - - if (set_tx) - key_idx |= 0x8000; - - buf.idx = cpu_to_le16(key_idx); - memcpy(buf.key, key, - sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); - - if (rsc == NULL) - memset(buf.rsc, 0, sizeof(buf.rsc)); - else - memcpy(buf.rsc, rsc, sizeof(buf.rsc)); - - if (tsc == NULL) { - memset(buf.tsc, 0, sizeof(buf.tsc)); - buf.tsc[4] = 0x10; - } else { - memcpy(buf.tsc, tsc, sizeof(buf.tsc)); - } - - /* Wait upto 100ms for tx queue to empty */ - k = 100; - do { - k--; - udelay(1000); - ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, - &xmitting); - if (ret) - break; - } while ((k > 0) && xmitting); - - if (k == 0) - ret = -ETIMEDOUT; - - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, - &buf); - - return ret ? ret : err; -} - -static int orinoco_clear_tkip_key(struct orinoco_private *priv, - int key_idx) -{ - hermes_t *hw = &priv->hw; - int err; - - memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, - key_idx); - if (err) - printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", - priv->ndev->name, err, key_idx); - return err; -} - -static int __orinoco_program_rids(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; - - /* Set the MAC address */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", - dev->name, err); - return err; - } - - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", - dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFOWNCHANNEL, - priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel %d\n", - dev->name, err, priv->channel); - return err; - } - } - - if (priv->has_ibss) { - u16 createibss; - - if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { - printk(KERN_WARNING "%s: This firmware requires an " - "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - createibss = 0; - } else { - createibss = priv->createibss; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", - dev->name, err); - return err; - } - } - - /* Set the desired BSSID */ - err = __orinoco_hw_set_wap(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting AP address\n", - dev->name, err); - return err; - } - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", - dev->name, err); - return err; - } - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", - dev->name, err); - return err; - } - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", - dev->name, err); - return err; - } - - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", - dev->name, err); - - priv->has_sensitivity = 0; - } - } - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", - dev->name, err); - return err; - } - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting fragmentation\n", - dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", - dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } - - /* Set up encryption */ - if (priv->has_wep || priv->has_wpa) { - err = __orinoco_hw_setup_enc(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating encryption\n", - dev->name, err); - return err; - } - } - - if (priv->iw_mode == IW_MODE_MONITOR) { - /* Enable monitor mode */ - dev->type = ARPHRD_IEEE80211; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_MONITOR, 0, NULL); - } else { - /* Disable monitor mode */ - dev->type = ARPHRD_ETHER; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_STOP, 0, NULL); - } - if (err) - return err; - - /* Set promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - - /* FIXME: what about netif_tx_lock */ - __orinoco_set_multicast_list(dev); - - return 0; -} - -/* FIXME: return int? */ -static void -__orinoco_set_multicast_list(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err = 0; - int promisc, mc_count; - - /* The Hermes doesn't seem to have an allmulti mode, so we go - * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST(priv)) ) { - promisc = 1; - mc_count = 0; - } else { - promisc = 0; - mc_count = dev->mc_count; - } - - if (promisc != priv->promiscuous) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPROMISCUOUSMODE, - promisc); - if (err) { - printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", - dev->name, err); - } else - priv->promiscuous = promisc; - } - - /* If we're not in promiscuous mode, then we need to set the - * group address if either we want to multicast, or if we were - * multicasting and want to stop */ - if (! promisc && (mc_count || priv->mc_count) ) { - struct dev_mc_list *p = dev->mc_list; - struct hermes_multicast mclist; - int i; - - for (i = 0; i < mc_count; i++) { - /* paranoia: is list shorter than mc_count? */ - BUG_ON(! p); - /* paranoia: bad address size in list? */ - BUG_ON(p->dmi_addrlen != ETH_ALEN); - - memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); - p = p->next; - } - - if (p) - printk(KERN_WARNING "%s: Multicast list is " - "longer than mc_count\n", dev->name); - - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), - &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->mc_count = mc_count; - } -} - -/* This must be called from user context, without locks held - use - * schedule_work() */ -static void orinoco_reset(struct work_struct *work) -{ - struct orinoco_private *priv = - container_of(work, struct orinoco_private, reset_work); - struct net_device *dev = priv->ndev; - struct hermes *hw = &priv->hw; - int err; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - /* When the hardware becomes available again, whatever - * detects that is responsible for re-initializing - * it. So no need for anything further */ - return; - - netif_stop_queue(dev); - - /* Shut off interrupts. Depending on what state the hardware - * is in, this might not work, but we'll try anyway */ - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - - priv->hw_unavailable++; - priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ - netif_carrier_off(dev); - - orinoco_unlock(priv, &flags); - - /* Scanning support: Cleanup of driver struct */ - orinoco_clear_scan_results(priv, 0); - priv->scan_inprogress = 0; - - if (priv->hard_reset) { - err = (*priv->hard_reset)(priv); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d " - "performing hard reset\n", dev->name, err); - goto disable; - } - } - - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", - dev->name, err); - goto disable; - } - - spin_lock_irq(&priv->lock); /* This has to be called from user context */ - - priv->hw_unavailable--; - - /* priv->open or priv->hw_unavailable might have changed while - * we dropped the lock */ - if (priv->open && (! priv->hw_unavailable)) { - err = __orinoco_up(dev); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - dev->trans_start = jiffies; - } - - spin_unlock_irq(&priv->lock); - - return; - disable: - hermes_set_irqmask(hw, 0); - netif_device_detach(dev); - printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); -} - -/********************************************************************/ -/* Interrupt handler */ -/********************************************************************/ - -static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) -{ - printk(KERN_DEBUG "%s: TICK\n", dev->name); -} - -static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) -{ - /* This seems to happen a fair bit under load, but ignoring it - seems to work fine...*/ - printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - dev->name); -} - -irqreturn_t orinoco_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int count = MAX_IRQLOOPS_PER_IRQ; - u16 evstat, events; - /* These are used to detect a runaway interrupt situation */ - /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, - * we panic and shut down the hardware */ - static int last_irq_jiffy = 0; /* jiffies value the last time - * we were called */ - static int loops_this_jiffy = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable - we don't know if the irq was - * for us or not */ - return IRQ_HANDLED; - } - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - if (! events) { - orinoco_unlock(priv, &flags); - return IRQ_NONE; - } - - if (jiffies != last_irq_jiffy) - loops_this_jiffy = 0; - last_irq_jiffy = jiffies; - - while (events && count--) { - if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_WARNING "%s: IRQ handler is looping too " - "much! Resetting.\n", dev->name); - /* Disable interrupts for now */ - hermes_set_irqmask(hw, 0); - schedule_work(&priv->reset_work); - break; - } - - /* Check the card hasn't been removed */ - if (! hermes_present(hw)) { - DEBUG(0, "orinoco_interrupt(): card removed\n"); - break; - } - - if (events & HERMES_EV_TICK) - __orinoco_ev_tick(dev, hw); - if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(dev, hw); - if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(dev, hw); - if (events & HERMES_EV_INFO) - __orinoco_ev_info(dev, hw); - if (events & HERMES_EV_RX) - __orinoco_ev_rx(dev, hw); - if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(dev, hw); - if (events & HERMES_EV_TX) - __orinoco_ev_tx(dev, hw); - if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(dev, hw); - - hermes_write_regn(hw, EVACK, evstat); - - evstat = hermes_read_regn(hw, EVSTAT); - events = evstat & hw->inten; - }; - - orinoco_unlock(priv, &flags); - return IRQ_HANDLED; -} - -/********************************************************************/ -/* Initialization */ -/********************************************************************/ - -struct comp_id { - u16 id, variant, major, minor; -} __attribute__ ((packed)); - -static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) -{ - if (nic_id->id < 0x8000) - return FIRMWARE_TYPE_AGERE; - else if (nic_id->id == 0x8000 && nic_id->major == 0) - return FIRMWARE_TYPE_SYMBOL; - else - return FIRMWARE_TYPE_INTERSIL; -} - -/* Set priv->firmware type, determine firmware properties */ -static int determine_firmware(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - struct comp_id nic_id, sta_id; - unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); - - /* Get the hardware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); - if (err) { - printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", - dev->name, err); - return err; - } - - le16_to_cpus(&nic_id.id); - le16_to_cpus(&nic_id.variant); - le16_to_cpus(&nic_id.major); - le16_to_cpus(&nic_id.minor); - printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", - dev->name, nic_id.id, nic_id.variant, - nic_id.major, nic_id.minor); - - priv->firmware_type = determine_firmware_type(&nic_id); - - /* Get the firmware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); - if (err) { - printk(KERN_ERR "%s: Cannot read station identity: error %d\n", - dev->name, err); - return err; - } - - le16_to_cpus(&sta_id.id); - le16_to_cpus(&sta_id.variant); - le16_to_cpus(&sta_id.major); - le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", - dev->name, sta_id.id, sta_id.variant, - sta_id.major, sta_id.minor); - - switch (sta_id.id) { - case 0x15: - printk(KERN_ERR "%s: Primary firmware is active\n", - dev->name); - return -ENODEV; - case 0x14b: - printk(KERN_ERR "%s: Tertiary firmware is active\n", - dev->name); - return -ENODEV; - case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ - case 0x21: /* Symbol Spectrum24 Trilogy */ - break; - default: - printk(KERN_NOTICE "%s: Unknown station ID, please report\n", - dev->name); - break; - } - - /* Default capabilities */ - priv->has_sensitivity = 1; - priv->has_mwo = 0; - priv->has_preamble = 0; - priv->has_port3 = 1; - priv->has_ibss = 1; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_alt_txcntl = 0; - priv->has_ext_scan = 0; - priv->has_wpa = 0; - priv->do_fw_download = 0; - - /* Determine capabilities from the firmware version */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); - - firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; - - priv->has_ibss = (firmver >= 0x60006); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ - priv->ibss_port = 1; - priv->has_hostscan = (firmver >= 0x8000a); - priv->do_fw_download = 1; - priv->broken_monitor = (firmver >= 0x80000); - priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_wpa = (firmver >= 0x9002a); - /* Tested with Agere firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case FIRMWARE_TYPE_SYMBOL: - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - memset(tmp, 0, sizeof(tmp)); - /* Get the Symbol firmware version */ - err = hermes_read_ltv(hw, USER_BAP, - HERMES_RID_SECONDARYVERSION_SYMBOL, - SYMBOL_MAX_VER_LEN, NULL, &tmp); - if (err) { - printk(KERN_WARNING - "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n", - dev->name, err); - firmver = 0; - tmp[0] = '\0'; - } else { - /* The firmware revision is a string, the format is - * something like : "V2.20-01". - * Quick and dirty parsing... - Jean II - */ - firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12) - | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4) - | (tmp[7] - '0'); - - tmp[SYMBOL_MAX_VER_LEN] = '\0'; - } - - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Symbol %s", tmp); - - priv->has_ibss = (firmver >= 0x20000); - priv->has_wep = (firmver >= 0x15012); - priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || - (firmver >= 0x29000 && firmver < 0x30000) || - firmver >= 0x31000; - priv->has_preamble = (firmver >= 0x20000); - priv->ibss_port = 4; - - /* Symbol firmware is found on various cards, but - * there has been no attempt to check firmware - * download on non-spectrum_cs based cards. - * - * Given that the Agere firmware download works - * differently, we should avoid doing a firmware - * download with the Symbol algorithm on non-spectrum - * cards. - * - * For now we can identify a spectrum_cs based card - * because it has a firmware reset function. - */ - priv->do_fw_download = (priv->stop_fw != NULL); - - priv->broken_disableport = (firmver == 0x25013) || - (firmver >= 0x30000 && firmver <= 0x31000); - priv->has_hostscan = (firmver >= 0x31001) || - (firmver >= 0x29057 && firmver < 0x30000); - /* Tested with Intel firmware : 0x20015 => Jean II */ - /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ - break; - case FIRMWARE_TYPE_INTERSIL: - /* D-Link, Linksys, Adtron, ZoomAir, and many others... - * Samsung, Compaq 100/200 and Proxim are slightly - * different and less well tested */ - /* D-Link MAC : 00:40:05:* */ - /* Addtron MAC : 00:90:D1:* */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Intersil %d.%d.%d", sta_id.major, sta_id.minor, - sta_id.variant); - - firmver = ((unsigned long)sta_id.major << 16) | - ((unsigned long)sta_id.minor << 8) | sta_id.variant; - - priv->has_ibss = (firmver >= 0x000700); /* FIXME */ - priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); - priv->has_pm = (firmver >= 0x000700); - priv->has_hostscan = (firmver >= 0x010301); - - if (firmver >= 0x000800) - priv->ibss_port = 0; - else { - printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.8.x - several features not supported\n", - dev->name); - priv->ibss_port = 1; - } - break; - } - printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, - priv->fw_name); - - return 0; -} - -static int orinoco_init(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err = 0; - struct hermes_idstring nickbuf; - u16 reclen; - int len; - - /* No need to lock, the hw_unavailable flag is already set in - * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; - - /* Initialize the firmware */ - err = hermes_init(hw); - if (err != 0) { - printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", - dev->name, err); - goto out; - } - - err = determine_firmware(dev); - if (err != 0) { - printk(KERN_ERR "%s: Incompatible firmware, aborting\n", - dev->name); - goto out; - } - - if (priv->do_fw_download) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - - /* Check firmware version again */ - err = determine_firmware(dev); - if (err != 0) { - printk(KERN_ERR "%s: Incompatible firmware, aborting\n", - dev->name); - goto out; - } - } - - if (priv->has_port3) - printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); - if (priv->has_ibss) - printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", - dev->name); - if (priv->has_wep) { - printk(KERN_DEBUG "%s: WEP supported, ", dev->name); - if (priv->has_big_wep) - printk("104-bit key\n"); - else - printk("40-bit key\n"); - } - if (priv->has_wpa) { - printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); - if (orinoco_mic_init(priv)) { - printk(KERN_ERR "%s: Failed to setup MIC crypto " - "algorithm. Disabling WPA support\n", dev->name); - priv->has_wpa = 0; - } - } - - /* Now we have the firmware capabilities, allocate appropiate - * sized scan buffers */ - if (orinoco_bss_data_allocate(priv)) - goto out; - orinoco_bss_data_init(priv); - - /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, dev->dev_addr); - if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); - goto out; - } - - printk(KERN_DEBUG "%s: MAC address %pM\n", - dev->name, dev->dev_addr); - - /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - printk(KERN_ERR "%s: failed to read station name\n", - dev->name); - goto out; - } - if (nickbuf.len) - len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); - else - len = min(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); - - err = orinoco_allocate_fid(dev); - if (err) { - printk(KERN_ERR "%s: failed to allocate NIC buffer!\n", - dev->name); - goto out; - } - - /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, - &priv->channel_mask); - if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - &priv->ap_density); - if (err || priv->ap_density < 1 || priv->ap_density > 3) { - priv->has_sensitivity = 0; - } - - /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - &priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", - dev->name); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &priv->mwo_robust); - else - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", - dev->name); - goto out; - } - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - &priv->pm_period); - if (err) { - printk(KERN_ERR "%s: failed to read power management period!\n", - dev->name); - goto out; - } - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - &priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: failed to read power management timeout!\n", - dev->name); - goto out; - } - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - &priv->preamble); - if (err) - goto out; - } - - /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; - /* By default use IEEE/IBSS ad-hoc mode if we have it */ - priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); - set_port_type(priv); - priv->channel = 0; /* use firmware default */ - - priv->promiscuous = 0; - priv->encode_alg = IW_ENCODE_ALG_NONE; - priv->tx_key = 0; - priv->wpa_enabled = 0; - priv->tkip_cm_active = 0; - priv->key_mgmt = 0; - priv->wpa_ie_len = 0; - priv->wpa_ie = NULL; - - /* Make the hardware available, as long as it hasn't been - * removed elsewhere (e.g. by PCMCIA hot unplug) */ - spin_lock_irq(&priv->lock); - priv->hw_unavailable--; - spin_unlock_irq(&priv->lock); - - printk(KERN_DEBUG "%s: ready\n", dev->name); - - out: - return err; -} - -struct net_device -*alloc_orinocodev(int sizeof_card, - struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)) -{ - struct net_device *dev; - struct orinoco_private *priv; - - dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); - if (! dev) - return NULL; - priv = netdev_priv(dev); - priv->ndev = dev; - if (sizeof_card) - priv->card = (void *)((unsigned long)priv - + sizeof(struct orinoco_private)); - else - priv->card = NULL; - priv->dev = device; - - /* Setup / override net_device fields */ - dev->init = orinoco_init; - dev->hard_start_xmit = orinoco_xmit; - dev->tx_timeout = orinoco_tx_timeout; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->get_stats = orinoco_get_stats; - dev->ethtool_ops = &orinoco_ethtool_ops; - dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def; -#ifdef WIRELESS_SPY - priv->wireless_data.spy_data = &priv->spy_data; - dev->wireless_data = &priv->wireless_data; -#endif - dev->change_mtu = orinoco_change_mtu; - dev->set_multicast_list = orinoco_set_multicast_list; - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Reserve space in skb for the SNAP header */ - dev->hard_header_len += ENCAPS_OVERHEAD; - - /* Set up default callbacks */ - dev->open = orinoco_open; - dev->stop = orinoco_stop; - priv->hard_reset = hard_reset; - priv->stop_fw = stop_fw; - - spin_lock_init(&priv->lock); - priv->open = 0; - priv->hw_unavailable = 1; /* orinoco_init() must clear this - * before anything else touches the - * hardware */ - INIT_WORK(&priv->reset_work, orinoco_reset); - INIT_WORK(&priv->join_work, orinoco_join_ap); - INIT_WORK(&priv->wevent_work, orinoco_send_wevents); - - INIT_LIST_HEAD(&priv->rx_list); - tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, - (unsigned long) dev); - - netif_carrier_off(dev); - priv->last_linkstatus = 0xffff; - - priv->cached_fw = NULL; - - return dev; -} - -void free_orinocodev(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - - /* No need to empty priv->rx_list: if the tasklet is scheduled - * when we call tasklet_kill it will run one final time, - * emptying the list */ - tasklet_kill(&priv->rx_tasklet); - if (priv->cached_fw) - release_firmware(priv->cached_fw); - priv->cached_fw = NULL; - priv->wpa_ie_len = 0; - kfree(priv->wpa_ie); - orinoco_mic_free(priv); - orinoco_bss_data_free(priv); - free_netdev(dev); -} - -/********************************************************************/ -/* Wireless extensions */ -/********************************************************************/ - -/* Return : < 0 -> error code ; >= 0 -> length */ -static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) -{ - hermes_t *hw = &priv->hw; - int err = 0; - struct hermes_idstring essidbuf; - char *p = (char *)(&essidbuf.val); - int len; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (strlen(priv->desired_essid) > 0) { - /* We read the desired SSID from the hardware rather - than from priv->desired_essid, just in case the - firmware is allowed to change it on us. I'm not - sure about this */ - /* My guess is that the OWNSSID should always be whatever - * we set to the card, whereas CURRENT_SSID is the one that - * may change... - Jean II */ - u16 rid; - - *active = 1; - - rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : - HERMES_RID_CNFDESIREDSSID; - - err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), - NULL, &essidbuf); - if (err) - goto fail_unlock; - } else { - *active = 0; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, - sizeof(essidbuf), NULL, &essidbuf); - if (err) - goto fail_unlock; - } - - len = le16_to_cpu(essidbuf.len); - BUG_ON(len > IW_ESSID_MAX_SIZE); - - memset(buf, 0, IW_ESSID_MAX_SIZE); - memcpy(buf, p, len); - err = len; - - fail_unlock: - orinoco_unlock(priv, &flags); - - return err; -} - -static long orinoco_hw_get_freq(struct orinoco_private *priv) -{ - - hermes_t *hw = &priv->hw; - int err = 0; - u16 channel; - long freq = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); - if (err) - goto out; - - /* Intersil firmware 1.3.5 returns 0 when the interface is down */ - if (channel == 0) { - err = -EBUSY; - goto out; - } - - if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", - priv->ndev->name, channel); - err = -EBUSY; - goto out; - - } - freq = channel_frequency[channel-1] * 100000; - - out: - orinoco_unlock(priv, &flags); - - if (err > 0) - err = -EBUSY; - return err ? err : freq; -} - -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, - int *numrates, s32 *rates, int max) -{ - hermes_t *hw = &priv->hw; - struct hermes_idstring list; - unsigned char *p = (unsigned char *)&list.val; - int err = 0; - int num; - int i; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, - sizeof(list), NULL, &list); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - num = le16_to_cpu(list.len); - *numrates = num; - num = min(num, max); - - for (i = 0; i < num; i++) { - rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ - } - - return 0; -} - -static int orinoco_ioctl_getname(struct net_device *dev, - struct iw_request_info *info, - char *name, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int numrates; - int err; - - err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0); - - if (!err && (numrates > 2)) - strcpy(name, "IEEE 802.11b"); - else - strcpy(name, "IEEE 802.11-DS"); - - return 0; -} - -static int orinoco_ioctl_setwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Enable automatic roaming - no sanity checks are needed */ - if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 || - memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) { - priv->bssid_fixed = 0; - memset(priv->desired_bssid, 0, ETH_ALEN); - - /* "off" means keep existing connection */ - if (ap_addr->sa_data[0] == 0) { - __orinoco_hw_set_wap(priv); - err = 0; - } - goto out; - } - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { - printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " - "support manual roaming\n", - dev->name); - err = -EOPNOTSUPP; - goto out; - } - - if (priv->iw_mode != IW_MODE_INFRA) { - printk(KERN_WARNING "%s: Manual roaming supported only in " - "managed mode\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Intersil firmware hangs without Desired ESSID */ - if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && - strlen(priv->desired_essid) == 0) { - printk(KERN_WARNING "%s: Desired ESSID must be set for " - "manual roaming\n", dev->name); - err = -EOPNOTSUPP; - goto out; - } - - /* Finally, enable manual roaming */ - priv->bssid_fixed = 1; - memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_getwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - - hermes_t *hw = &priv->hw; - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - ap_addr->sa_family = ARPHRD_ETHER; - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, ap_addr->sa_data); - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_setmode(struct net_device *dev, - struct iw_request_info *info, - u32 *mode, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (priv->iw_mode == *mode) - return 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (*mode) { - case IW_MODE_ADHOC: - if (!priv->has_ibss && !priv->has_port3) - err = -EOPNOTSUPP; - break; - - case IW_MODE_INFRA: - break; - - case IW_MODE_MONITOR: - if (priv->broken_monitor && !force_monitor) { - printk(KERN_WARNING "%s: Monitor mode support is " - "buggy in this firmware, not enabling\n", - dev->name); - err = -EOPNOTSUPP; - } - break; - - default: - err = -EOPNOTSUPP; - break; - } - - if (err == -EINPROGRESS) { - priv->iw_mode = *mode; - set_port_type(priv); - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getmode(struct net_device *dev, - struct iw_request_info *info, - u32 *mode, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - - *mode = priv->iw_mode; - return 0; -} - -static int orinoco_ioctl_getiwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *rrq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = 0; - struct iw_range *range = (struct iw_range *) extra; - int numrates; - int i, k; - - rrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 22; - - /* Set available channels/frequencies */ - range->num_channels = NUM_CHANNELS; - k = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - range->freq[k].i = i + 1; - range->freq[k].m = channel_frequency[i] * 100000; - range->freq[k].e = 1; - k++; - } - - if (k >= IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = k; - range->sensitivity = 3; - - if (priv->has_wep) { - range->max_encoding_tokens = ORINOCO_MAX_KEYS; - range->encoding_size[0] = SMALL_KEY_SIZE; - range->num_encoding_sizes = 1; - - if (priv->has_big_wep) { - range->encoding_size[1] = LARGE_KEY_SIZE; - range->num_encoding_sizes = 2; - } - } - - if (priv->has_wpa) - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; - - if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ - /* Quality stats meaningless in ad-hoc mode */ - } else { - range->max_qual.qual = 0x8b - 0x2f; - range->max_qual.level = 0x2f - 0x95 - 1; - range->max_qual.noise = 0x2f - 0x95 - 1; - /* Need to get better values */ - range->avg_qual.qual = 0x24; - range->avg_qual.level = 0xC2; - range->avg_qual.noise = 0x9E; - } - - err = orinoco_hw_get_bitratelist(priv, &numrates, - range->bitrate, IW_MAX_BITRATES); - if (err) - return err; - range->num_bitrates = numrates; - - /* Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface. May be use for QoS stuff... - * Jean II */ - if (numrates > 2) - range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ - else - range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->min_pmp = 0; - range->max_pmp = 65535000; - range->min_pmt = 0; - range->max_pmt = 65535 * 1000; /* ??? */ - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; - - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - range->min_retry = 0; - range->max_retry = 65535; /* ??? */ - range->min_r_time = 0; - range->max_r_time = 65535 * 1000; /* ??? */ - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - range->scan_capa = IW_SCAN_CAPA_ESSID; - else - range->scan_capa = IW_SCAN_CAPA_NONE; - - /* Event capability (kernel) */ - IW_EVENT_CAPA_SET_KERNEL(range->event_capa); - /* Event capability (driver) */ - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); - IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); - - return 0; -} - -static int orinoco_ioctl_setiwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, - char *keybuf) -{ - struct orinoco_private *priv = netdev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - int setindex = priv->tx_key; - int encode_alg = priv->encode_alg; - int restricted = priv->wep_restrict; - u16 xlen = 0; - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (! priv->has_wep) - return -EOPNOTSUPP; - - if (erq->pointer) { - /* We actually have a key to set - check its length */ - if (erq->length > LARGE_KEY_SIZE) - return -E2BIG; - - if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) - return -E2BIG; - } - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Clear any TKIP key we have */ - if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) - (void) orinoco_clear_tkip_key(priv, setindex); - - if (erq->length > 0) { - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - /* Adjust key length to a supported value */ - if (erq->length > SMALL_KEY_SIZE) { - xlen = LARGE_KEY_SIZE; - } else if (erq->length > 0) { - xlen = SMALL_KEY_SIZE; - } else - xlen = 0; - - /* Switch on WEP if off */ - if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { - setindex = index; - encode_alg = IW_ENCODE_ALG_WEP; - } - } else { - /* Important note : if the user do "iwconfig eth0 enc off", - * we will arrive there with an index of -1. This is valid - * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { - if((index != -1) || (erq->flags == 0)) { - err = -EINVAL; - goto out; - } - } else { - /* Set the index : Check that the key is valid */ - if(priv->keys[index].len == 0) { - err = -EINVAL; - goto out; - } - setindex = index; - } - } - - if (erq->flags & IW_ENCODE_DISABLED) - encode_alg = IW_ENCODE_ALG_NONE; - if (erq->flags & IW_ENCODE_OPEN) - restricted = 0; - if (erq->flags & IW_ENCODE_RESTRICTED) - restricted = 1; - - if (erq->pointer && erq->length > 0) { - priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, - sizeof(priv->keys[index].data)); - memcpy(priv->keys[index].data, keybuf, erq->length); - } - priv->tx_key = setindex; - - /* Try fast key change if connected and only keys are changed */ - if ((priv->encode_alg == encode_alg) && - (priv->wep_restrict == restricted) && - netif_carrier_ok(dev)) { - err = __orinoco_hw_setup_wepkeys(priv); - /* No need to commit if successful */ - goto out; - } - - priv->encode_alg = encode_alg; - priv->wep_restrict = restricted; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getiwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, - char *keybuf) -{ - struct orinoco_private *priv = netdev_priv(dev); - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - u16 xlen = 0; - unsigned long flags; - - if (! priv->has_wep) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) - index = priv->tx_key; - - erq->flags = 0; - if (!priv->encode_alg) - erq->flags |= IW_ENCODE_DISABLED; - erq->flags |= index + 1; - - if (priv->wep_restrict) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - xlen = le16_to_cpu(priv->keys[index].len); - - erq->length = xlen; - - memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); - - orinoco_unlock(priv, &flags); - return 0; -} - -static int orinoco_ioctl_setessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, - char *essidbuf) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it - * anyway... - Jean II */ - - /* Hum... Should not use Wireless Extension constant (may change), - * should use our own... - Jean II */ - if (erq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ - memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); - - /* If not ANY, get the new ESSID */ - if (erq->flags) { - memcpy(priv->desired_essid, essidbuf, erq->length); - } - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, - char *essidbuf) -{ - struct orinoco_private *priv = netdev_priv(dev); - int active; - int err = 0; - unsigned long flags; - - if (netif_running(dev)) { - err = orinoco_hw_get_essid(priv, &active, essidbuf); - if (err < 0) - return err; - erq->length = err; - } else { - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); - erq->length = strlen(priv->desired_essid); - orinoco_unlock(priv, &flags); - } - - erq->flags = 1; - - return 0; -} - -static int orinoco_ioctl_setnick(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *nrq, - char *nickbuf) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - if (nrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, nickbuf, nrq->length); - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getnick(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *nrq, - char *nickbuf) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE); - orinoco_unlock(priv, &flags); - - nrq->length = strlen(priv->nick); - - return 0; -} - -static int orinoco_ioctl_setfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *frq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int chan = -1; - unsigned long flags; - int err = -EINPROGRESS; /* Call commit handler */ - - /* In infrastructure mode the AP sets the channel */ - if (priv->iw_mode == IW_MODE_INFRA) - return -EBUSY; - - if ( (frq->e == 0) && (frq->m <= 1000) ) { - /* Setting by channel number */ - chan = frq->m; - } else { - /* Setting by frequency - search the table */ - int mult = 1; - int i; - - for (i = 0; i < (6 - frq->e); i++) - mult *= 10; - - for (i = 0; i < NUM_CHANNELS; i++) - if (frq->m == (channel_frequency[i] * mult)) - chan = i+1; - } - - if ( (chan < 1) || (chan > NUM_CHANNELS) || - ! (priv->channel_mask & (1 << (chan-1)) ) ) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->channel = chan; - if (priv->iw_mode == IW_MODE_MONITOR) { - /* Fast channel change - no commit if successful */ - hermes_t *hw = &priv->hw; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_SET_CHANNEL, - chan, NULL); - } - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *frq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int tmp; - - /* Locking done in there */ - tmp = orinoco_hw_get_freq(priv); - if (tmp < 0) { - return tmp; - } - - frq->m = tmp; - frq->e = 1; - - return 0; -} - -static int orinoco_ioctl_getsens(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - u16 val; - int err; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, &val); - orinoco_unlock(priv, &flags); - - if (err) - return err; - - srq->value = val; - srq->fixed = 0; /* auto */ - - return 0; -} - -static int orinoco_ioctl_setsens(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int val = srq->value; - unsigned long flags; - - if (!priv->has_sensitivity) - return -EOPNOTSUPP; - - if ((val < 1) || (val > 3)) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->ap_density = val; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_setrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rrq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int val = rrq->value; - unsigned long flags; - - if (rrq->disabled) - val = 2347; - - if ( (val < 0) || (val > 2347) ) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->rts_thresh = val; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rrq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - - rrq->value = priv->rts_thresh; - rrq->disabled = (rrq->value == 2347); - rrq->fixed = 1; - - return 0; -} - -static int orinoco_ioctl_setfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (priv->has_mwo) { - if (frq->disabled) - priv->mwo_robust = 0; - else { - if (frq->fixed) - printk(KERN_WARNING "%s: Fixed fragmentation is " - "not supported on this firmware. " - "Using MWO robust instead.\n", dev->name); - priv->mwo_robust = 1; - } - } else { - if (frq->disabled) - priv->frag_thresh = 2346; - else { - if ( (frq->value < 256) || (frq->value > 2346) ) - err = -EINVAL; - else - priv->frag_thresh = frq->value & ~0x1; /* must be even */ - } - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - u16 val; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (priv->has_mwo) { - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &val); - if (err) - val = 0; - - frq->value = val ? 2347 : 0; - frq->disabled = ! val; - frq->fixed = 0; - } else { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &val); - if (err) - val = 0; - - frq->value = val; - frq->disabled = (val >= 2346); - frq->fixed = 1; - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_setrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rrq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int ratemode = -1; - int bitrate; /* 100s of kilobits */ - int i; - unsigned long flags; - - /* As the user space doesn't know our highest rate, it uses -1 - * to ask us to set the highest rate. Test it using "iwconfig - * ethX rate auto" - Jean II */ - if (rrq->value == -1) - bitrate = 110; - else { - if (rrq->value % 100000) - return -EINVAL; - bitrate = rrq->value / 100000; - } - - if ( (bitrate != 10) && (bitrate != 20) && - (bitrate != 55) && (bitrate != 110) ) - return -EINVAL; - - for (i = 0; i < BITRATE_TABLE_SIZE; i++) - if ( (bitrate_table[i].bitrate == bitrate) && - (bitrate_table[i].automatic == ! rrq->fixed) ) { - ratemode = i; - break; - } - - if (ratemode == -1) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - priv->bitratemode = ratemode; - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; -} - -static int orinoco_ioctl_getrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rrq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err = 0; - int ratemode; - int i; - u16 val; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - ratemode = priv->bitratemode; - - BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); - - rrq->value = bitrate_table[ratemode].bitrate * 100000; - rrq->fixed = ! bitrate_table[ratemode].automatic; - rrq->disabled = 0; - - /* If the interface is running we try to find more about the - current mode */ - if (netif_running(dev)) { - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CURRENTTXRATE, &val); - if (err) - goto out; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ - /* Note : in Lucent firmware, the return value of - * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, - * and therefore is totally different from the - * encoding of HERMES_RID_CNFTXRATECONTROL. - * Don't forget that 6Mb/s is really 5.5Mb/s */ - if (val == 6) - rrq->value = 5500000; - else - rrq->value = val * 1000000; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - for (i = 0; i < BITRATE_TABLE_SIZE; i++) - if (bitrate_table[i].intersil_txratectrl == val) { - ratemode = i; - break; - } - if (i >= BITRATE_TABLE_SIZE) - printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", - dev->name, val); - - rrq->value = bitrate_table[ratemode].bitrate * 100000; - break; - default: - BUG(); - } - } - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_setpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *prq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (prq->disabled) { - priv->pm_on = 0; - } else { - switch (prq->flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - priv->pm_mcast = 0; - priv->pm_on = 1; - break; - case IW_POWER_ALL_R: - priv->pm_mcast = 1; - priv->pm_on = 1; - break; - case IW_POWER_ON: - /* No flags : but we may have a value - Jean II */ - break; - default: - err = -EINVAL; - goto out; - } - - if (prq->flags & IW_POWER_TIMEOUT) { - priv->pm_on = 1; - priv->pm_timeout = prq->value / 1000; - } - if (prq->flags & IW_POWER_PERIOD) { - priv->pm_on = 1; - priv->pm_period = prq->value / 1000; - } - /* It's valid to not have a value if we are just toggling - * the flags... Jean II */ - if(!priv->pm_on) { - err = -EINVAL; - goto out; - } - } - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *prq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err = 0; - u16 enable, period, timeout, mcast; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, &period); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast); - if (err) - goto out; - - prq->disabled = !enable; - /* Note : by default, display the period */ - if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - prq->flags = IW_POWER_TIMEOUT; - prq->value = timeout * 1000; - } else { - prq->flags = IW_POWER_PERIOD; - prq->value = period * 1000; - } - if (mcast) - prq->flags |= IW_POWER_ALL_R; - else - prq->flags |= IW_POWER_UNICAST_R; - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, alg = ext->alg, set_key = 1; - unsigned long flags; - int err = -EINVAL; - u16 key_len; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Determine and validate the key index */ - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - if (encoding->flags & IW_ENCODE_DISABLED) - alg = IW_ENCODE_ALG_NONE; - - if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { - /* Clear any TKIP TX key we had */ - (void) orinoco_clear_tkip_key(priv, priv->tx_key); - } - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - priv->tx_key = idx; - set_key = ((alg == IW_ENCODE_ALG_TKIP) || - (ext->key_len > 0)) ? 1 : 0; - } - - if (set_key) { - /* Set the requested key first */ - switch (alg) { - case IW_ENCODE_ALG_NONE: - priv->encode_alg = alg; - priv->keys[idx].len = 0; - break; - - case IW_ENCODE_ALG_WEP: - if (ext->key_len > SMALL_KEY_SIZE) - key_len = LARGE_KEY_SIZE; - else if (ext->key_len > 0) - key_len = SMALL_KEY_SIZE; - else - goto out; - - priv->encode_alg = alg; - priv->keys[idx].len = cpu_to_le16(key_len); - - key_len = min(ext->key_len, key_len); - - memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); - memcpy(priv->keys[idx].data, ext->key, key_len); - break; - - case IW_ENCODE_ALG_TKIP: - { - hermes_t *hw = &priv->hw; - u8 *tkip_iv = NULL; - - if (!priv->has_wpa || - (ext->key_len > sizeof(priv->tkip_key[0]))) - goto out; - - priv->encode_alg = alg; - memset(&priv->tkip_key[idx], 0, - sizeof(priv->tkip_key[idx])); - memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); - - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - tkip_iv = &ext->rx_seq[0]; - - err = __orinoco_hw_set_tkip_key(hw, idx, - ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - (u8 *) &priv->tkip_key[idx], - tkip_iv, NULL); - if (err) - printk(KERN_ERR "%s: Error %d setting TKIP key" - "\n", dev->name, err); - - goto out; - } - default: - goto out; - } - } - err = -EINPROGRESS; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - unsigned long flags; - int err; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = -EINVAL; - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - goto out; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if ((idx < 1) || (idx > 4)) - goto out; - idx--; - } else - idx = priv->tx_key; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - ext->alg = priv->encode_alg; - switch (priv->encode_alg) { - case IW_ENCODE_ALG_NONE: - ext->key_len = 0; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case IW_ENCODE_ALG_WEP: - ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), - max_key_len); - memcpy(ext->key, priv->keys[idx].data, ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - case IW_ENCODE_ALG_TKIP: - ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), - max_key_len); - memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); - encoding->flags |= IW_ENCODE_ENABLED; - break; - } - - err = 0; - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = -EINPROGRESS; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_PRIVACY_INVOKED: - case IW_AUTH_DROP_UNENCRYPTED: - /* - * orinoco does not use these parameters - */ - break; - - case IW_AUTH_KEY_MGMT: - /* wl_lkm implies value 2 == PSK for Hermes I - * which ties in with WEXT - * no other hints tho :( - */ - priv->key_mgmt = param->value; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - /* When countermeasures are enabled, shut down the - * card; when disabled, re-enable the card. This must - * take effect immediately. - * - * TODO: Make sure that the EAPOL message is getting - * out before card disabled - */ - if (param->value) { - priv->tkip_cm_active = 1; - ret = hermes_enable_port(hw, 0); - } else { - priv->tkip_cm_active = 0; - ret = hermes_disable_port(hw, 0); - } - break; - - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - priv->wep_restrict = 1; - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - priv->wep_restrict = 0; - else - ret = -EINVAL; - break; - - case IW_AUTH_WPA_ENABLED: - if (priv->has_wpa) { - priv->wpa_enabled = param->value ? 1 : 0; - } else { - if (param->value) - ret = -EOPNOTSUPP; - /* else silently accept disable of WPA */ - priv->wpa_enabled = 0; - } - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct iw_param *param = &wrqu->param; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_KEY_MGMT: - param->value = priv->key_mgmt; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - param->value = priv->tkip_cm_active; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (priv->wep_restrict) - param->value = IW_AUTH_ALG_SHARED_KEY; - else - param->value = IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = priv->wpa_enabled; - break; - - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - u8 *buf; - unsigned long flags; - int err = 0; - - /* cut off at IEEE80211_MAX_DATA_LEN */ - if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || - (wrqu->data.length && (extra == NULL))) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (wrqu->data.length) { - buf = kmalloc(wrqu->data.length, GFP_KERNEL); - if (buf == NULL) { - err = -ENOMEM; - goto out; - } - - memcpy(buf, extra, wrqu->data.length); - kfree(priv->wpa_ie); - priv->wpa_ie = buf; - priv->wpa_ie_len = wrqu->data.length; - } else { - kfree(priv->wpa_ie); - priv->wpa_ie = NULL; - priv->wpa_ie_len = 0; - } - - if (priv->wpa_ie) { - /* Looks like wl_lkm wants to check the auth alg, and - * somehow pass it to the firmware. - * Instead it just calls the key mgmt rid - * - we do this in set auth. - */ - } - -out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { - wrqu->data.length = 0; - goto out; - } - - if (wrqu->data.length < priv->wpa_ie_len) { - err = -E2BIG; - goto out; - } - - wrqu->data.length = priv->wpa_ie_len; - memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); - -out: - orinoco_unlock(priv, &flags); - return err; -} - -static int orinoco_ioctl_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_mlme *mlme = (struct iw_mlme *)extra; - unsigned long flags; - int ret = 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* silently ignore */ - break; - - case IW_MLME_DISASSOC: - { - struct { - u8 addr[ETH_ALEN]; - __le16 reason_code; - } __attribute__ ((packed)) buf; - - memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); - buf.reason_code = cpu_to_le16(mlme->reason_code); - ret = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFDISASSOCIATE, - &buf); - break; - } - default: - ret = -EOPNOTSUPP; - } - - orinoco_unlock(priv, &flags); - return ret; -} - -static int orinoco_ioctl_getretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rrq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err = 0; - u16 short_limit, long_limit, lifetime; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, - &short_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, - &long_limit); - if (err) - goto out; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, - &lifetime); - if (err) - goto out; - - rrq->disabled = 0; /* Can't be disabled */ - - /* Note : by default, display the retry number */ - if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - rrq->flags = IW_RETRY_LIFETIME; - rrq->value = lifetime * 1000; /* ??? */ - } else { - /* By default, display the min number */ - if ((rrq->flags & IW_RETRY_LONG)) { - rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - rrq->value = long_limit; - } else { - rrq->flags = IW_RETRY_LIMIT; - rrq->value = short_limit; - if(short_limit != long_limit) - rrq->flags |= IW_RETRY_SHORT; - } - } - - out: - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_reset(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - - if (! capable(CAP_NET_ADMIN)) - return -EPERM; - - if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { - printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - - /* Firmware reset */ - orinoco_reset(&priv->reset_work); - } else { - printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); - - schedule_work(&priv->reset_work); - } - - return 0; -} - -static int orinoco_ioctl_setibssport(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) - -{ - struct orinoco_private *priv = netdev_priv(dev); - int val = *( (int *) extra ); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - priv->ibss_port = val ; - - /* Actually update the mode we are using */ - set_port_type(priv); - - orinoco_unlock(priv, &flags); - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getibssport(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int *val = (int *) extra; - - *val = priv->ibss_port; - return 0; -} - -static int orinoco_ioctl_setport3(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int val = *( (int *) extra ); - int err = 0; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (val) { - case 0: /* Try to do IEEE ad-hoc mode */ - if (! priv->has_ibss) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 0; - - break; - - case 1: /* Try to do Lucent proprietary ad-hoc mode */ - if (! priv->has_port3) { - err = -EINVAL; - break; - } - priv->prefer_port3 = 1; - break; - - default: - err = -EINVAL; - } - - if (! err) { - /* Actually update the mode we are using */ - set_port_type(priv); - err = -EINPROGRESS; - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getport3(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int *val = (int *) extra; - - *val = priv->prefer_port3; - return 0; -} - -static int orinoco_ioctl_setpreamble(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int val; - - if (! priv->has_preamble) - return -EOPNOTSUPP; - - /* 802.11b has recently defined some short preamble. - * Basically, the Phy header has been reduced in size. - * This increase performance, especially at high rates - * (the preamble is transmitted at 1Mb/s), unfortunately - * this give compatibility troubles... - Jean II */ - val = *( (int *) extra ); - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (val) - priv->preamble = 1; - else - priv->preamble = 0; - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getpreamble(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int *val = (int *) extra; - - if (! priv->has_preamble) - return -EOPNOTSUPP; - - *val = priv->preamble; - return 0; -} - -/* ioctl interface to hermes_read_ltv() - * To use with iwpriv, pass the RID as the token argument, e.g. - * iwpriv get_rid [0xfc00] - * At least Wireless Tools 25 is required to use iwpriv. - * For Wireless Tools 25 and 26 append "dummy" are the end. */ -static int orinoco_ioctl_getrid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int rid = data->flags; - u16 length; - int err; - unsigned long flags; - - /* It's a "get" function, but we don't want users to access the - * WEP key and other raw firmware data */ - if (! capable(CAP_NET_ADMIN)) - return -EPERM; - - if (rid < 0xfc00 || rid > 0xffff) - return -EINVAL; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, - extra); - if (err) - goto out; - - data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), - MAX_RID_LEN); - - out: - orinoco_unlock(priv, &flags); - return err; -} - -/* Trigger a scan (look for other cells in the vicinity) */ -static int orinoco_ioctl_setscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_scan_req *si = (struct iw_scan_req *) extra; - int err = 0; - unsigned long flags; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Scanning with port 0 disabled would fail */ - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - /* In monitor mode, the scan results are always empty. - * Probe responses are passed to the driver as received - * frames and could be processed in software. */ - if (priv->iw_mode == IW_MODE_MONITOR) { - err = -EOPNOTSUPP; - goto out; - } - - /* Note : because we don't lock out the irq handler, the way - * we access scan variables in priv is critical. - * o scan_inprogress : not touched by irq handler - * o scan_mode : not touched by irq handler - * Before modifying anything on those variables, please think hard ! - * Jean II */ - - /* Save flags */ - priv->scan_mode = srq->flags; - - /* Always trigger scanning, even if it's in progress. - * This way, if the info frame get lost, we will recover somewhat - * gracefully - Jean II */ - - if (priv->has_hostscan) { - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN_SYMBOL, - HERMES_HOSTSCAN_SYMBOL_ONCE | - HERMES_HOSTSCAN_SYMBOL_BCAST); - break; - case FIRMWARE_TYPE_INTERSIL: { - __le16 req[3]; - - req[0] = cpu_to_le16(0x3fff); /* All channels */ - req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ - req[2] = 0; /* Any ESSID */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN, &req); - } - break; - case FIRMWARE_TYPE_AGERE: - if (priv->scan_mode & IW_SCAN_THIS_ESSID) { - struct hermes_idstring idbuf; - size_t len = min(sizeof(idbuf.val), - (size_t) si->essid_len); - idbuf.len = cpu_to_le16(len); - memcpy(idbuf.val, si->essid, len); - - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - HERMES_BYTES_TO_RECLEN(len + 2), - &idbuf); - } else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - 0); /* Any ESSID */ - if (err) - break; - - if (priv->has_ext_scan) { - /* Clear scan results at the start of - * an extended scan */ - orinoco_clear_scan_results(priv, - msecs_to_jiffies(15000)); - - /* TODO: Is this available on older firmware? - * Can we use it to scan specific channels - * for IW_SCAN_THIS_FREQ? */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANCHANNELS2GHZ, - 0x7FFF); - if (err) - goto out; - - err = hermes_inquire(hw, - HERMES_INQ_CHANNELINFO); - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - break; - } - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - /* One more client */ - if (! err) - priv->scan_inprogress = 1; - - out: - orinoco_unlock(priv, &flags); - return err; -} - -#define MAX_CUSTOM_LEN 64 - -/* Translate scan data returned from the card to a card independant - * format that the Wireless Tools will understand - Jean II */ -static inline char *orinoco_translate_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - union hermes_scan_info *bss, - unsigned int last_scanned) -{ - struct orinoco_private *priv = netdev_priv(dev); - u16 capabilities; - u16 channel; - struct iw_event iwe; /* Temporary buffer */ - char custom[MAX_CUSTOM_LEN]; - - memset(&iwe, 0, sizeof(iwe)); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = le16_to_cpu(bss->a.essid_len); - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->a.essid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(bss->a.capabilities); - if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - channel = bss->s.channel; - if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add channel and frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.u.freq.m = channel_frequency[channel-1] * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - /* Add quality statistics. level and noise in dB. No link quality */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; - iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; - iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* Bit rate is not available in Lucent/Agere firmwares */ - if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { - char *current_val = current_ev + iwe_stream_lcp_len(info); - int i; - int step; - - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - step = 2; - else - step = 1; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 10 values */ - for (i = 0; i < 10; i += step) { - /* NULL terminated */ - if (bss->p.rates[i] == 0x0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = - ((bss->p.rates[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value(info, current_ev, - current_val, - end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - /* Beacon interval */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "bcn_int=%d", - le16_to_cpu(bss->a.beacon_interv)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Capabilites */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "capab=0x%04x", - capabilities); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - return current_ev; -} - -static inline char *orinoco_translate_ext_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - struct agere_ext_scan_info *bss, - unsigned int last_scanned) -{ - u16 capabilities; - u16 channel; - struct iw_event iwe; /* Temporary buffer */ - char custom[MAX_CUSTOM_LEN]; - u8 *ie; - - memset(&iwe, 0, sizeof(iwe)); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - ie = bss->data; - iwe.u.data.length = ie[1]; - if (iwe.u.data.length) { - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, &ie[2]); - } - - /* Add mode */ - capabilities = le16_to_cpu(bss->capabilities); - if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - iwe.cmd = SIOCGIWMODE; - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); - channel = ie ? ie[2] : 0; - if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add channel and frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.u.freq.m = channel_frequency[channel-1] * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - /* Add quality statistics. level and noise in dB. No link quality */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; - iwe.u.qual.level = bss->level - 0x95; - iwe.u.qual.noise = bss->noise - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* WPA IE */ - ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); - if (ie) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie[1] + 2; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie); - } - - /* RSN IE */ - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); - if (ie) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie[1] + 2; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie); - } - - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); - if (ie) { - char *p = current_ev + iwe_stream_lcp_len(info); - int i; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - - for (i = 2; i < (ie[1] + 2); i++) { - iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); - p = iwe_stream_add_value(info, current_ev, p, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if (p > (current_ev + iwe_stream_lcp_len(info))) - current_ev = p; - } - - /* Timestamp */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = - snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", - (unsigned long long) le64_to_cpu(bss->timestamp)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Beacon interval */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "bcn_int=%d", - le16_to_cpu(bss->beacon_interval)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Capabilites */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "capab=0x%04x", - capabilities); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - return current_ev; -} - -/* Return results of a scan */ -static int orinoco_ioctl_getscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int err = 0; - unsigned long flags; - char *current_ev = extra; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (priv->scan_inprogress) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy. - * Second, we grab some rtnetlink lock before comming - * here (in dev_ioctl()). - * Third, we generate an Wireless Event, so the - * caller can wait itself on that - Jean II */ - err = -EAGAIN; - goto out; - } - - if (priv->has_ext_scan) { - struct xbss_element *bss; - - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate this entry to WE format */ - current_ev = - orinoco_translate_ext_scan(dev, info, - current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) - <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a - * bigger buffer */ - err = -E2BIG; - goto out; - } - } - - } else { - struct bss_element *bss; - - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate this entry to WE format */ - current_ev = orinoco_translate_scan(dev, info, - current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) - <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a - * bigger buffer */ - err = -E2BIG; - goto out; - } - } - } - - srq->length = (current_ev - extra); - srq->flags = (__u16) priv->scan_mode; - -out: - orinoco_unlock(priv, &flags); - return err; -} - -/* Commit handler, called after set operations */ -static int orinoco_ioctl_commit(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - unsigned long flags; - int err = 0; - - if (!priv->open) - return 0; - - if (priv->broken_disableport) { - orinoco_reset(&priv->reset_work); - return 0; - } - - if (orinoco_lock(priv, &flags) != 0) - return err; - - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port " - "while reconfiguring card\n", dev->name); - priv->broken_disableport = 1; - goto out; - } - - err = __orinoco_program_rids(dev); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", - dev->name); - goto out; - } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", - dev->name); - goto out; - } - - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; - } - - orinoco_unlock(priv, &flags); - return err; -} - -static const struct iw_priv_args orinoco_privtab[] = { - { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, - { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, - { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_port3" }, - { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_port3" }, - { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_preamble" }, - { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_preamble" }, - { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - 0, "set_ibssport" }, - { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_ibssport" }, - { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, - "get_rid" }, -}; - - -/* - * Structures to export the Wireless Handlers - */ - -#define STD_IW_HANDLER(id, func) \ - [IW_IOCTL_IDX(id)] = (iw_handler) func -static const iw_handler orinoco_handler[] = { - STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), - STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), - STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), - STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), - STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), - STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), - STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), - STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), - STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), - STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), - STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), - STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), - STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), - STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), - STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), - STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), - STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), - STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), - STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), - STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), - STD_IW_HANDLER(SIOCGIWRTS, orinoco_ioctl_getrts), - STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag), - STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag), - STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry), - STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), - STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), - STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), - STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), - STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), - STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), - STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), - STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), - STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), - STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), - STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), -}; - - -/* - Added typecasting since we no longer use iwreq_data -- Moustafa - */ -static const iw_handler orinoco_private_handler[] = { - [0] = (iw_handler) orinoco_ioctl_reset, - [1] = (iw_handler) orinoco_ioctl_reset, - [2] = (iw_handler) orinoco_ioctl_setport3, - [3] = (iw_handler) orinoco_ioctl_getport3, - [4] = (iw_handler) orinoco_ioctl_setpreamble, - [5] = (iw_handler) orinoco_ioctl_getpreamble, - [6] = (iw_handler) orinoco_ioctl_setibssport, - [7] = (iw_handler) orinoco_ioctl_getibssport, - [9] = (iw_handler) orinoco_ioctl_getrid, -}; - -static const struct iw_handler_def orinoco_handler_def = { - .num_standard = ARRAY_SIZE(orinoco_handler), - .num_private = ARRAY_SIZE(orinoco_private_handler), - .num_private_args = ARRAY_SIZE(orinoco_privtab), - .standard = orinoco_handler, - .private = orinoco_private_handler, - .private_args = orinoco_privtab, - .get_wireless_stats = orinoco_get_wireless_stats, -}; - -static void orinoco_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct orinoco_private *priv = netdev_priv(dev); - - strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); - strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); - strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); - if (dev->dev.parent) - strncpy(info->bus_info, dev->dev.parent->bus_id, - sizeof(info->bus_info) - 1); - else - snprintf(info->bus_info, sizeof(info->bus_info) - 1, - "PCMCIA %p", priv->hw.iobase); -} - -static const struct ethtool_ops orinoco_ethtool_ops = { - .get_drvinfo = orinoco_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -EXPORT_SYMBOL(alloc_orinocodev); -EXPORT_SYMBOL(free_orinocodev); - -EXPORT_SYMBOL(__orinoco_up); -EXPORT_SYMBOL(__orinoco_down); -EXPORT_SYMBOL(orinoco_reinit_firmware); - -EXPORT_SYMBOL(orinoco_interrupt); - -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (David Gibson , " - "Pavel Roskin , et al)"; - -static int __init init_orinoco(void) -{ - printk(KERN_DEBUG "%s\n", version); - return 0; -} - -static void __exit exit_orinoco(void) -{ -} - -module_init(init_orinoco); -module_exit(exit_orinoco); diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h deleted file mode 100644 index 8c29538..0000000 --- a/drivers/net/wireless/orinoco.h +++ /dev/null @@ -1,218 +0,0 @@ -/* orinoco.h - * - * Common definitions to all pieces of the various orinoco - * drivers - */ - -#ifndef _ORINOCO_H -#define _ORINOCO_H - -#define DRIVER_VERSION "0.15" - -#include -#include -#include -#include - -#include "hermes.h" - -/* To enable debug messages */ -//#define ORINOCO_DEBUG 3 - -#define WIRELESS_SPY // enable iwspy support - -#define MAX_SCAN_LEN 4096 - -#define ORINOCO_MAX_KEY_SIZE 14 -#define ORINOCO_MAX_KEYS 4 - -struct orinoco_key { - __le16 len; /* always stored as little-endian */ - char data[ORINOCO_MAX_KEY_SIZE]; -} __attribute__ ((packed)); - -#define TKIP_KEYLEN 16 -#define MIC_KEYLEN 8 - -struct orinoco_tkip_key { - u8 tkip[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; -}; - -typedef enum { - FIRMWARE_TYPE_AGERE, - FIRMWARE_TYPE_INTERSIL, - FIRMWARE_TYPE_SYMBOL -} fwtype_t; - -struct bss_element { - union hermes_scan_info bss; - unsigned long last_scanned; - struct list_head list; -}; - -struct xbss_element { - struct agere_ext_scan_info bss; - unsigned long last_scanned; - struct list_head list; -}; - -struct hermes_rx_descriptor; - -struct orinoco_rx_data { - struct hermes_rx_descriptor *desc; - struct sk_buff *skb; - struct list_head list; -}; - -struct firmware; - -struct orinoco_private { - void *card; /* Pointer to card dependent structure */ - struct device *dev; - int (*hard_reset)(struct orinoco_private *); - int (*stop_fw)(struct orinoco_private *, int); - - /* Synchronisation stuff */ - spinlock_t lock; - int hw_unavailable; - struct work_struct reset_work; - - /* Interrupt tasklets */ - struct tasklet_struct rx_tasklet; - struct list_head rx_list; - struct orinoco_rx_data *rx_data; - - /* driver state */ - int open; - u16 last_linkstatus; - struct work_struct join_work; - struct work_struct wevent_work; - - /* Net device stuff */ - struct net_device *ndev; - struct net_device_stats stats; - struct iw_statistics wstats; - - /* Hardware control variables */ - hermes_t hw; - u16 txfid; - - /* Capabilities of the hardware/firmware */ - fwtype_t firmware_type; - char fw_name[32]; - int ibss_port; - int nicbuf_size; - u16 channel_mask; - - /* Boolean capabilities */ - unsigned int has_ibss:1; - unsigned int has_port3:1; - unsigned int has_wep:1; - unsigned int has_big_wep:1; - unsigned int has_mwo:1; - unsigned int has_pm:1; - unsigned int has_preamble:1; - unsigned int has_sensitivity:1; - unsigned int has_hostscan:1; - unsigned int has_alt_txcntl:1; - unsigned int has_ext_scan:1; - unsigned int has_wpa:1; - unsigned int do_fw_download:1; - unsigned int broken_disableport:1; - unsigned int broken_monitor:1; - - /* Configuration paramaters */ - u32 iw_mode; - int prefer_port3; - u16 encode_alg, wep_restrict, tx_key; - struct orinoco_key keys[ORINOCO_MAX_KEYS]; - int bitratemode; - char nick[IW_ESSID_MAX_SIZE+1]; - char desired_essid[IW_ESSID_MAX_SIZE+1]; - char desired_bssid[ETH_ALEN]; - int bssid_fixed; - u16 frag_thresh, mwo_robust; - u16 channel; - u16 ap_density, rts_thresh; - u16 pm_on, pm_mcast, pm_period, pm_timeout; - u16 preamble; -#ifdef WIRELESS_SPY - struct iw_spy_data spy_data; /* iwspy support */ - struct iw_public_data wireless_data; -#endif - - /* Configuration dependent variables */ - int port_type, createibss; - int promiscuous, mc_count; - - /* Scanning support */ - struct list_head bss_list; - struct list_head bss_free_list; - void *bss_xbss_data; - - int scan_inprogress; /* Scan pending... */ - u32 scan_mode; /* Type of scan done */ - - /* WPA support */ - u8 *wpa_ie; - int wpa_ie_len; - - struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; - struct crypto_hash *rx_tfm_mic; - struct crypto_hash *tx_tfm_mic; - - unsigned int wpa_enabled:1; - unsigned int tkip_cm_active:1; - unsigned int key_mgmt:3; - - /* Cached in memory firmware to use in ->resume */ - const struct firmware *cached_fw; -}; - -#ifdef ORINOCO_DEBUG -extern int orinoco_debug; -#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0) -#else -#define DEBUG(n, args...) do { } while (0) -#endif /* ORINOCO_DEBUG */ - -/********************************************************************/ -/* Exported prototypes */ -/********************************************************************/ - -extern struct net_device *alloc_orinocodev( - int sizeof_card, struct device *device, - int (*hard_reset)(struct orinoco_private *), - int (*stop_fw)(struct orinoco_private *, int)); -extern void free_orinocodev(struct net_device *dev); -extern int __orinoco_up(struct net_device *dev); -extern int __orinoco_down(struct net_device *dev); -extern int orinoco_reinit_firmware(struct net_device *dev); -extern irqreturn_t orinoco_interrupt(int irq, void * dev_id); - -/********************************************************************/ -/* Locking and synchronization functions */ -/********************************************************************/ - -static inline int orinoco_lock(struct orinoco_private *priv, - unsigned long *flags) -{ - spin_lock_irqsave(&priv->lock, *flags); - if (priv->hw_unavailable) { - DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", - priv->ndev); - spin_unlock_irqrestore(&priv->lock, *flags); - return -EBUSY; - } - return 0; -} - -static inline void orinoco_unlock(struct orinoco_private *priv, - unsigned long *flags) -{ - spin_unlock_irqrestore(&priv->lock, *flags); -} - -#endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile new file mode 100644 index 0000000..791366e --- /dev/null +++ b/drivers/net/wireless/orinoco/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the orinoco wireless device drivers. +# + +obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o +obj-$(CONFIG_APPLE_AIRPORT) += airport.o +obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o +obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o +obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o +obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o +obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c new file mode 100644 index 0000000..ce03a2e --- /dev/null +++ b/drivers/net/wireless/orinoco/airport.c @@ -0,0 +1,286 @@ +/* airport.c + * + * A driver for "Hermes" chipset based Apple Airport wireless + * card. + * + * Copyright notice & release notes in file orinoco.c + * + * Note specific to airport stub: + * + * 0.05 : first version of the new split driver + * 0.06 : fix possible hang on powerup, add sleep support + */ + +#define DRIVER_NAME "airport" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include + +#include "orinoco.h" + +#define AIRPORT_IO_LEN (0x1000) /* one page */ + +struct airport { + struct macio_dev *mdev; + void __iomem *vaddr; + int irq_requested; + int ndev_registered; +}; + +static int +airport_suspend(struct macio_dev *mdev, pm_message_t state) +{ + struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", + dev->name); + return 0; + } + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", + dev->name, err); + + netif_device_detach(dev); + + priv->hw_unavailable++; + + orinoco_unlock(priv, &flags); + + disable_irq(dev->irq); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); + + return 0; +} + +static int +airport_resume(struct macio_dev *mdev) +{ + struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); + + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); + msleep(200); + + enable_irq(dev->irq); + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", + dev->name, err); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", + dev->name, err); + } + + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int +airport_detach(struct macio_dev *mdev) +{ + struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); + struct orinoco_private *priv = netdev_priv(dev); + struct airport *card = priv->card; + + if (card->ndev_registered) + unregister_netdev(dev); + card->ndev_registered = 0; + + if (card->irq_requested) + free_irq(dev->irq, dev); + card->irq_requested = 0; + + if (card->vaddr) + iounmap(card->vaddr); + card->vaddr = NULL; + + macio_release_resource(mdev, 0); + + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); + ssleep(1); + + macio_set_drvdata(mdev, NULL); + free_orinocodev(dev); + + return 0; +} + +static int airport_hard_reset(struct orinoco_private *priv) +{ + /* It would be nice to power cycle the Airport for a real hard + * reset, but for some reason although it appears to + * re-initialize properly, it falls in a screaming heap + * shortly afterwards. */ +#if 0 + struct net_device *dev = priv->ndev; + struct airport *card = priv->card; + + /* Vitally important. If we don't do this it seems we get an + * interrupt somewhere during the power cycle, since + * hw_unavailable is already set it doesn't get ACKed, we get + * into an interrupt loop and the PMU decides to turn us + * off. */ + disable_irq(dev->irq); + + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); + ssleep(1); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1); + ssleep(1); + + enable_irq(dev->irq); + ssleep(1); +#endif + + return 0; +} + +static int +airport_attach(struct macio_dev *mdev, const struct of_device_id *match) +{ + struct orinoco_private *priv; + struct net_device *dev; + struct airport *card; + unsigned long phys_addr; + hermes_t *hw; + + if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { + printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n"); + return -ENODEV; + } + + /* Allocate space for private device-specific data */ + dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, + airport_hard_reset, NULL); + if (! dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); + return -ENODEV; + } + priv = netdev_priv(dev); + card = priv->card; + + hw = &priv->hw; + card->mdev = mdev; + + if (macio_request_resource(mdev, 0, "airport")) { + printk(KERN_ERR PFX "can't request IO resource !\n"); + free_orinocodev(dev); + return -EBUSY; + } + + SET_NETDEV_DEV(dev, &mdev->ofdev.dev); + + macio_set_drvdata(mdev, dev); + + /* Setup interrupts & base address */ + dev->irq = macio_irq(mdev, 0); + phys_addr = macio_resource_start(mdev, 0); /* Physical address */ + printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); + dev->base_addr = phys_addr; + card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); + if (!card->vaddr) { + printk(KERN_ERR PFX "ioremap() failed\n"); + goto failed; + } + + hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING); + + /* Power up card */ + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1); + ssleep(1); + + /* Reset it before we get the interrupt */ + hermes_init(hw); + + if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) { + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); + goto failed; + } + card->irq_requested = 1; + + /* Tell the stack we exist */ + if (register_netdev(dev) != 0) { + printk(KERN_ERR PFX "register_netdev() failed\n"); + goto failed; + } + printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name); + card->ndev_registered = 1; + return 0; + failed: + airport_detach(mdev); + return -ENODEV; +} /* airport_attach */ + + +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Benjamin Herrenschmidt )"; +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); +MODULE_LICENSE("Dual MPL/GPL"); + +static struct of_device_id airport_match[] = +{ + { + .name = "radio", + }, + {}, +}; + +MODULE_DEVICE_TABLE (of, airport_match); + +static struct macio_driver airport_driver = +{ + .name = DRIVER_NAME, + .match_table = airport_match, + .probe = airport_attach, + .remove = airport_detach, + .suspend = airport_suspend, + .resume = airport_resume, +}; + +static int __init +init_airport(void) +{ + printk(KERN_DEBUG "%s\n", version); + + return macio_register_driver(&airport_driver); +} + +static void __exit +exit_airport(void) +{ + return macio_unregister_driver(&airport_driver); +} + +module_init(init_airport); +module_exit(exit_airport); diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c new file mode 100644 index 0000000..bfa3753 --- /dev/null +++ b/drivers/net/wireless/orinoco/hermes.c @@ -0,0 +1,544 @@ +/* hermes.c + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no + * particular order). + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia. + * (C) Copyright David Gibson, IBM Corp. 2001-2003. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include +#include +#include +#include + +#include "hermes.h" + +MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); +MODULE_AUTHOR("Pavel Roskin " + " & David Gibson "); +MODULE_LICENSE("Dual MPL/GPL"); + +/* These are maximum timeouts. Most often, card wil react much faster */ +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ + +/* + * Debugging helpers + */ + +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \ + printk(stuff);} while (0) + +#undef HERMES_DEBUG +#ifdef HERMES_DEBUG +#include + +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff) + +#else /* ! HERMES_DEBUG */ + +#define DEBUG(lvl, stuff...) do { } while (0) + +#endif /* ! HERMES_DEBUG */ + + +/* + * Internal functions + */ + +/* Issue a command to the chip. Waiting for it to complete is the caller's + problem. + + Returns -EBUSY if the command register is busy, 0 on success. + + Callable from any context. +*/ +static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0, + u16 param1, u16 param2) +{ + int k = CMD_BUSY_TIMEOUT; + u16 reg; + + /* First wait for the command register to unbusy */ + reg = hermes_read_regn(hw, CMD); + while ( (reg & HERMES_CMD_BUSY) && k ) { + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(hw, PARAM2, param2); + hermes_write_regn(hw, PARAM1, param1); + hermes_write_regn(hw, PARAM0, param0); + hermes_write_regn(hw, CMD, cmd); + + return 0; +} + +/* + * Function definitions + */ + +/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ +int hermes_doicmd_wait(hermes_t *hw, u16 cmd, + u16 parm0, u16 parm1, u16 parm2, + struct hermes_response *resp) +{ + int err = 0; + int k; + u16 status, reg; + + err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ((!(reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (!hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (!(reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ %p: " + "Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + if (resp) { + resp->status = status; + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + } + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + if (status & HERMES_STATUS_RESULT) + err = -EIO; +out: + return err; +} +EXPORT_SYMBOL(hermes_doicmd_wait); + +void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) +{ + hw->iobase = address; + hw->reg_spacing = reg_spacing; + hw->inten = 0x0; +} +EXPORT_SYMBOL(hermes_struct_init); + +int hermes_init(hermes_t *hw) +{ + u16 reg; + int err = 0; + int k; + + /* We don't want to be interrupted while resetting the chipset */ + hw->inten = 0x0; + hermes_write_regn(hw, INTEN, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + /* Normally it's a "can't happen" for the command register to + be busy when we go to issue a command because we are + serializing all commands. However we want to have some + chance of resetting the card even if it gets into a stupid + state, so we actually wait to see if the command register + will unbusy itself here. */ + k = CMD_BUSY_TIMEOUT; + reg = hermes_read_regn(hw, CMD); + while (k && (reg & HERMES_CMD_BUSY)) { + if (reg == 0xffff) /* Special case - the card has probably been removed, + so don't wait for the timeout */ + return -ENODEV; + + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* No need to explicitly handle the timeout - if we've timed + out hermes_issue_cmd() will probably return -EBUSY below */ + + /* According to the documentation, EVSTAT may contain + obsolete event occurrence information. We have to acknowledge + it by writing EVACK. */ + reg = hermes_read_regn(hw, EVSTAT); + hermes_write_regn(hw, EVACK, reg); + + /* We don't use hermes_docmd_wait here, because the reset wipes + the magic constant in SWSUPPORT0 away, and it gets confused */ + err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); + + return err; +} +EXPORT_SYMBOL(hermes_init); + +/* Issue a command to the chip, and (busy!) wait for it to + * complete. + * + * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware + * + * Callable from any context, but locking is your problem. */ +int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, + struct hermes_response *resp) +{ + int err; + int k; + u16 reg; + u16 status; + + err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); + if (err) { + if (! hermes_present(hw)) { + if (net_ratelimit()) + printk(KERN_WARNING "hermes @ %p: " + "Card removed while issuing command " + "0x%04x.\n", hw->iobase, cmd); + err = -ENODEV; + } else + if (net_ratelimit()) + printk(KERN_ERR "hermes @ %p: " + "Error %d issuing command 0x%04x.\n", + hw->iobase, err, cmd); + goto out; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ %p: Card removed " + "while waiting for command 0x%04x completion.\n", + hw->iobase, cmd); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ %p: Timeout waiting for " + "command 0x%04x completion.\n", hw->iobase, cmd); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + if (resp) { + resp->status = status; + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + } + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + if (status & HERMES_STATUS_RESULT) + err = -EIO; + + out: + return err; +} +EXPORT_SYMBOL(hermes_docmd_wait); + +int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) +{ + int err = 0; + int k; + u16 reg; + + if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); + if (err) { + return err; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = ALLOC_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_ALLOC)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ %p: " + "Card removed waiting for frame allocation.\n", + hw->iobase); + return -ENODEV; + } + + if (! (reg & HERMES_EV_ALLOC)) { + printk(KERN_ERR "hermes @ %p: " + "Timeout waiting for frame allocation\n", + hw->iobase); + return -ETIMEDOUT; + } + + *fid = hermes_read_regn(hw, ALLOCFID); + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); + + return 0; +} +EXPORT_SYMBOL(hermes_allocate); + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error + * from firmware + * + * Callable from any context */ +static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + u16 reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + k = HERMES_BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ((reg & HERMES_OFFSET_BUSY) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + + /* Now we actually set up the transfer */ + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + + /* Wait for the BAP to be ready */ + k = HERMES_BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg != offset) { + printk(KERN_ERR "hermes @ %p: BAP%d offset %s: " + "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap, + (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error", + reg, id, offset); + + if (reg & HERMES_OFFSET_BUSY) { + return -ETIMEDOUT; + } + + return -EIO; /* error or wrong offset */ + } + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if ( (len < 0) || (len % 2) ) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_read_words(hw, dreg, buf, len/2); + + out: + return err; +} +EXPORT_SYMBOL(hermes_bap_pread); + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len < 0) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_write_bytes(hw, dreg, buf, len); + + out: + return err; +} +EXPORT_SYMBOL(hermes_bap_pwrite); + +/* Read a Length-Type-Value record from the card. + * + * If length is NULL, we ignore the length read from the card, and + * read the entire buffer regardless. This is useful because some of + * the configuration records appear to have incorrect lengths in + * practice. + * + * Callable from user or bh context. */ +int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, + u16 *length, void *buf) +{ + int err = 0; + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + u16 rlength, rtype; + unsigned nwords; + + if ( (bufsize < 0) || (bufsize % 2) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); + if (err) + return err; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + return err; + + rlength = hermes_read_reg(hw, dreg); + + if (! rlength) + return -ENODATA; + + rtype = hermes_read_reg(hw, dreg); + + if (length) + *length = rlength; + + if (rtype != rid) + printk(KERN_WARNING "hermes @ %p: %s(): " + "rid (0x%04x) does not match type (0x%04x)\n", + hw->iobase, __func__, rid, rtype); + if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) + printk(KERN_WARNING "hermes @ %p: " + "Truncating LTV record from %d to %d bytes. " + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, + HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); + + nwords = min((unsigned)rlength - 1, bufsize / 2); + hermes_read_words(hw, dreg, buf, nwords); + + return 0; +} +EXPORT_SYMBOL(hermes_read_ltv); + +int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, + u16 length, const void *value) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + unsigned count; + + if (length == 0) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + return err; + + hermes_write_reg(hw, dreg, length); + hermes_write_reg(hw, dreg, rid); + + count = length - 1; + + hermes_write_bytes(hw, dreg, value, count << 1); + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + rid, NULL); + + return err; +} +EXPORT_SYMBOL(hermes_write_ltv); + +static int __init init_hermes(void) +{ + return 0; +} + +static void __exit exit_hermes(void) +{ +} + +module_init(init_hermes); +module_exit(exit_hermes); diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h new file mode 100644 index 0000000..8b13c8f --- /dev/null +++ b/drivers/net/wireless/orinoco/hermes.h @@ -0,0 +1,494 @@ +/* hermes.h + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia. + * (C) Copyright David Gibson, IBM Corp. 2001-2003. + * + * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * This file distributed under the GPL, version 2. + */ + +#ifndef _HERMES_H +#define _HERMES_H + +/* Notes on locking: + * + * As a module of low level hardware access routines, there is no + * locking. Users of this module should ensure that they serialize + * access to the hermes_t structure, and to the hardware +*/ + +#include +#include + +/* + * Limits and constants + */ +#define HERMES_ALLOC_LEN_MIN (4) +#define HERMES_ALLOC_LEN_MAX (2400) +#define HERMES_LTV_LEN_MAX (34) +#define HERMES_BAP_DATALEN_MAX (4096) +#define HERMES_BAP_OFFSET_MAX (4096) +#define HERMES_PORTID_MAX (7) +#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX+1) +#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */ +#define HERMES_PDA_RECS_MAX (200) /* a guess */ +#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */ +#define HERMES_SCANRESULT_MAX (35) +#define HERMES_CHINFORESULT_MAX (8) +#define HERMES_MAX_MULTICAST (16) +#define HERMES_MAGIC (0x7d1f) + +/* + * Hermes register offsets + */ +#define HERMES_CMD (0x00) +#define HERMES_PARAM0 (0x02) +#define HERMES_PARAM1 (0x04) +#define HERMES_PARAM2 (0x06) +#define HERMES_STATUS (0x08) +#define HERMES_RESP0 (0x0A) +#define HERMES_RESP1 (0x0C) +#define HERMES_RESP2 (0x0E) +#define HERMES_INFOFID (0x10) +#define HERMES_RXFID (0x20) +#define HERMES_ALLOCFID (0x22) +#define HERMES_TXCOMPLFID (0x24) +#define HERMES_SELECT0 (0x18) +#define HERMES_OFFSET0 (0x1C) +#define HERMES_DATA0 (0x36) +#define HERMES_SELECT1 (0x1A) +#define HERMES_OFFSET1 (0x1E) +#define HERMES_DATA1 (0x38) +#define HERMES_EVSTAT (0x30) +#define HERMES_INTEN (0x32) +#define HERMES_EVACK (0x34) +#define HERMES_CONTROL (0x14) +#define HERMES_SWSUPPORT0 (0x28) +#define HERMES_SWSUPPORT1 (0x2A) +#define HERMES_SWSUPPORT2 (0x2C) +#define HERMES_AUXPAGE (0x3A) +#define HERMES_AUXOFFSET (0x3C) +#define HERMES_AUXDATA (0x3E) + +/* + * CMD register bitmasks + */ +#define HERMES_CMD_BUSY (0x8000) +#define HERMES_CMD_AINFO (0x7f00) +#define HERMES_CMD_MACPORT (0x0700) +#define HERMES_CMD_RECL (0x0100) +#define HERMES_CMD_WRITE (0x0100) +#define HERMES_CMD_PROGMODE (0x0300) +#define HERMES_CMD_CMDCODE (0x003f) + +/* + * STATUS register bitmasks + */ +#define HERMES_STATUS_RESULT (0x7f00) +#define HERMES_STATUS_CMDCODE (0x003f) + +/* + * OFFSET register bitmasks + */ +#define HERMES_OFFSET_BUSY (0x8000) +#define HERMES_OFFSET_ERR (0x4000) +#define HERMES_OFFSET_DATAOFF (0x0ffe) + +/* + * Event register bitmasks (INTEN, EVSTAT, EVACK) + */ +#define HERMES_EV_TICK (0x8000) +#define HERMES_EV_WTERR (0x4000) +#define HERMES_EV_INFDROP (0x2000) +#define HERMES_EV_INFO (0x0080) +#define HERMES_EV_DTIM (0x0020) +#define HERMES_EV_CMD (0x0010) +#define HERMES_EV_ALLOC (0x0008) +#define HERMES_EV_TXEXC (0x0004) +#define HERMES_EV_TX (0x0002) +#define HERMES_EV_RX (0x0001) + +/* + * Command codes + */ +/*--- Controller Commands ----------------------------*/ +#define HERMES_CMD_INIT (0x0000) +#define HERMES_CMD_ENABLE (0x0001) +#define HERMES_CMD_DISABLE (0x0002) +#define HERMES_CMD_DIAG (0x0003) + +/*--- Buffer Mgmt Commands ---------------------------*/ +#define HERMES_CMD_ALLOC (0x000A) +#define HERMES_CMD_TX (0x000B) + +/*--- Regulate Commands ------------------------------*/ +#define HERMES_CMD_NOTIFY (0x0010) +#define HERMES_CMD_INQUIRE (0x0011) + +/*--- Configure Commands -----------------------------*/ +#define HERMES_CMD_ACCESS (0x0021) +#define HERMES_CMD_DOWNLD (0x0022) + +/*--- Serial I/O Commands ----------------------------*/ +#define HERMES_CMD_READMIF (0x0030) +#define HERMES_CMD_WRITEMIF (0x0031) + +/*--- Debugging Commands -----------------------------*/ +#define HERMES_CMD_TEST (0x0038) + + +/* Test command arguments */ +#define HERMES_TEST_SET_CHANNEL 0x0800 +#define HERMES_TEST_MONITOR 0x0b00 +#define HERMES_TEST_STOP 0x0f00 + +/* Authentication algorithms */ +#define HERMES_AUTH_OPEN 1 +#define HERMES_AUTH_SHARED_KEY 2 + +/* WEP settings */ +#define HERMES_WEP_PRIVACY_INVOKED 0x0001 +#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002 +#define HERMES_WEP_HOST_ENCRYPT 0x0010 +#define HERMES_WEP_HOST_DECRYPT 0x0080 + +/* Symbol hostscan options */ +#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001 +#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002 +#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040 +#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080 + +/* + * Frame structures and constants + */ + +#define HERMES_DESCRIPTOR_OFFSET 0 +#define HERMES_802_11_OFFSET (14) +#define HERMES_802_3_OFFSET (14+32) +#define HERMES_802_2_OFFSET (14+32+14) +#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) + +#define HERMES_RXSTAT_ERR (0x0003) +#define HERMES_RXSTAT_BADCRC (0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) +#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ +#define HERMES_RXSTAT_MACPORT (0x0700) +#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ +#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ +#define HERMES_RXSTAT_MSGTYPE (0xE000) +#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ +#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ + +/* Shift amount for key ID in RXSTAT and TXCTRL */ +#define HERMES_MIC_KEY_ID_SHIFT 11 + +struct hermes_tx_descriptor { + __le16 status; + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; + u8 retry_count; + u8 tx_rate; + __le16 tx_control; +} __attribute__ ((packed)); + +#define HERMES_TXSTAT_RETRYERR (0x0001) +#define HERMES_TXSTAT_AGEDERR (0x0002) +#define HERMES_TXSTAT_DISCON (0x0004) +#define HERMES_TXSTAT_FORMERR (0x0008) + +#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ +#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ +#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ +#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ +#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ +#define HERMES_TXCTRL_ALT_RTRY (0x0020) + +/* Inquiry constants and data types */ + +#define HERMES_INQ_TALLIES (0xF100) +#define HERMES_INQ_SCAN (0xF101) +#define HERMES_INQ_CHANNELINFO (0xF102) +#define HERMES_INQ_HOSTSCAN (0xF103) +#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104) +#define HERMES_INQ_LINKSTATUS (0xF200) +#define HERMES_INQ_SEC_STAT_AGERE (0xF202) + +struct hermes_tallies_frame { + __le16 TxUnicastFrames; + __le16 TxMulticastFrames; + __le16 TxFragments; + __le16 TxUnicastOctets; + __le16 TxMulticastOctets; + __le16 TxDeferredTransmissions; + __le16 TxSingleRetryFrames; + __le16 TxMultipleRetryFrames; + __le16 TxRetryLimitExceeded; + __le16 TxDiscards; + __le16 RxUnicastFrames; + __le16 RxMulticastFrames; + __le16 RxFragments; + __le16 RxUnicastOctets; + __le16 RxMulticastOctets; + __le16 RxFCSErrors; + __le16 RxDiscards_NoBuffer; + __le16 TxDiscardsWrongSA; + __le16 RxWEPUndecryptable; + __le16 RxMsgInMsgFragments; + __le16 RxMsgInBadMsgFragments; + /* Those last are probably not available in very old firmwares */ + __le16 RxDiscards_WEPICVError; + __le16 RxDiscards_WEPExcluded; +} __attribute__ ((packed)); + +/* Grabbed from wlan-ng - Thanks Mark... - Jean II + * This is the result of a scan inquiry command */ +/* Structure describing info about an Access Point */ +struct prism2_scan_apinfo { + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ + __le16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ + u8 rates[10]; /* Bit rate supported */ + __le16 proberesp_rate; /* Data rate of the response frame */ + __le16 atim; /* ATIM window time, Kus (hostscan only) */ +} __attribute__ ((packed)); + +/* Same stuff for the Lucent/Agere card. + * Thanks to h1kari - Jean II */ +struct agere_scan_apinfo { + __le16 channel; /* Channel where the AP sits */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ + __le16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ +} __attribute__ ((packed)); + +/* Moustafa: Scan structure for Symbol cards */ +struct symbol_scan_apinfo { + u8 channel; /* Channel where the AP sits */ + u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */ + __le16 noise; /* Noise level */ + __le16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + __le16 beacon_interv; /* Beacon interval */ + __le16 capabilities; /* Capabilities */ + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */ + __le16 essid_len; /* ESSID length */ + u8 essid[32]; /* ESSID of the network */ + __le16 rates[5]; /* Bit rate supported */ + __le16 basic_rates; /* Basic rates bitmask */ + u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */ + u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */ +} __attribute__ ((packed)); + +union hermes_scan_info { + struct agere_scan_apinfo a; + struct prism2_scan_apinfo p; + struct symbol_scan_apinfo s; +}; + +/* Extended scan struct for HERMES_INQ_CHANNELINFO. + * wl_lkm calls this an ACS scan (Automatic Channel Select). + * Keep out of union hermes_scan_info because it is much bigger than + * the older scan structures. */ +struct agere_ext_scan_info { + __le16 reserved0; + + u8 noise; + u8 level; + u8 rx_flow; + u8 rate; + __le16 reserved1[2]; + + __le16 frame_control; + __le16 dur_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 sequence; + u8 addr4[ETH_ALEN]; + + __le16 data_length; + + /* Next 3 fields do not get filled in. */ + u8 daddr[ETH_ALEN]; + u8 saddr[ETH_ALEN]; + __le16 len_type; + + __le64 timestamp; + __le16 beacon_interval; + __le16 capabilities; + u8 data[316]; +} __attribute__ ((packed)); + +#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) +#define HERMES_LINKSTATUS_CONNECTED (0x0001) +#define HERMES_LINKSTATUS_DISCONNECTED (0x0002) +#define HERMES_LINKSTATUS_AP_CHANGE (0x0003) +#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004) +#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005) +#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006) + +struct hermes_linkstatus { + __le16 linkstatus; /* Link status */ +} __attribute__ ((packed)); + +struct hermes_response { + u16 status, resp0, resp1, resp2; +}; + +/* "ID" structure - used for ESSID and station nickname */ +struct hermes_idstring { + __le16 len; + __le16 val[16]; +} __attribute__ ((packed)); + +struct hermes_multicast { + u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)); + +/* Timeouts */ +#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */ + +/* Basic control structure */ +typedef struct hermes { + void __iomem *iobase; + int reg_spacing; +#define HERMES_16BIT_REGSPACING 0 +#define HERMES_32BIT_REGSPACING 1 + u16 inten; /* Which interrupts should be enabled? */ +} hermes_t; + +/* Register access convenience macros */ +#define hermes_read_reg(hw, off) \ + (ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing ))) +#define hermes_write_reg(hw, off, val) \ + (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing))) +#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name) +#define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val)) + +/* Function prototypes */ +void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing); +int hermes_init(hermes_t *hw); +int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, + struct hermes_response *resp); +int hermes_doicmd_wait(hermes_t *hw, u16 cmd, + u16 parm0, u16 parm1, u16 parm2, + struct hermes_response *resp); +int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); + +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, + u16 id, u16 offset); +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, + u16 id, u16 offset); +int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, + u16 *length, void *buf); +int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, + u16 length, const void *value); + +/* Inline functions */ + +static inline int hermes_present(hermes_t *hw) +{ + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; +} + +static inline void hermes_set_irqmask(hermes_t *hw, u16 events) +{ + hw->inten = events; + hermes_write_regn(hw, INTEN, events); +} + +static inline int hermes_enable_port(hermes_t *hw, int port) +{ + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, NULL); +} + +static inline int hermes_disable_port(hermes_t *hw, int port) +{ + return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), + 0, NULL); +} + +/* Initiate an INQUIRE command (tallies or scan). The result will come as an + * information frame in __orinoco_ev_info() */ +static inline int hermes_inquire(hermes_t *hw, u16 rid) +{ + return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL); +} + +#define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 ) +#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count) +{ + off = off << hw->reg_spacing; + ioread16_rep(hw->iobase + off, buf, count); +} + +static inline void hermes_write_bytes(struct hermes *hw, int off, + const char *buf, unsigned count) +{ + off = off << hw->reg_spacing; + iowrite16_rep(hw->iobase + off, buf, count >> 1); + if (unlikely(count & 1)) + iowrite8(buf[count - 1], hw->iobase + off); +} + +static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) +{ + unsigned i; + + off = off << hw->reg_spacing; + + for (i = 0; i < count; i++) + iowrite16(0, hw->iobase + off); +} + +#define HERMES_READ_RECORD(hw, bap, rid, buf) \ + (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) + +static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word) +{ + __le16 rec; + int err; + + err = HERMES_READ_RECORD(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + +static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word) +{ + __le16 rec = cpu_to_le16(word); + return HERMES_WRITE_RECORD(hw, bap, rid, &rec); +} + +#endif /* _HERMES_H */ diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c new file mode 100644 index 0000000..d8c626e --- /dev/null +++ b/drivers/net/wireless/orinoco/hermes_dld.c @@ -0,0 +1,730 @@ +/* + * Hermes download helper driver. + * + * This could be entirely merged into hermes.c. + * + * I'm keeping it separate to minimise the amount of merging between + * kernel upgrades. It also means the memory overhead for drivers that + * don't need firmware download low. + * + * This driver: + * - is capable of writing to the volatile area of the hermes device + * - is currently not capable of writing to non-volatile areas + * - provide helpers to identify and update plugin data + * - is not capable of interpreting a fw image directly. That is up to + * the main card driver. + * - deals with Hermes I devices. It can probably be modified to deal + * with Hermes II devices + * + * Copyright (C) 2007, David Kilroy + * + * Plug data code slightly modified from spectrum_cs driver + * Copyright (C) 2002-2005 Pavel Roskin + * Portions based on information in wl_lkm_718 Agere driver + * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include +#include +#include "hermes.h" +#include "hermes_dld.h" + +MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset"); +MODULE_AUTHOR("David Kilroy "); +MODULE_LICENSE("Dual MPL/GPL"); + +#define PFX "hermes_dld: " + +/* + * AUX port access. To unlock the AUX port write the access keys to the + * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL + * register. Then read it and make sure it's HERMES_AUX_ENABLED. + */ +#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ +#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ +#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ +#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ + +#define HERMES_AUX_PW0 0xFE01 +#define HERMES_AUX_PW1 0xDC23 +#define HERMES_AUX_PW2 0xBA45 + +/* HERMES_CMD_DOWNLD */ +#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) + +/* End markers used in dblocks */ +#define PDI_END 0x00000000 /* End of PDA */ +#define BLOCK_END 0xFFFFFFFF /* Last image block */ +#define TEXT_END 0x1A /* End of text header */ + +/* + * PDA == Production Data Area + * + * In principle, the max. size of the PDA is is 4096 words. Currently, + * however, only about 500 bytes of this area are used. + * + * Some USB implementations can't handle sizes in excess of 1016. Note + * that PDA is not actually used in those USB environments, but may be + * retrieved by common code. + */ +#define MAX_PDA_SIZE 1000 + +/* Limit the amout we try to download in a single shot. + * Size is in bytes. + */ +#define MAX_DL_SIZE 1024 +#define LIMIT_PROGRAM_SIZE 0 + +/* + * The following structures have little-endian fields denoted by + * the leading underscore. Don't access them directly - use inline + * functions defined below. + */ + +/* + * The binary image to be downloaded consists of series of data blocks. + * Each block has the following structure. + */ +struct dblock { + __le32 addr; /* adapter address where to write the block */ + __le16 len; /* length of the data only, in bytes */ + char data[0]; /* data to be written */ +} __attribute__ ((packed)); + +/* + * Plug Data References are located in in the image after the last data + * block. They refer to areas in the adapter memory where the plug data + * items with matching ID should be written. + */ +struct pdr { + __le32 id; /* record ID */ + __le32 addr; /* adapter address where to write the data */ + __le32 len; /* expected length of the data, in bytes */ + char next[0]; /* next PDR starts here */ +} __attribute__ ((packed)); + +/* + * Plug Data Items are located in the EEPROM read from the adapter by + * primary firmware. They refer to the device-specific data that should + * be plugged into the secondary firmware. + */ +struct pdi { + __le16 len; /* length of ID and data, in words */ + __le16 id; /* record ID */ + char data[0]; /* plug data */ +} __attribute__ ((packed)); + +/*** FW data block access functions ***/ + +static inline u32 +dblock_addr(const struct dblock *blk) +{ + return le32_to_cpu(blk->addr); +} + +static inline u32 +dblock_len(const struct dblock *blk) +{ + return le16_to_cpu(blk->len); +} + +/*** PDR Access functions ***/ + +static inline u32 +pdr_id(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->id); +} + +static inline u32 +pdr_addr(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->addr); +} + +static inline u32 +pdr_len(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->len); +} + +/*** PDI Access functions ***/ + +static inline u32 +pdi_id(const struct pdi *pdi) +{ + return le16_to_cpu(pdi->id); +} + +/* Return length of the data only, in bytes */ +static inline u32 +pdi_len(const struct pdi *pdi) +{ + return 2 * (le16_to_cpu(pdi->len) - 1); +} + +/*** Hermes AUX control ***/ + +static inline void +hermes_aux_setaddr(hermes_t *hw, u32 addr) +{ + hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); + hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); +} + +static inline int +hermes_aux_control(hermes_t *hw, int enabled) +{ + int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; + int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; + int i; + + /* Already open? */ + if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) + return 0; + + hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); + hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); + hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); + hermes_write_reg(hw, HERMES_CONTROL, action); + + for (i = 0; i < 20; i++) { + udelay(10); + if (hermes_read_reg(hw, HERMES_CONTROL) == + desired_state) + return 0; + } + + return -EBUSY; +} + +/*** Plug Data Functions ***/ + +/* + * Scan PDR for the record with the specified RECORD_ID. + * If it's not found, return NULL. + */ +static struct pdr * +hermes_find_pdr(struct pdr *first_pdr, u32 record_id) +{ + struct pdr *pdr = first_pdr; + void *end = (void *)first_pdr + MAX_PDA_SIZE; + + while (((void *)pdr < end) && + (pdr_id(pdr) != PDI_END)) { + /* + * PDR area is currently not terminated by PDI_END. + * It's followed by CRC records, which have the type + * field where PDR has length. The type can be 0 or 1. + */ + if (pdr_len(pdr) < 2) + return NULL; + + /* If the record ID matches, we are done */ + if (pdr_id(pdr) == record_id) + return pdr; + + pdr = (struct pdr *) pdr->next; + } + return NULL; +} + +/* Scan production data items for a particular entry */ +static struct pdi * +hermes_find_pdi(struct pdi *first_pdi, u32 record_id) +{ + struct pdi *pdi = first_pdi; + + while (pdi_id(pdi) != PDI_END) { + + /* If the record ID matches, we are done */ + if (pdi_id(pdi) == record_id) + return pdi; + + pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; + } + return NULL; +} + +/* Process one Plug Data Item - find corresponding PDR and plug it */ +static int +hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) +{ + struct pdr *pdr; + + /* Find the PDR corresponding to this PDI */ + pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); + + /* No match is found, safe to ignore */ + if (!pdr) + return 0; + + /* Lengths of the data in PDI and PDR must match */ + if (pdi_len(pdi) != pdr_len(pdr)) + return -EINVAL; + + /* do the actual plugging */ + hermes_aux_setaddr(hw, pdr_addr(pdr)); + hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); + + return 0; +} + +/* Read PDA from the adapter */ +int hermes_read_pda(hermes_t *hw, + __le16 *pda, + u32 pda_addr, + u16 pda_len, + int use_eeprom) /* can we get this into hw? */ +{ + int ret; + u16 pda_size; + u16 data_len = pda_len; + __le16 *data = pda; + + if (use_eeprom) { + /* PDA of spectrum symbol is in eeprom */ + + /* Issue command to read EEPROM */ + ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); + if (ret) + return ret; + } else { + /* wl_lkm does not include PDA size in the PDA area. + * We will pad the information into pda, so other routines + * don't have to be modified */ + pda[0] = cpu_to_le16(pda_len - 2); + /* Includes CFG_PROD_DATA but not itself */ + pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ + data_len = pda_len - 4; + data = pda + 2; + } + + /* Open auxiliary port */ + ret = hermes_aux_control(hw, 1); + printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret); + if (ret) + return ret; + + /* read PDA from EEPROM */ + hermes_aux_setaddr(hw, pda_addr); + hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); + + /* Close aux port */ + ret = hermes_aux_control(hw, 0); + printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret); + + /* Check PDA length */ + pda_size = le16_to_cpu(pda[0]); + printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n", + pda_size, pda_len); + if (pda_size > pda_len) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(hermes_read_pda); + +/* Parse PDA and write the records into the adapter + * + * Attempt to write every records that is in the specified pda + * which also has a valid production data record for the firmware. + */ +int hermes_apply_pda(hermes_t *hw, + const char *first_pdr, + const __le16 *pda) +{ + int ret; + const struct pdi *pdi; + struct pdr *pdr; + + pdr = (struct pdr *) first_pdr; + + /* Go through every PDI and plug them into the adapter */ + pdi = (const struct pdi *) (pda + 2); + while (pdi_id(pdi) != PDI_END) { + ret = hermes_plug_pdi(hw, pdr, pdi); + if (ret) + return ret; + + /* Increment to the next PDI */ + pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; + } + return 0; +} +EXPORT_SYMBOL(hermes_apply_pda); + +/* Identify the total number of bytes in all blocks + * including the header data. + */ +size_t +hermes_blocks_length(const char *first_block) +{ + const struct dblock *blk = (const struct dblock *) first_block; + int total_len = 0; + int len; + + /* Skip all blocks to locate Plug Data References + * (Spectrum CS) */ + while (dblock_addr(blk) != BLOCK_END) { + len = dblock_len(blk); + total_len += sizeof(*blk) + len; + blk = (struct dblock *) &blk->data[len]; + } + + return total_len; +} +EXPORT_SYMBOL(hermes_blocks_length); + +/*** Hermes programming ***/ + +/* About to start programming data (Hermes I) + * offset is the entry point + * + * Spectrum_cs' Symbol fw does not require this + * wl_lkm Agere fw does + * Don't know about intersil + */ +int hermesi_program_init(hermes_t *hw, u32 offset) +{ + int err; + + /* Disable interrupts?*/ + /*hw->inten = 0x0;*/ + /*hermes_write_regn(hw, INTEN, 0);*/ + /*hermes_set_irqmask(hw, 0);*/ + + /* Acknowledge any outstanding command */ + hermes_write_regn(hw, EVACK, 0xFFFF); + + /* Using doicmd_wait rather than docmd_wait */ + err = hermes_doicmd_wait(hw, + 0x0100 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + if (err) + return err; + + err = hermes_doicmd_wait(hw, + 0x0000 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + if (err) + return err; + + err = hermes_aux_control(hw, 1); + printk(KERN_DEBUG PFX "AUX enable returned %d\n", err); + + if (err) + return err; + + printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); + err = hermes_doicmd_wait(hw, + HERMES_PROGRAM_ENABLE_VOLATILE, + offset & 0xFFFFu, + offset >> 16, + 0, + NULL); + printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n", + err); + + return err; +} +EXPORT_SYMBOL(hermesi_program_init); + +/* Done programming data (Hermes I) + * + * Spectrum_cs' Symbol fw does not require this + * wl_lkm Agere fw does + * Don't know about intersil + */ +int hermesi_program_end(hermes_t *hw) +{ + struct hermes_response resp; + int rc = 0; + int err; + + rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); + + printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, " + "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", + rc, resp.resp0, resp.resp1, resp.resp2); + + if ((rc == 0) && + ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) + rc = -EIO; + + err = hermes_aux_control(hw, 0); + printk(KERN_DEBUG PFX "AUX disable returned %d\n", err); + + /* Acknowledge any outstanding command */ + hermes_write_regn(hw, EVACK, 0xFFFF); + + /* Reinitialise, ignoring return */ + (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + + return rc ? rc : err; +} +EXPORT_SYMBOL(hermesi_program_end); + +/* Program the data blocks */ +int hermes_program(hermes_t *hw, const char *first_block, const char *end) +{ + const struct dblock *blk; + u32 blkaddr; + u32 blklen; +#if LIMIT_PROGRAM_SIZE + u32 addr; + u32 len; +#endif + + blk = (const struct dblock *) first_block; + + if ((const char *) blk > (end - sizeof(*blk))) + return -EIO; + + blkaddr = dblock_addr(blk); + blklen = dblock_len(blk); + + while ((blkaddr != BLOCK_END) && + (((const char *) blk + blklen) <= end)) { + printk(KERN_DEBUG PFX + "Programming block of length %d to address 0x%08x\n", + blklen, blkaddr); + +#if !LIMIT_PROGRAM_SIZE + /* wl_lkm driver splits this into writes of 2000 bytes */ + hermes_aux_setaddr(hw, blkaddr); + hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, + blklen); +#else + len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE; + addr = blkaddr; + + while (addr < (blkaddr + blklen)) { + printk(KERN_DEBUG PFX + "Programming subblock of length %d " + "to address 0x%08x. Data @ %p\n", + len, addr, &blk->data[addr - blkaddr]); + + hermes_aux_setaddr(hw, addr); + hermes_write_bytes(hw, HERMES_AUXDATA, + &blk->data[addr - blkaddr], + len); + + addr += len; + len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ? + (blkaddr + blklen - addr) : MAX_DL_SIZE; + } +#endif + blk = (const struct dblock *) &blk->data[blklen]; + + if ((const char *) blk > (end - sizeof(*blk))) + return -EIO; + + blkaddr = dblock_addr(blk); + blklen = dblock_len(blk); + } + return 0; +} +EXPORT_SYMBOL(hermes_program); + +static int __init init_hermes_dld(void) +{ + return 0; +} + +static void __exit exit_hermes_dld(void) +{ +} + +module_init(init_hermes_dld); +module_exit(exit_hermes_dld); + +/*** Default plugging data for Hermes I ***/ +/* Values from wl_lkm_718/hcf/dhf.c */ + +#define DEFINE_DEFAULT_PDR(pid, length, data) \ +static const struct { \ + __le16 len; \ + __le16 id; \ + u8 val[length]; \ +} __attribute__ ((packed)) default_pdr_data_##pid = { \ + __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ + sizeof(__le16)) - 1), \ + __constant_cpu_to_le16(pid), \ + data \ +} + +#define DEFAULT_PDR(pid) default_pdr_data_##pid + +/* HWIF Compatiblity */ +DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); + +/* PPPPSign */ +DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); + +/* PPPPProf */ +DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); + +/* Antenna diversity */ +DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); + +/* Modem VCO band Set-up */ +DEFINE_DEFAULT_PDR(0x0160, 28, + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00"); + +/* Modem Rx Gain Table Values */ +DEFINE_DEFAULT_PDR(0x0161, 256, + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3E\01\x3E\x01\x3D\x01" + "\x3D\x01\x3C\01\x3C\x01\x3B\x01" + "\x3B\x01\x3A\01\x3A\x01\x39\x01" + "\x39\x01\x38\01\x38\x01\x37\x01" + "\x37\x01\x36\01\x36\x01\x35\x01" + "\x35\x01\x34\01\x34\x01\x33\x01" + "\x33\x01\x32\x01\x32\x01\x31\x01" + "\x31\x01\x30\x01\x30\x01\x7B\x01" + "\x7B\x01\x7A\x01\x7A\x01\x79\x01" + "\x79\x01\x78\x01\x78\x01\x77\x01" + "\x77\x01\x76\x01\x76\x01\x75\x01" + "\x75\x01\x74\x01\x74\x01\x73\x01" + "\x73\x01\x72\x01\x72\x01\x71\x01" + "\x71\x01\x70\x01\x70\x01\x68\x01" + "\x68\x01\x67\x01\x67\x01\x66\x01" + "\x66\x01\x65\x01\x65\x01\x57\x01" + "\x57\x01\x56\x01\x56\x01\x55\x01" + "\x55\x01\x54\x01\x54\x01\x53\x01" + "\x53\x01\x52\x01\x52\x01\x51\x01" + "\x51\x01\x50\x01\x50\x01\x48\x01" + "\x48\x01\x47\x01\x47\x01\x46\x01" + "\x46\x01\x45\x01\x45\x01\x44\x01" + "\x44\x01\x43\x01\x43\x01\x42\x01" + "\x42\x01\x41\x01\x41\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01"); + +/* Write PDA according to certain rules. + * + * For every production data record, look for a previous setting in + * the pda, and use that. + * + * For certain records, use defaults if they are not found in pda. + */ +int hermes_apply_pda_with_defaults(hermes_t *hw, + const char *first_pdr, + const __le16 *pda) +{ + const struct pdr *pdr = (const struct pdr *) first_pdr; + struct pdi *first_pdi = (struct pdi *) &pda[2]; + struct pdi *pdi; + struct pdi *default_pdi = NULL; + struct pdi *outdoor_pdi; + void *end = (void *)first_pdr + MAX_PDA_SIZE; + int record_id; + + while (((void *)pdr < end) && + (pdr_id(pdr) != PDI_END)) { + /* + * For spectrum_cs firmwares, + * PDR area is currently not terminated by PDI_END. + * It's followed by CRC records, which have the type + * field where PDR has length. The type can be 0 or 1. + */ + if (pdr_len(pdr) < 2) + break; + record_id = pdr_id(pdr); + + pdi = hermes_find_pdi(first_pdi, record_id); + if (pdi) + printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", + record_id, pdi); + + switch (record_id) { + case 0x110: /* Modem REFDAC values */ + case 0x120: /* Modem VGDAC values */ + outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); + default_pdi = NULL; + if (outdoor_pdi) { + pdi = outdoor_pdi; + printk(KERN_DEBUG PFX + "Using outdoor record 0x%04x at %p\n", + record_id + 1, pdi); + } + break; + case 0x5: /* HWIF Compatiblity */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); + break; + case 0x108: /* PPPPSign */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); + break; + case 0x109: /* PPPPProf */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); + break; + case 0x150: /* Antenna diversity */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); + break; + case 0x160: /* Modem VCO band Set-up */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); + break; + case 0x161: /* Modem Rx Gain Table Values */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); + break; + default: + default_pdi = NULL; + break; + } + if (!pdi && default_pdi) { + /* Use default */ + pdi = default_pdi; + printk(KERN_DEBUG PFX + "Using default record 0x%04x at %p\n", + record_id, pdi); + } + + if (pdi) { + /* Lengths of the data in PDI and PDR must match */ + if (pdi_len(pdi) == pdr_len(pdr)) { + /* do the actual plugging */ + hermes_aux_setaddr(hw, pdr_addr(pdr)); + hermes_write_bytes(hw, HERMES_AUXDATA, + pdi->data, pdi_len(pdi)); + } + } + + pdr++; + } + return 0; +} +EXPORT_SYMBOL(hermes_apply_pda_with_defaults); diff --git a/drivers/net/wireless/orinoco/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h new file mode 100644 index 0000000..6fcb262 --- /dev/null +++ b/drivers/net/wireless/orinoco/hermes_dld.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007, David Kilroy + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ +#ifndef _HERMES_DLD_H +#define _HERMES_DLD_H + +#include "hermes.h" + +int hermesi_program_init(hermes_t *hw, u32 offset); +int hermesi_program_end(hermes_t *hw); +int hermes_program(hermes_t *hw, const char *first_block, const char *end); + +int hermes_read_pda(hermes_t *hw, + __le16 *pda, + u32 pda_addr, + u16 pda_len, + int use_eeprom); +int hermes_apply_pda(hermes_t *hw, + const char *first_pdr, + const __le16 *pda); +int hermes_apply_pda_with_defaults(hermes_t *hw, + const char *first_pdr, + const __le16 *pda); + +size_t hermes_blocks_length(const char *first_block); + +#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/orinoco/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h new file mode 100644 index 0000000..42eb67d --- /dev/null +++ b/drivers/net/wireless/orinoco/hermes_rid.h @@ -0,0 +1,165 @@ +#ifndef _HERMES_RID_H +#define _HERMES_RID_H + +/* + * Configuration RIDs + */ +#define HERMES_RID_CNFPORTTYPE 0xFC00 +#define HERMES_RID_CNFOWNMACADDR 0xFC01 +#define HERMES_RID_CNFDESIREDSSID 0xFC02 +#define HERMES_RID_CNFOWNCHANNEL 0xFC03 +#define HERMES_RID_CNFOWNSSID 0xFC04 +#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 +#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 +#define HERMES_RID_CNFMAXDATALEN 0xFC07 +#define HERMES_RID_CNFWDSADDRESS 0xFC08 +#define HERMES_RID_CNFPMENABLED 0xFC09 +#define HERMES_RID_CNFPMEPS 0xFC0A +#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B +#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C +#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D +#define HERMES_RID_CNFOWNNAME 0xFC0E +#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 +#define HERMES_RID_CNFWDSADDRESS1 0xFC11 +#define HERMES_RID_CNFWDSADDRESS2 0xFC12 +#define HERMES_RID_CNFWDSADDRESS3 0xFC13 +#define HERMES_RID_CNFWDSADDRESS4 0xFC14 +#define HERMES_RID_CNFWDSADDRESS5 0xFC15 +#define HERMES_RID_CNFWDSADDRESS6 0xFC16 +#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 +#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 +#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 +#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 +#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 +#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 +#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 +#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 +#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 +#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 +#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 +#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 +#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 +#define HERMES_RID_CNFAUTHENTICATION 0xFC2A +#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B +#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B +#define HERMES_RID_CNFTXCONTROL 0xFC2C +#define HERMES_RID_CNFROAMINGMODE 0xFC2D +#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E +#define HERMES_RID_CNFRCVCRCERROR 0xFC30 +#define HERMES_RID_CNFMMLIFE 0xFC31 +#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 +#define HERMES_RID_CNFBEACONINT 0xFC33 +#define HERMES_RID_CNFAPPCFINFO 0xFC34 +#define HERMES_RID_CNFSTAPCFINFO 0xFC35 +#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 +#define HERMES_RID_CNFTIMCTRL 0xFC40 +#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 +#define HERMES_RID_CNFENHSECURITY 0xFC43 +#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 +#define HERMES_RID_CNFCREATEIBSS 0xFC81 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 +#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 +#define HERMES_RID_CNFTXRATECONTROL 0xFC84 +#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 +#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A +#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 +#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 +#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 +#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 +#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A +#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B +#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C +#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D +#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB +#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 +#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 +#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 +#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 +#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 +#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 +#define HERMES_RID_CNFBASICRATES 0xFCB3 +#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 +#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 +#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 +#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 +#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 +#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 +#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA +#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB +#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 +#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 +#define HERMES_RID_CNFTICKTIME 0xFCE0 +#define HERMES_RID_CNFSCANREQUEST 0xFCE1 +#define HERMES_RID_CNFJOINREQUEST 0xFCE2 +#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 +#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 +#define HERMES_RID_CNFHOSTSCAN 0xFCE5 + +/* + * Information RIDs + */ +#define HERMES_RID_MAXLOADTIME 0xFD00 +#define HERMES_RID_DOWNLOADBUFFER 0xFD01 +#define HERMES_RID_PRIID 0xFD02 +#define HERMES_RID_PRISUPRANGE 0xFD03 +#define HERMES_RID_CFIACTRANGES 0xFD04 +#define HERMES_RID_NICSERNUM 0xFD0A +#define HERMES_RID_NICID 0xFD0B +#define HERMES_RID_MFISUPRANGE 0xFD0C +#define HERMES_RID_CFISUPRANGE 0xFD0D +#define HERMES_RID_CHANNELLIST 0xFD10 +#define HERMES_RID_REGULATORYDOMAINS 0xFD11 +#define HERMES_RID_TEMPTYPE 0xFD12 +#define HERMES_RID_CIS 0xFD13 +#define HERMES_RID_STAID 0xFD20 +#define HERMES_RID_STASUPRANGE 0xFD21 +#define HERMES_RID_MFIACTRANGES 0xFD22 +#define HERMES_RID_CFIACTRANGES2 0xFD23 +#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 +#define HERMES_RID_PORTSTATUS 0xFD40 +#define HERMES_RID_CURRENTSSID 0xFD41 +#define HERMES_RID_CURRENTBSSID 0xFD42 +#define HERMES_RID_COMMSQUALITY 0xFD43 +#define HERMES_RID_CURRENTTXRATE 0xFD44 +#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 +#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 +#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 +#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 +#define HERMES_RID_LONGRETRYLIMIT 0xFD49 +#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A +#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B +#define HERMES_RID_CFPOLLABLE 0xFD4C +#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D +#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F +#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51 +#define HERMES_RID_CURRENTTXRATE1 0xFD80 +#define HERMES_RID_CURRENTTXRATE2 0xFD81 +#define HERMES_RID_CURRENTTXRATE3 0xFD82 +#define HERMES_RID_CURRENTTXRATE4 0xFD83 +#define HERMES_RID_CURRENTTXRATE5 0xFD84 +#define HERMES_RID_CURRENTTXRATE6 0xFD85 +#define HERMES_RID_OWNMACADDR 0xFD86 +#define HERMES_RID_SCANRESULTSTABLE 0xFD88 +#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 +#define HERMES_RID_CURRENT_WPA_IE 0xFD8A +#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B +#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C +#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D +#define HERMES_RID_TXQUEUEEMPTY 0xFD91 +#define HERMES_RID_PHYTYPE 0xFDC0 +#define HERMES_RID_CURRENTCHANNEL 0xFDC1 +#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 +#define HERMES_RID_CCAMODE 0xFDC3 +#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 +#define HERMES_RID_BUILDSEQ 0xFFFE +#define HERMES_RID_FWID 0xFFFF + +#endif diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c new file mode 100644 index 0000000..f4ea08f --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -0,0 +1,6032 @@ +/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c) + * + * A driver for Hermes or Prism 2 chipset based PCMCIA wireless + * adaptors, with Lucent/Agere, Intersil or Symbol firmware. + * + * Current maintainers (as of 29 September 2003) are: + * Pavel Roskin + * and David Gibson + * + * (C) Copyright David Gibson, IBM Corporation 2001-2003. + * Copyright (C) 2000 David Gibson, Linuxcare Australia. + * With some help from : + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * Copyright (C) 2001 Benjamin Herrenschmidt + * + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 + * + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.stud.fh-dortmund.de/~andy/wvlan/ + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David + * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights + * Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. */ + +/* + * TODO + * o Handle de-encapsulation within network layer, provide 802.11 + * headers (patch from Thomas 'Dent' Mirlacher) + * o Fix possible races in SPY handling. + * o Disconnect wireless extensions from fundamental configuration. + * o (maybe) Software WEP support (patch from Stano Meduna). + * o (maybe) Use multiple Tx buffers - driver handling queue + * rather than firmware. + */ + +/* Locking and synchronization: + * + * The basic principle is that everything is serialized through a + * single spinlock, priv->lock. The lock is used in user, bh and irq + * context, so when taken outside hardirq context it should always be + * taken with interrupts disabled. The lock protects both the + * hardware and the struct orinoco_private. + * + * Another flag, priv->hw_unavailable indicates that the hardware is + * unavailable for an extended period of time (e.g. suspended, or in + * the middle of a hard reset). This flag is protected by the + * spinlock. All code which touches the hardware should check the + * flag after taking the lock, and if it is set, give up on whatever + * they are doing and drop the lock again. The orinoco_lock() + * function handles this (it unlocks and returns -EBUSY if + * hw_unavailable is non-zero). + */ + +#define DRIVER_NAME "orinoco" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hermes_rid.h" +#include "hermes_dld.h" +#include "orinoco.h" + +/********************************************************************/ +/* Module information */ +/********************************************************************/ + +MODULE_AUTHOR("Pavel Roskin & David Gibson "); +MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); +MODULE_LICENSE("Dual MPL/GPL"); + +/* Level of debugging. Used in the macros in orinoco.h */ +#ifdef ORINOCO_DEBUG +int orinoco_debug = ORINOCO_DEBUG; +module_param(orinoco_debug, int, 0644); +MODULE_PARM_DESC(orinoco_debug, "Debug level"); +EXPORT_SYMBOL(orinoco_debug); +#endif + +static int suppress_linkstatus; /* = 0 */ +module_param(suppress_linkstatus, bool, 0644); +MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes"); +static int ignore_disconnect; /* = 0 */ +module_param(ignore_disconnect, int, 0644); +MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer"); + +static int force_monitor; /* = 0 */ +module_param(force_monitor, int, 0644); +MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); + +/********************************************************************/ +/* Compile time configuration and compatibility stuff */ +/********************************************************************/ + +/* We do this this way to avoid ifdefs in the actual code */ +#ifdef WIRELESS_SPY +#define SPY_NUMBER(priv) (priv->spy_data.spy_number) +#else +#define SPY_NUMBER(priv) 0 +#endif /* WIRELESS_SPY */ + +/********************************************************************/ +/* Internal constants */ +/********************************************************************/ + +/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ +static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; +#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) + +#define ORINOCO_MIN_MTU 256 +#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) + +#define SYMBOL_MAX_VER_LEN (14) +#define USER_BAP 0 +#define IRQ_BAP 1 +#define MAX_IRQLOOPS_PER_IRQ 10 +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of + * how many events the + * device could + * legitimately generate */ +#define SMALL_KEY_SIZE 5 +#define LARGE_KEY_SIZE 13 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ + +#define DUMMY_FID 0xFFFF + +/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ + HERMES_MAX_MULTICAST : 0)*/ +#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) + +#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ + | HERMES_EV_TX | HERMES_EV_TXEXC \ + | HERMES_EV_WTERR | HERMES_EV_INFO \ + | HERMES_EV_INFDROP ) + +#define MAX_RID_LEN 1024 + +static const struct iw_handler_def orinoco_handler_def; +static const struct ethtool_ops orinoco_ethtool_ops; + +/********************************************************************/ +/* Data tables */ +/********************************************************************/ + +/* The frequency of each channel in MHz */ +static const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; +#define NUM_CHANNELS ARRAY_SIZE(channel_frequency) + +/* This tables gives the actual meanings of the bitrate IDs returned + * by the firmware. */ +static struct { + int bitrate; /* in 100s of kilobits */ + int automatic; + u16 agere_txratectrl; + u16 intersil_txratectrl; +} bitrate_table[] = { + {110, 1, 3, 15}, /* Entry 0 is the default */ + {10, 0, 1, 1}, + {10, 1, 1, 1}, + {20, 0, 2, 2}, + {20, 1, 6, 3}, + {55, 0, 4, 4}, + {55, 1, 7, 7}, + {110, 0, 5, 8}, +}; +#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) + +/********************************************************************/ +/* Data types */ +/********************************************************************/ + +/* Beginning of the Tx descriptor, used in TxExc handling */ +struct hermes_txexc_data { + struct hermes_tx_descriptor desc; + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; +} __attribute__ ((packed)); + +/* Rx frame header except compatibility 802.3 header */ +struct hermes_rx_descriptor { + /* Control */ + __le16 status; + __le32 time; + u8 silence; + u8 signal; + u8 rate; + u8 rxflow; + __le32 reserved; + + /* 802.11 header */ + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + + /* Data length */ + __le16 data_len; +} __attribute__ ((packed)); + +/********************************************************************/ +/* Function prototypes */ +/********************************************************************/ + +static int __orinoco_program_rids(struct net_device *dev); +static void __orinoco_set_multicast_list(struct net_device *dev); + +/********************************************************************/ +/* Michael MIC crypto setup */ +/********************************************************************/ +#define MICHAEL_MIC_LEN 8 +static int orinoco_mic_init(struct orinoco_private *priv) +{ + priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); + if (IS_ERR(priv->tx_tfm_mic)) { + printk(KERN_DEBUG "orinoco_mic_init: could not allocate " + "crypto API michael_mic\n"); + priv->tx_tfm_mic = NULL; + return -ENOMEM; + } + + priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); + if (IS_ERR(priv->rx_tfm_mic)) { + printk(KERN_DEBUG "orinoco_mic_init: could not allocate " + "crypto API michael_mic\n"); + priv->rx_tfm_mic = NULL; + return -ENOMEM; + } + + return 0; +} + +static void orinoco_mic_free(struct orinoco_private *priv) +{ + if (priv->tx_tfm_mic) + crypto_free_hash(priv->tx_tfm_mic); + if (priv->rx_tfm_mic) + crypto_free_hash(priv->rx_tfm_mic); +} + +static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, + u8 *da, u8 *sa, u8 priority, + u8 *data, size_t data_len, u8 *mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ + + if (tfm_michael == NULL) { + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } + + /* Copy header into buffer. We need the padding on the end zeroed */ + memcpy(&hdr[0], da, ETH_ALEN); + memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); + hdr[ETH_ALEN*2] = priority; + hdr[ETH_ALEN*2+1] = 0; + hdr[ETH_ALEN*2+2] = 0; + hdr[ETH_ALEN*2+3] = 0; + + /* Use scatter gather to MIC header and data in one go */ + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, sizeof(hdr)); + sg_set_buf(&sg[1], data, data_len); + + if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr), + mic); +} + +/********************************************************************/ +/* Internal helper functions */ +/********************************************************************/ + +static inline void set_port_type(struct orinoco_private *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->createibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->createibss = 0; + } else { + priv->port_type = priv->ibss_port; + priv->createibss = 1; + } + break; + case IW_MODE_MONITOR: + priv->port_type = 3; + priv->createibss = 0; + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev->name); + } +} + +#define ORINOCO_MAX_BSS_COUNT 64 +static int orinoco_bss_data_allocate(struct orinoco_private *priv) +{ + if (priv->bss_xbss_data) + return 0; + + if (priv->has_ext_scan) + priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * + sizeof(struct xbss_element), + GFP_KERNEL); + else + priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * + sizeof(struct bss_element), + GFP_KERNEL); + + if (!priv->bss_xbss_data) { + printk(KERN_WARNING "Out of memory allocating beacons"); + return -ENOMEM; + } + return 0; +} + +static void orinoco_bss_data_free(struct orinoco_private *priv) +{ + kfree(priv->bss_xbss_data); + priv->bss_xbss_data = NULL; +} + +#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) +#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) +static void orinoco_bss_data_init(struct orinoco_private *priv) +{ + int i; + + INIT_LIST_HEAD(&priv->bss_free_list); + INIT_LIST_HEAD(&priv->bss_list); + if (priv->has_ext_scan) + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&(PRIV_XBSS[i].list), + &priv->bss_free_list); + else + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&(PRIV_BSS[i].list), + &priv->bss_free_list); + +} + +static inline u8 *orinoco_get_ie(u8 *data, size_t len, + enum ieee80211_eid eid) +{ + u8 *p = data; + while ((p + 2) < (data + len)) { + if (p[0] == eid) + return p; + p += p[1] + 2; + } + return NULL; +} + +#define WPA_OUI_TYPE "\x00\x50\xF2\x01" +#define WPA_SELECTOR_LEN 4 +static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) +{ + u8 *p = data; + while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { + if ((p[0] == WLAN_EID_GENERIC) && + (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) + return p; + p += p[1] + 2; + } + return NULL; +} + + +/********************************************************************/ +/* Download functionality */ +/********************************************************************/ + +struct fw_info { + char *pri_fw; + char *sta_fw; + char *ap_fw; + u32 pda_addr; + u16 pda_size; +}; + +const static struct fw_info orinoco_fw[] = { + { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, + { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } +}; + +/* Structure used to access fields in FW + * Make sure LE decoding macros are used + */ +struct orinoco_fw_header { + char hdr_vers[6]; /* ASCII string for header version */ + __le16 headersize; /* Total length of header */ + __le32 entry_point; /* NIC entry point */ + __le32 blocks; /* Number of blocks to program */ + __le32 block_offset; /* Offset of block data from eof header */ + __le32 pdr_offset; /* Offset to PDR data from eof header */ + __le32 pri_offset; /* Offset to primary plug data */ + __le32 compat_offset; /* Offset to compatibility data*/ + char signature[0]; /* FW signature length headersize-20 */ +} __attribute__ ((packed)); + +/* Download either STA or AP firmware into the card. */ +static int +orinoco_dl_firmware(struct orinoco_private *priv, + const struct fw_info *fw, + int ap) +{ + /* Plug Data Area (PDA) */ + __le16 *pda; + + hermes_t *hw = &priv->hw; + const struct firmware *fw_entry; + const struct orinoco_fw_header *hdr; + const unsigned char *first_block; + const unsigned char *end; + const char *firmware; + struct net_device *dev = priv->ndev; + int err = 0; + + pda = kzalloc(fw->pda_size, GFP_KERNEL); + if (!pda) + return -ENOMEM; + + if (ap) + firmware = fw->ap_fw; + else + firmware = fw->sta_fw; + + printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", + dev->name, firmware); + + /* Read current plug data */ + err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); + printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); + if (err) + goto free; + + if (priv->cached_fw) + fw_entry = priv->cached_fw; + else { + err = request_firmware(&fw_entry, firmware, priv->dev); + if (err) { + printk(KERN_ERR "%s: Cannot find firmware %s\n", + dev->name, firmware); + err = -ENOENT; + goto free; + } + priv->cached_fw = fw_entry; + } + + hdr = (const struct orinoco_fw_header *) fw_entry->data; + + /* Enable aux port to allow programming */ + err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); + printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Program data */ + first_block = (fw_entry->data + + le16_to_cpu(hdr->headersize) + + le32_to_cpu(hdr->block_offset)); + end = fw_entry->data + fw_entry->size; + + err = hermes_program(hw, first_block, end); + printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Update production data */ + first_block = (fw_entry->data + + le16_to_cpu(hdr->headersize) + + le32_to_cpu(hdr->pdr_offset)); + + err = hermes_apply_pda_with_defaults(hw, first_block, pda); + printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); + if (err) + goto abort; + + /* Tell card we've finished */ + err = hermesi_program_end(hw); + printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Check if we're running */ + printk(KERN_DEBUG "%s: hermes_present returned %d\n", + dev->name, hermes_present(hw)); + +abort: + /* In case of error, assume firmware was bogus and release it */ + if (err) { + priv->cached_fw = NULL; + release_firmware(fw_entry); + } + +free: + kfree(pda); + return err; +} + +/* End markers */ +#define TEXT_END 0x1A /* End of text header */ + +/* + * Process a firmware image - stop the card, load the firmware, reset + * the card and make sure it responds. For the secondary firmware take + * care of the PDA - read it and then write it on top of the firmware. + */ +static int +symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, + const unsigned char *image, const unsigned char *end, + int secondary) +{ + hermes_t *hw = &priv->hw; + int ret = 0; + const unsigned char *ptr; + const unsigned char *first_block; + + /* Plug Data Area (PDA) */ + __le16 *pda = NULL; + + /* Binary block begins after the 0x1A marker */ + ptr = image; + while (*ptr++ != TEXT_END); + first_block = ptr; + + /* Read the PDA from EEPROM */ + if (secondary) { + pda = kzalloc(fw->pda_size, GFP_KERNEL); + if (!pda) + return -ENOMEM; + + ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); + if (ret) + goto free; + } + + /* Stop the firmware, so that it can be safely rewritten */ + if (priv->stop_fw) { + ret = priv->stop_fw(priv, 1); + if (ret) + goto free; + } + + /* Program the adapter with new firmware */ + ret = hermes_program(hw, first_block, end); + if (ret) + goto free; + + /* Write the PDA to the adapter */ + if (secondary) { + size_t len = hermes_blocks_length(first_block); + ptr = first_block + len; + ret = hermes_apply_pda(hw, ptr, pda); + kfree(pda); + if (ret) + return ret; + } + + /* Run the firmware */ + if (priv->stop_fw) { + ret = priv->stop_fw(priv, 0); + if (ret) + return ret; + } + + /* Reset hermes chip and make sure it responds */ + ret = hermes_init(hw); + + /* hermes_reset() should return 0 with the secondary firmware */ + if (secondary && ret != 0) + return -ENODEV; + + /* And this should work with any firmware */ + if (!hermes_present(hw)) + return -ENODEV; + + return 0; + +free: + kfree(pda); + return ret; +} + + +/* + * Download the firmware into the card, this also does a PCMCIA soft + * reset on the card, to make sure it's in a sane state. + */ +static int +symbol_dl_firmware(struct orinoco_private *priv, + const struct fw_info *fw) +{ + struct net_device *dev = priv->ndev; + int ret; + const struct firmware *fw_entry; + + if (request_firmware(&fw_entry, fw->pri_fw, + priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->pri_fw); + return -ENOENT; + } + + /* Load primary firmware */ + ret = symbol_dl_image(priv, fw, fw_entry->data, + fw_entry->data + fw_entry->size, 0); + release_firmware(fw_entry); + if (ret) { + printk(KERN_ERR "%s: Primary firmware download failed\n", + dev->name); + return ret; + } + + if (request_firmware(&fw_entry, fw->sta_fw, + priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->sta_fw); + return -ENOENT; + } + + /* Load secondary firmware */ + ret = symbol_dl_image(priv, fw, fw_entry->data, + fw_entry->data + fw_entry->size, 1); + release_firmware(fw_entry); + if (ret) { + printk(KERN_ERR "%s: Secondary firmware download failed\n", + dev->name); + } + + return ret; +} + +static int orinoco_download(struct orinoco_private *priv) +{ + int err = 0; + /* Reload firmware */ + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* case FIRMWARE_TYPE_INTERSIL: */ + err = orinoco_dl_firmware(priv, + &orinoco_fw[priv->firmware_type], 0); + break; + + case FIRMWARE_TYPE_SYMBOL: + err = symbol_dl_firmware(priv, + &orinoco_fw[priv->firmware_type]); + break; + case FIRMWARE_TYPE_INTERSIL: + break; + } + /* TODO: if we fail we probably need to reinitialise + * the driver */ + + return err; +} + +/********************************************************************/ +/* Device methods */ +/********************************************************************/ + +static int orinoco_open(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = __orinoco_up(dev); + + if (! err) + priv->open = 1; + + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_stop(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = 0; + + /* We mustn't use orinoco_lock() here, because we need to be + able to close the interface even if hw_unavailable is set + (e.g. as we're released after a PC Card removal) */ + spin_lock_irq(&priv->lock); + + priv->open = 0; + + err = __orinoco_down(dev); + + spin_unlock_irq(&priv->lock); + + return err; +} + +static struct net_device_stats *orinoco_get_stats(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + + return &priv->stats; +} + +static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err; + unsigned long flags; + + if (! netif_device_present(dev)) { + printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", + dev->name); + return NULL; /* FIXME: Can we do better than this? */ + } + + /* If busy, return the old stats. Returning NULL may cause + * the interface to disappear from /proc/net/wireless */ + if (orinoco_lock(priv, &flags) != 0) + return wstats; + + /* We can't really wait for the tallies inquiry command to + * complete, so we just use the previous results and trigger + * a new tallies inquiry command for next time - Jean II */ + /* FIXME: Really we should wait for the inquiry to come back - + * as it is the stats we give don't make a whole lot of sense. + * Unfortunately, it's not clear how to do that within the + * wireless extensions framework: I think we're in user + * context, but a lock seems to be held by the time we get in + * here so we're not safe to sleep here. */ + hermes_inquire(hw, HERMES_INQ_TALLIES); + + if (priv->iw_mode == IW_MODE_ADHOC) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (SPY_NUMBER(priv)) { + wstats->qual.qual = priv->spy_data.spy_stat[0].qual; + wstats->qual.level = priv->spy_data.spy_stat[0].level; + wstats->qual.noise = priv->spy_data.spy_stat[0].noise; + wstats->qual.updated = priv->spy_data.spy_stat[0].updated; + } + } else { + struct { + __le16 qual, signal, noise, unused; + } __attribute__ ((packed)) cq; + + err = HERMES_READ_RECORD(hw, USER_BAP, + HERMES_RID_COMMSQUALITY, &cq); + + if (!err) { + wstats->qual.qual = (int)le16_to_cpu(cq.qual); + wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; + wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; + wstats->qual.updated = 7; + } + } + + orinoco_unlock(priv, &flags); + return wstats; +} + +static void orinoco_set_multicast_list(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) { + printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " + "called when hw_unavailable\n", dev->name); + return; + } + + __orinoco_set_multicast_list(dev); + orinoco_unlock(priv, &flags); +} + +static int orinoco_change_mtu(struct net_device *dev, int new_mtu) +{ + struct orinoco_private *priv = netdev_priv(dev); + + if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) + return -EINVAL; + + /* MTU + encapsulation + header length */ + if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > + (priv->nicbuf_size - ETH_HLEN) ) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + +/********************************************************************/ +/* Tx path */ +/********************************************************************/ + +static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + u16 txfid = priv->txfid; + struct ethhdr *eh; + int tx_control; + unsigned long flags; + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + return NETDEV_TX_BUSY; + } + + if (netif_queue_stopped(dev)) { + printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", + dev->name); + return NETDEV_TX_BUSY; + } + + if (orinoco_lock(priv, &flags) != 0) { + printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", + dev->name); + return NETDEV_TX_BUSY; + } + + if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) { + /* Oops, the firmware hasn't established a connection, + silently drop the packet (this seems to be the + safest approach). */ + goto drop; + } + + /* Check packet length */ + if (skb->len < ETH_HLEN) + goto drop; + + tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; + + if (priv->encode_alg == IW_ENCODE_ALG_TKIP) + tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | + HERMES_TXCTRL_MIC; + + if (priv->has_alt_txcntl) { + /* WPA enabled firmwares have tx_cntl at the end of + * the 802.11 header. So write zeroed descriptor and + * 802.11 header at the same time + */ + char desc[HERMES_802_3_OFFSET]; + __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; + + memset(&desc, 0, sizeof(desc)); + + *txcntl = cpu_to_le16(tx_control); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), + txfid, 0); + if (err) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx " + "descriptor to BAP\n", dev->name, err); + goto busy; + } + } else { + struct hermes_tx_descriptor desc; + + memset(&desc, 0, sizeof(desc)); + + desc.tx_control = cpu_to_le16(tx_control); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), + txfid, 0); + if (err) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx " + "descriptor to BAP\n", dev->name, err); + goto busy; + } + + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + } + + eh = (struct ethhdr *)skb->data; + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ + struct header_struct { + struct ethhdr eth; /* 802.3 header */ + u8 encap[6]; /* 802.2 header */ + } __attribute__ ((packed)) hdr; + + /* Strip destination and source from the data */ + skb_pull(skb, 2 * ETH_ALEN); + + /* And move them to a separate header */ + memcpy(&hdr.eth, eh, 2 * ETH_ALEN); + hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len); + memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); + + /* Insert the SNAP header */ + if (skb_headroom(skb) < sizeof(hdr)) { + printk(KERN_ERR + "%s: Not enough headroom for 802.2 headers %d\n", + dev->name, skb_headroom(skb)); + goto drop; + } + eh = (struct ethhdr *) skb_push(skb, sizeof(hdr)); + memcpy(eh, &hdr, sizeof(hdr)); + } + + err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len, + txfid, HERMES_802_3_OFFSET); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet to BAP\n", + dev->name, err); + goto busy; + } + + /* Calculate Michael MIC */ + if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { + u8 mic_buf[MICHAEL_MIC_LEN + 1]; + u8 *mic; + size_t offset; + size_t len; + + if (skb->len % 2) { + /* MIC start is on an odd boundary */ + mic_buf[0] = skb->data[skb->len - 1]; + mic = &mic_buf[1]; + offset = skb->len - 1; + len = MICHAEL_MIC_LEN + 1; + } else { + mic = &mic_buf[0]; + offset = skb->len; + len = MICHAEL_MIC_LEN; + } + + michael_mic(priv->tx_tfm_mic, + priv->tkip_key[priv->tx_key].tx_mic, + eh->h_dest, eh->h_source, 0 /* priority */, + skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); + + /* Write the MIC */ + err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len, + txfid, HERMES_802_3_OFFSET + offset); + if (err) { + printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", + dev->name, err); + goto busy; + } + } + + /* Finally, we actually initiate the send */ + netif_stop_queue(dev); + + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, + txfid, NULL); + if (err) { + netif_start_queue(dev); + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d transmitting packet\n", + dev->name, err); + goto busy; + } + + dev->trans_start = jiffies; + stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; + goto ok; + + drop: + stats->tx_errors++; + stats->tx_dropped++; + + ok: + orinoco_unlock(priv, &flags); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + + busy: + if (err == -EIO) + schedule_work(&priv->reset_work); + orinoco_unlock(priv, &flags); + return NETDEV_TX_BUSY; +} + +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + u16 fid = hermes_read_regn(hw, ALLOCFID); + + if (fid != priv->txfid) { + if (fid != DUMMY_FID) + printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", + dev->name, fid); + return; + } + + hermes_write_regn(hw, ALLOCFID, DUMMY_FID); +} + +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + + stats->tx_packets++; + + netif_wake_queue(dev); + + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); +} + +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + u16 fid = hermes_read_regn(hw, TXCOMPLFID); + u16 status; + struct hermes_txexc_data hdr; + int err = 0; + + if (fid == DUMMY_FID) + return; /* Nothing's really happened */ + + /* Read part of the frame header - we need status and addr1 */ + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, + sizeof(struct hermes_txexc_data), + fid, 0); + + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); + stats->tx_errors++; + + if (err) { + printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " + "(FID=%04X error %d)\n", + dev->name, fid, err); + return; + } + + DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, + err, fid); + + /* We produce a TXDROP event only for retry or lifetime + * exceeded, because that's the only status that really mean + * that this particular node went away. + * Other errors means that *we* screwed up. - Jean II */ + status = le16_to_cpu(hdr.desc.status); + if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { + union iwreq_data wrqu; + + /* Copy 802.11 dest address. + * We use the 802.11 header because the frame may + * not be 802.3 or may be mangled... + * In Ad-Hoc mode, it will be the node address. + * In managed mode, it will be most likely the AP addr + * User space will figure out how to convert it to + * whatever it needs (IP address or else). + * - Jean II */ + memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + + /* Send event to user space */ + wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); + } + + netif_wake_queue(dev); +} + +static void orinoco_tx_timeout(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + struct hermes *hw = &priv->hw; + + printk(KERN_WARNING "%s: Tx timeout! " + "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", + dev->name, hermes_read_regn(hw, ALLOCFID), + hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); + + stats->tx_errors++; + + schedule_work(&priv->reset_work); +} + +/********************************************************************/ +/* Rx path (data frames) */ +/********************************************************************/ + +/* Does the frame have a SNAP header indicating it should be + * de-encapsulated to Ethernet-II? */ +static inline int is_ethersnap(void *_hdr) +{ + u8 *hdr = _hdr; + + /* We de-encapsulate all packets which, a) have SNAP headers + * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header + * and where b) the OUI of the SNAP header is 00:00:00 or + * 00:00:f8 - we need both because different APs appear to use + * different OUIs for some reason */ + return (memcmp(hdr, &encaps_hdr, 5) == 0) + && ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) ); +} + +static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, + int level, int noise) +{ + struct iw_quality wstats; + wstats.level = level - 0x95; + wstats.noise = noise - 0x95; + wstats.qual = (level > noise) ? (level - noise) : 0; + wstats.updated = 7; + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); +} + +static void orinoco_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct hermes_rx_descriptor *desc) +{ + struct orinoco_private *priv = netdev_priv(dev); + + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if (SPY_NUMBER(priv)) { + orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN, + desc->signal, desc->silence); + } +} + +/* + * orinoco_rx_monitor - handle received monitor frames. + * + * Arguments: + * dev network device + * rxfid received FID + * desc rx descriptor of the frame + * + * Call context: interrupt + */ +static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, + struct hermes_rx_descriptor *desc) +{ + u32 hdrlen = 30; /* return full header by default */ + u32 datalen = 0; + u16 fc; + int err; + int len; + struct sk_buff *skb; + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + + len = le16_to_cpu(desc->data_len); + + /* Determine the size of the header and the data */ + fc = le16_to_cpu(desc->frame_ctl); + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_TODS) + && (fc & IEEE80211_FCTL_FROMDS)) + hdrlen = 30; + else + hdrlen = 24; + datalen = len; + break; + case IEEE80211_FTYPE_MGMT: + hdrlen = 24; + datalen = len; + break; + case IEEE80211_FTYPE_CTL: + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PSPOLL: + case IEEE80211_STYPE_RTS: + case IEEE80211_STYPE_CFEND: + case IEEE80211_STYPE_CFENDACK: + hdrlen = 16; + break; + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = 10; + break; + } + break; + default: + /* Unknown frame type */ + break; + } + + /* sanity check the length */ + if (datalen > IEEE80211_MAX_DATA_LEN + 12) { + printk(KERN_DEBUG "%s: oversized monitor frame, " + "data length = %d\n", dev->name, datalen); + stats->rx_length_errors++; + goto update_stats; + } + + skb = dev_alloc_skb(hdrlen + datalen); + if (!skb) { + printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n", + dev->name); + goto update_stats; + } + + /* Copy the 802.11 header to the skb */ + memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen); + skb_reset_mac_header(skb); + + /* If any, copy the data from the card to the skb */ + if (datalen > 0) { + err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen), + ALIGN(datalen, 2), rxfid, + HERMES_802_2_OFFSET); + if (err) { + printk(KERN_ERR "%s: error %d reading monitor frame\n", + dev->name, err); + goto drop; + } + } + + skb->dev = dev; + skb->ip_summed = CHECKSUM_NONE; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_802_2); + + stats->rx_packets++; + stats->rx_bytes += skb->len; + + netif_rx(skb); + return; + + drop: + dev_kfree_skb_irq(skb); + update_stats: + stats->rx_errors++; + stats->rx_dropped++; +} + +/* Get tsc from the firmware */ +static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, + u8 *tsc) +{ + hermes_t *hw = &priv->hw; + int err = 0; + u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; + + if ((key < 0) || (key > 4)) + return -EINVAL; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, + sizeof(tsc_arr), NULL, &tsc_arr); + if (!err) + memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); + + return err; +} + +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + u16 rxfid, status; + int length; + struct hermes_rx_descriptor *desc; + struct orinoco_rx_data *rx_data; + int err; + + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if (!desc) { + printk(KERN_WARNING + "%s: Can't allocate space for RX descriptor\n", + dev->name); + goto update_stats; + } + + rxfid = hermes_read_regn(hw, RXFID); + + err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), + rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading Rx descriptor. " + "Frame dropped.\n", dev->name, err); + goto update_stats; + } + + status = le16_to_cpu(desc->status); + + if (status & HERMES_RXSTAT_BADCRC) { + DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", + dev->name); + stats->rx_crc_errors++; + goto update_stats; + } + + /* Handle frames in monitor mode */ + if (priv->iw_mode == IW_MODE_MONITOR) { + orinoco_rx_monitor(dev, rxfid, desc); + goto out; + } + + if (status & HERMES_RXSTAT_UNDECRYPTABLE) { + DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + wstats->discard.code++; + goto update_stats; + } + + length = le16_to_cpu(desc->data_len); + + /* Sanity checks */ + if (length < 3) { /* No for even an 802.2 LLC header */ + /* At least on Symbol firmware with PCF we get quite a + lot of these legitimately - Poll frames with no + data. */ + goto out; + } + if (length > IEEE80211_MAX_DATA_LEN) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + goto update_stats; + } + + /* Payload size does not include Michael MIC. Increase payload + * size to read it together with the data. */ + if (status & HERMES_RXSTAT_MIC) + length += MICHAEL_MIC_LEN; + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + goto update_stats; + } + + /* We'll prepend the header, so reserve space for it. The worst + case is no decapsulation, when 802.3 header is prepended and + nothing is removed. 2 is for aligning the IP header. */ + skb_reserve(skb, ETH_HLEN + 2); + + err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length), + ALIGN(length, 2), rxfid, + HERMES_802_2_OFFSET); + if (err) { + printk(KERN_ERR "%s: error %d reading frame. " + "Frame dropped.\n", dev->name, err); + goto drop; + } + + /* Add desc and skb to rx queue */ + rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); + if (!rx_data) { + printk(KERN_WARNING "%s: Can't allocate RX packet\n", + dev->name); + goto drop; + } + rx_data->desc = desc; + rx_data->skb = skb; + list_add_tail(&rx_data->list, &priv->rx_list); + tasklet_schedule(&priv->rx_tasklet); + + return; + +drop: + dev_kfree_skb_irq(skb); +update_stats: + stats->rx_errors++; + stats->rx_dropped++; +out: + kfree(desc); +} + +static void orinoco_rx(struct net_device *dev, + struct hermes_rx_descriptor *desc, + struct sk_buff *skb) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + u16 status, fc; + int length; + struct ethhdr *hdr; + + status = le16_to_cpu(desc->status); + length = le16_to_cpu(desc->data_len); + fc = le16_to_cpu(desc->frame_ctl); + + /* Calculate and check MIC */ + if (status & HERMES_RXSTAT_MIC) { + int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> + HERMES_MIC_KEY_ID_SHIFT); + u8 mic[MICHAEL_MIC_LEN]; + u8 *rxmic; + u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? + desc->addr3 : desc->addr2; + + /* Extract Michael MIC from payload */ + rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; + + skb_trim(skb, skb->len - MICHAEL_MIC_LEN); + length -= MICHAEL_MIC_LEN; + + michael_mic(priv->rx_tfm_mic, + priv->tkip_key[key_id].rx_mic, + desc->addr1, + src, + 0, /* priority or QoS? */ + skb->data, + skb->len, + &mic[0]); + + if (memcmp(mic, rxmic, + MICHAEL_MIC_LEN)) { + union iwreq_data wrqu; + struct iw_michaelmicfailure wxmic; + + printk(KERN_WARNING "%s: " + "Invalid Michael MIC in data frame from %pM, " + "using key %i\n", + dev->name, src, key_id); + + /* TODO: update stats */ + + /* Notify userspace */ + memset(&wxmic, 0, sizeof(wxmic)); + wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; + wxmic.flags |= (desc->addr1[0] & 1) ? + IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; + wxmic.src_addr.sa_family = ARPHRD_ETHER; + memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); + + (void) orinoco_hw_get_tkip_iv(priv, key_id, + &wxmic.tsc[0]); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(wxmic); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, + (char *) &wxmic); + + goto drop; + } + } + + /* Handle decapsulation + * In most cases, the firmware tell us about SNAP frames. + * For some reason, the SNAP frames sent by LinkSys APs + * are not properly recognised by most firmwares. + * So, check ourselves */ + if (length >= ENCAPS_OVERHEAD && + (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || + is_ethersnap(skb->data))) { + /* These indicate a SNAP within 802.2 LLC within + 802.11 frame which we'll need to de-encapsulate to + the original EthernetII frame. */ + hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); + } else { + /* 802.3 frame - prepend 802.3 header as is */ + hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); + hdr->h_proto = htons(length); + } + memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); + if (fc & IEEE80211_FCTL_FROMDS) + memcpy(hdr->h_source, desc->addr3, ETH_ALEN); + else + memcpy(hdr->h_source, desc->addr2, ETH_ALEN); + + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + if (fc & IEEE80211_FCTL_TODS) + skb->pkt_type = PACKET_OTHERHOST; + + /* Process the wireless stats if needed */ + orinoco_stat_gather(dev, skb, desc); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + dev_kfree_skb(skb); + stats->rx_errors++; + stats->rx_dropped++; +} + +static void orinoco_rx_isr_tasklet(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_rx_data *rx_data, *temp; + struct hermes_rx_descriptor *desc; + struct sk_buff *skb; + + /* extract desc and skb from queue */ + list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { + desc = rx_data->desc; + skb = rx_data->skb; + list_del(&rx_data->list); + kfree(rx_data); + + orinoco_rx(dev, desc, skb); + + kfree(desc); + } +} + +/********************************************************************/ +/* Rx path (info frames) */ +/********************************************************************/ + +static void print_linkstatus(struct net_device *dev, u16 status) +{ + char * s; + + if (suppress_linkstatus) + return; + + switch (status) { + case HERMES_LINKSTATUS_NOT_CONNECTED: + s = "Not Connected"; + break; + case HERMES_LINKSTATUS_CONNECTED: + s = "Connected"; + break; + case HERMES_LINKSTATUS_DISCONNECTED: + s = "Disconnected"; + break; + case HERMES_LINKSTATUS_AP_CHANGE: + s = "AP Changed"; + break; + case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: + s = "AP Out of Range"; + break; + case HERMES_LINKSTATUS_AP_IN_RANGE: + s = "AP In Range"; + break; + case HERMES_LINKSTATUS_ASSOC_FAILED: + s = "Association Failed"; + break; + default: + s = "UNKNOWN"; + } + + printk(KERN_INFO "%s: New link status: %s (%04x)\n", + dev->name, s, status); +} + +/* Search scan results for requested BSSID, join it if found */ +static void orinoco_join_ap(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, join_work); + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + int err; + unsigned long flags; + struct join_req { + u8 bssid[ETH_ALEN]; + __le16 channel; + } __attribute__ ((packed)) req; + const int atom_len = offsetof(struct prism2_scan_apinfo, atim); + struct prism2_scan_apinfo *atom = NULL; + int offset = 4; + int found = 0; + u8 *buf; + u16 len; + + /* Allocate buffer for scan results */ + buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL); + if (! buf) + return; + + if (orinoco_lock(priv, &flags) != 0) + goto fail_lock; + + /* Sanity checks in case user changed something in the meantime */ + if (! priv->bssid_fixed) + goto out; + + if (strlen(priv->desired_essid) == 0) + goto out; + + /* Read scan results from the firmware */ + err = hermes_read_ltv(hw, USER_BAP, + HERMES_RID_SCANRESULTSTABLE, + MAX_SCAN_LEN, &len, buf); + if (err) { + printk(KERN_ERR "%s: Cannot read scan results\n", + dev->name); + goto out; + } + + len = HERMES_RECLEN_TO_BYTES(len); + + /* Go through the scan results looking for the channel of the AP + * we were requested to join */ + for (; offset + atom_len <= len; offset += atom_len) { + atom = (struct prism2_scan_apinfo *) (buf + offset); + if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) { + found = 1; + break; + } + } + + if (! found) { + DEBUG(1, "%s: Requested AP not found in scan results\n", + dev->name); + goto out; + } + + memcpy(req.bssid, priv->desired_bssid, ETH_ALEN); + req.channel = atom->channel; /* both are little-endian */ + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST, + &req); + if (err) + printk(KERN_ERR "%s: Error issuing join request\n", dev->name); + + out: + orinoco_unlock(priv, &flags); + + fail_lock: + kfree(buf); +} + +/* Send new BSSID to userspace */ +static void orinoco_send_bssid_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, + ETH_ALEN, NULL, wrqu.ap_addr.sa_data); + if (err != 0) + return; + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +} + +static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + u8 buf[88]; + u8 *ie; + + if (!priv->has_wpa) + return; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, + sizeof(buf), NULL, &buf); + if (err != 0) + return; + + ie = orinoco_get_wpa_ie(buf, sizeof(buf)); + if (ie) { + int rem = sizeof(buf) - (ie - &buf[0]); + wrqu.data.length = ie[1] + 2; + if (wrqu.data.length > rem) + wrqu.data.length = rem; + + if (wrqu.data.length) + /* Send event to user space */ + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); + } +} + +static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ + u8 *ie; + + if (!priv->has_wpa) + return; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, + sizeof(buf), NULL, &buf); + if (err != 0) + return; + + ie = orinoco_get_wpa_ie(buf, sizeof(buf)); + if (ie) { + int rem = sizeof(buf) - (ie - &buf[0]); + wrqu.data.length = ie[1] + 2; + if (wrqu.data.length > rem) + wrqu.data.length = rem; + + if (wrqu.data.length) + /* Send event to user space */ + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); + } +} + +static void orinoco_send_wevents(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, wevent_work); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return; + + orinoco_send_assocreqie_wevent(priv); + orinoco_send_assocrespie_wevent(priv); + orinoco_send_bssid_wevent(priv); + + orinoco_unlock(priv, &flags); +} + +static inline void orinoco_clear_scan_results(struct orinoco_private *priv, + unsigned long scan_age) +{ + if (priv->has_ext_scan) { + struct xbss_element *bss; + struct xbss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, + &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(&bss->bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } + } + } else { + struct bss_element *bss; + struct bss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, + &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(&bss->bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } + } + } +} + +static void orinoco_add_ext_scan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *atom) +{ + struct xbss_element *bss = NULL; + int found = 0; + + /* Try to update an existing bss first */ + list_for_each_entry(bss, &priv->bss_list, list) { + if (compare_ether_addr(bss->bss.bssid, atom->bssid)) + continue; + /* ESSID lengths */ + if (bss->bss.data[1] != atom->data[1]) + continue; + if (memcmp(&bss->bss.data[2], &atom->data[2], + atom->data[1])) + continue; + found = 1; + break; + } + + /* Grab a bss off the free list */ + if (!found && !list_empty(&priv->bss_free_list)) { + bss = list_entry(priv->bss_free_list.next, + struct xbss_element, list); + list_del(priv->bss_free_list.next); + + list_add_tail(&bss->list, &priv->bss_list); + } + + if (bss) { + /* Always update the BSS to get latest beacon info */ + memcpy(&bss->bss, atom, sizeof(bss->bss)); + bss->last_scanned = jiffies; + } +} + +static int orinoco_process_scan_results(struct net_device *dev, + unsigned char *buf, + int len) +{ + struct orinoco_private *priv = netdev_priv(dev); + int offset; /* In the scan data */ + union hermes_scan_info *atom; + int atom_len; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + atom_len = sizeof(struct agere_scan_apinfo); + offset = 0; + break; + case FIRMWARE_TYPE_SYMBOL: + /* Lack of documentation necessitates this hack. + * Different firmwares have 68 or 76 byte long atoms. + * We try modulo first. If the length divides by both, + * we check what would be the channel in the second + * frame for a 68-byte atom. 76-byte atoms have 0 there. + * Valid channel cannot be 0. */ + if (len % 76) + atom_len = 68; + else if (len % 68) + atom_len = 76; + else if (len >= 1292 && buf[68] == 0) + atom_len = 76; + else + atom_len = 68; + offset = 0; + break; + case FIRMWARE_TYPE_INTERSIL: + offset = 4; + if (priv->has_hostscan) { + atom_len = le16_to_cpup((__le16 *)buf); + /* Sanity check for atom_len */ + if (atom_len < sizeof(struct prism2_scan_apinfo)) { + printk(KERN_ERR "%s: Invalid atom_len in scan " + "data: %d\n", dev->name, atom_len); + return -EIO; + } + } else + atom_len = offsetof(struct prism2_scan_apinfo, atim); + break; + default: + return -EOPNOTSUPP; + } + + /* Check that we got an whole number of atoms */ + if ((len - offset) % atom_len) { + printk(KERN_ERR "%s: Unexpected scan data length %d, " + "atom_len %d, offset %d\n", dev->name, len, + atom_len, offset); + return -EIO; + } + + orinoco_clear_scan_results(priv, msecs_to_jiffies(15000)); + + /* Read the entries one by one */ + for (; offset + atom_len <= len; offset += atom_len) { + int found = 0; + struct bss_element *bss = NULL; + + /* Get next atom */ + atom = (union hermes_scan_info *) (buf + offset); + + /* Try to update an existing bss first */ + list_for_each_entry(bss, &priv->bss_list, list) { + if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid)) + continue; + if (le16_to_cpu(bss->bss.a.essid_len) != + le16_to_cpu(atom->a.essid_len)) + continue; + if (memcmp(bss->bss.a.essid, atom->a.essid, + le16_to_cpu(atom->a.essid_len))) + continue; + found = 1; + break; + } + + /* Grab a bss off the free list */ + if (!found && !list_empty(&priv->bss_free_list)) { + bss = list_entry(priv->bss_free_list.next, + struct bss_element, list); + list_del(priv->bss_free_list.next); + + list_add_tail(&bss->list, &priv->bss_list); + } + + if (bss) { + /* Always update the BSS to get latest beacon info */ + memcpy(&bss->bss, atom, sizeof(bss->bss)); + bss->last_scanned = jiffies; + } + } + + return 0; +} + +static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) +{ + struct orinoco_private *priv = netdev_priv(dev); + u16 infofid; + struct { + __le16 len; + __le16 type; + } __attribute__ ((packed)) info; + int len, type; + int err; + + /* This is an answer to an INQUIRE command that we did earlier, + * or an information "event" generated by the card + * The controller return to us a pseudo frame containing + * the information in question - Jean II */ + infofid = hermes_read_regn(hw, INFOFID); + + /* Read the info frame header - don't try too hard */ + err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), + infofid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading info frame. " + "Frame dropped.\n", dev->name, err); + return; + } + + len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); + type = le16_to_cpu(info.type); + + switch (type) { + case HERMES_INQ_TALLIES: { + struct hermes_tallies_frame tallies; + struct iw_statistics *wstats = &priv->wstats; + + if (len > sizeof(tallies)) { + printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", + dev->name, len); + len = sizeof(tallies); + } + + err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len, + infofid, sizeof(info)); + if (err) + break; + + /* Increment our various counters */ + /* wstats->discard.nwid - no wrong BSSID stuff */ + wstats->discard.code += + le16_to_cpu(tallies.RxWEPUndecryptable); + if (len == sizeof(tallies)) + wstats->discard.code += + le16_to_cpu(tallies.RxDiscards_WEPICVError) + + le16_to_cpu(tallies.RxDiscards_WEPExcluded); + wstats->discard.misc += + le16_to_cpu(tallies.TxDiscardsWrongSA); + wstats->discard.fragment += + le16_to_cpu(tallies.RxMsgInBadMsgFragments); + wstats->discard.retries += + le16_to_cpu(tallies.TxRetryLimitExceeded); + /* wstats->miss.beacon - no match */ + } + break; + case HERMES_INQ_LINKSTATUS: { + struct hermes_linkstatus linkstatus; + u16 newstatus; + int connected; + + if (priv->iw_mode == IW_MODE_MONITOR) + break; + + if (len != sizeof(linkstatus)) { + printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", + dev->name, len); + break; + } + + err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len, + infofid, sizeof(info)); + if (err) + break; + newstatus = le16_to_cpu(linkstatus.linkstatus); + + /* Symbol firmware uses "out of range" to signal that + * the hostscan frame can be requested. */ + if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && + priv->firmware_type == FIRMWARE_TYPE_SYMBOL && + priv->has_hostscan && priv->scan_inprogress) { + hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); + break; + } + + connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); + + if (connected) + netif_carrier_on(dev); + else if (!ignore_disconnect) + netif_carrier_off(dev); + + if (newstatus != priv->last_linkstatus) { + priv->last_linkstatus = newstatus; + print_linkstatus(dev, newstatus); + /* The info frame contains only one word which is the + * status (see hermes.h). The status is pretty boring + * in itself, that's why we export the new BSSID... + * Jean II */ + schedule_work(&priv->wevent_work); + } + } + break; + case HERMES_INQ_SCAN: + if (!priv->scan_inprogress && priv->bssid_fixed && + priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { + schedule_work(&priv->join_work); + break; + } + /* fall through */ + case HERMES_INQ_HOSTSCAN: + case HERMES_INQ_HOSTSCAN_SYMBOL: { + /* Result of a scanning. Contains information about + * cells in the vicinity - Jean II */ + union iwreq_data wrqu; + unsigned char *buf; + + /* Scan is no longer in progress */ + priv->scan_inprogress = 0; + + /* Sanity check */ + if (len > 4096) { + printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", + dev->name, len); + break; + } + + /* Allocate buffer for results */ + buf = kmalloc(len, GFP_ATOMIC); + if (buf == NULL) + /* No memory, so can't printk()... */ + break; + + /* Read scan data */ + err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, + infofid, sizeof(info)); + if (err) { + kfree(buf); + break; + } + +#ifdef ORINOCO_DEBUG + { + int i; + printk(KERN_DEBUG "Scan result [%02X", buf[0]); + for(i = 1; i < (len * 2); i++) + printk(":%02X", buf[i]); + printk("]\n"); + } +#endif /* ORINOCO_DEBUG */ + + if (orinoco_process_scan_results(dev, buf, len) == 0) { + /* Send an empty event to user space. + * We don't send the received data on the event because + * it would require us to do complex transcoding, and + * we want to minimise the work done in the irq handler + * Use a request to extract the data - Jean II */ + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + } + kfree(buf); + } + break; + case HERMES_INQ_CHANNELINFO: + { + struct agere_ext_scan_info *bss; + + if (!priv->scan_inprogress) { + printk(KERN_DEBUG "%s: Got chaninfo without scan, " + "len=%d\n", dev->name, len); + break; + } + + /* An empty result indicates that the scan is complete */ + if (len == 0) { + union iwreq_data wrqu; + + /* Scan is no longer in progress */ + priv->scan_inprogress = 0; + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + break; + } + + /* Sanity check */ + else if (len > sizeof(*bss)) { + printk(KERN_WARNING + "%s: Ext scan results too large (%d bytes). " + "Truncating results to %zd bytes.\n", + dev->name, len, sizeof(*bss)); + len = sizeof(*bss); + } else if (len < (offsetof(struct agere_ext_scan_info, + data) + 2)) { + /* Drop this result now so we don't have to + * keep checking later */ + printk(KERN_WARNING + "%s: Ext scan results too short (%d bytes)\n", + dev->name, len); + break; + } + + bss = kmalloc(sizeof(*bss), GFP_ATOMIC); + if (bss == NULL) + break; + + /* Read scan data */ + err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, + infofid, sizeof(info)); + if (err) { + kfree(bss); + break; + } + + orinoco_add_ext_scan_result(priv, bss); + + kfree(bss); + break; + } + case HERMES_INQ_SEC_STAT_AGERE: + /* Security status (Agere specific) */ + /* Ignore this frame for now */ + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) + break; + /* fall through */ + default: + printk(KERN_DEBUG "%s: Unknown information frame received: " + "type 0x%04x, length %d\n", dev->name, type, len); + /* We don't actually do anything about it */ + break; + } +} + +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) +{ + if (net_ratelimit()) + printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); +} + +/********************************************************************/ +/* Internal hardware control routines */ +/********************************************************************/ + +int __orinoco_up(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + + netif_carrier_off(dev); /* just to make sure */ + + err = __orinoco_program_rids(dev); + if (err) { + printk(KERN_ERR "%s: Error %d configuring card\n", + dev->name, err); + return err; + } + + /* Fire things up again */ + hermes_set_irqmask(hw, ORINOCO_INTEN); + err = hermes_enable_port(hw, 0); + if (err) { + printk(KERN_ERR "%s: Error %d enabling MAC port\n", + dev->name, err); + return err; + } + + netif_start_queue(dev); + + return 0; +} + +int __orinoco_down(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + + netif_stop_queue(dev); + + if (! priv->hw_unavailable) { + if (! priv->broken_disableport) { + err = hermes_disable_port(hw, 0); + if (err) { + /* Some firmwares (e.g. Intersil 1.3.x) seem + * to have problems disabling the port, oh + * well, too bad. */ + printk(KERN_WARNING "%s: Error %d disabling MAC port\n", + dev->name, err); + priv->broken_disableport = 1; + } + } + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + } + + /* firmware will have to reassociate */ + netif_carrier_off(dev); + priv->last_linkstatus = 0xffff; + + return 0; +} + +static int orinoco_allocate_fid(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { + /* Try workaround for old Symbol firmware bug */ + printk(KERN_WARNING "%s: firmware ALLOC bug detected " + "(old Symbol firmware?). Trying to work around... ", + dev->name); + + priv->nicbuf_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + if (err) + printk("failed!\n"); + else + printk("ok.\n"); + } + + return err; +} + +int orinoco_reinit_firmware(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + int err; + + err = hermes_init(hw); + if (priv->do_fw_download && !err) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + } + if (!err) + err = orinoco_allocate_fid(dev); + + return err; +} + +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + if (priv->bitratemode >= BITRATE_TABLE_SIZE) { + printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", + priv->ndev->name, priv->bitratemode); + return -EINVAL; + } + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].agere_txratectrl); + break; + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].intersil_txratectrl); + break; + default: + BUG(); + } + + return err; +} + +/* Set fixed AP address */ +static int __orinoco_hw_set_wap(struct orinoco_private *priv) +{ + int roaming_flag; + int err = 0; + hermes_t *hw = &priv->hw; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* not supported */ + break; + case FIRMWARE_TYPE_INTERSIL: + if (priv->bssid_fixed) + roaming_flag = 2; + else + roaming_flag = 1; + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFROAMINGMODE, + roaming_flag); + break; + case FIRMWARE_TYPE_SYMBOL: + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFMANDATORYBSSID_SYMBOL, + &priv->desired_bssid); + break; + } + return err; +} + +/* Change the WEP keys and/or the current keys. Can be called + * either from __orinoco_hw_setup_enc() or directly from + * orinoco_ioctl_setiwencode(). In the later case the association + * with the AP is not broken (if the firmware can handle it), + * which is needed for 802.1x implementations. */ +static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFWEPKEYS_AGERE, + &priv->keys); + if (err) + return err; + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXKEY_AGERE, + priv->tx_key); + if (err) + return err; + break; + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + { + int keylen; + int i; + + /* Force uniform key length to work around firmware bugs */ + keylen = le16_to_cpu(priv->keys[priv->tx_key].len); + + if (keylen > LARGE_KEY_SIZE) { + printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", + priv->ndev->name, priv->tx_key, keylen); + return -E2BIG; + } + + /* Write all 4 keys */ + for(i = 0; i < ORINOCO_MAX_KEYS; i++) { + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFDEFAULTKEY0 + i, + HERMES_BYTES_TO_RECLEN(keylen), + priv->keys[i].data); + if (err) + return err; + } + + /* Write the index of the key used in transmission */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPDEFAULTKEYID, + priv->tx_key); + if (err) + return err; + } + break; + } + + return 0; +} + +static int __orinoco_hw_setup_enc(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + int master_wep_flag; + int auth_flag; + int enc_flag; + + /* Setup WEP keys for WEP and WPA */ + if (priv->encode_alg) + __orinoco_hw_setup_wepkeys(priv); + + if (priv->wep_restrict) + auth_flag = HERMES_AUTH_SHARED_KEY; + else + auth_flag = HERMES_AUTH_OPEN; + + if (priv->wpa_enabled) + enc_flag = 2; + else if (priv->encode_alg == IW_ENCODE_ALG_WEP) + enc_flag = 1; + else + enc_flag = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ + if (priv->encode_alg == IW_ENCODE_ALG_WEP) { + /* Enable the shared-key authentication. */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION_AGERE, + auth_flag); + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPENABLED_AGERE, + enc_flag); + if (err) + return err; + + if (priv->has_wpa) { + /* Set WPA key management */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, + priv->key_mgmt); + if (err) + return err; + } + + break; + + case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->encode_alg == IW_ENCODE_ALG_WEP) { + if (priv->wep_restrict || + (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) + master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | + HERMES_WEP_EXCL_UNENCRYPTED; + else + master_wep_flag = HERMES_WEP_PRIVACY_INVOKED; + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION, + auth_flag); + if (err) + return err; + } else + master_wep_flag = 0; + + if (priv->iw_mode == IW_MODE_MONITOR) + master_wep_flag |= HERMES_WEP_HOST_DECRYPT; + + /* Master WEP setting : on/off */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPFLAGS_INTERSIL, + master_wep_flag); + if (err) + return err; + + break; + } + + return 0; +} + +/* key must be 32 bytes, including the tx and rx MIC keys. + * rsc must be 8 bytes + * tsc must be 8 bytes or NULL + */ +static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, + u8 *key, u8 *rsc, u8 *tsc) +{ + struct { + __le16 idx; + u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 key[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; + u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; + } __attribute__ ((packed)) buf; + int ret; + int err; + int k; + u16 xmitting; + + key_idx &= 0x3; + + if (set_tx) + key_idx |= 0x8000; + + buf.idx = cpu_to_le16(key_idx); + memcpy(buf.key, key, + sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); + + if (rsc == NULL) + memset(buf.rsc, 0, sizeof(buf.rsc)); + else + memcpy(buf.rsc, rsc, sizeof(buf.rsc)); + + if (tsc == NULL) { + memset(buf.tsc, 0, sizeof(buf.tsc)); + buf.tsc[4] = 0x10; + } else { + memcpy(buf.tsc, tsc, sizeof(buf.tsc)); + } + + /* Wait upto 100ms for tx queue to empty */ + k = 100; + do { + k--; + udelay(1000); + ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, + &xmitting); + if (ret) + break; + } while ((k > 0) && xmitting); + + if (k == 0) + ret = -ETIMEDOUT; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, + &buf); + + return ret ? ret : err; +} + +static int orinoco_clear_tkip_key(struct orinoco_private *priv, + int key_idx) +{ + hermes_t *hw = &priv->hw; + int err; + + memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, + key_idx); + if (err) + printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", + priv->ndev->name, err, key_idx); + return err; +} + +static int __orinoco_program_rids(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err; + struct hermes_idstring idbuf; + + /* Set the MAC address */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); + if (err) { + printk(KERN_ERR "%s: Error %d setting MAC address\n", + dev->name, err); + return err; + } + + /* Set up the link mode */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, + priv->port_type); + if (err) { + printk(KERN_ERR "%s: Error %d setting port type\n", + dev->name, err); + return err; + } + /* Set the channel/frequency */ + if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFOWNCHANNEL, + priv->channel); + if (err) { + printk(KERN_ERR "%s: Error %d setting channel %d\n", + dev->name, err, priv->channel); + return err; + } + } + + if (priv->has_ibss) { + u16 createibss; + + if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { + printk(KERN_WARNING "%s: This firmware requires an " + "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + createibss = 0; + } else { + createibss = priv->createibss; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFCREATEIBSS, + createibss); + if (err) { + printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", + dev->name, err); + return err; + } + } + + /* Set the desired BSSID */ + err = __orinoco_hw_set_wap(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting AP address\n", + dev->name, err); + return err; + } + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting OWNSSID\n", + dev->name, err); + return err; + } + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", + dev->name, err); + return err; + } + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting nickname\n", + dev->name, err); + return err; + } + + /* Set AP density */ + if (priv->has_sensitivity) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, + priv->ap_density); + if (err) { + printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " + "Disabling sensitivity control\n", + dev->name, err); + + priv->has_sensitivity = 0; + } + } + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting RTS threshold\n", + dev->name, err); + return err; + } + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting fragmentation\n", + dev->name, err); + return err; + } + + /* Set bitrate */ + err = __orinoco_hw_set_bitrate(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting bitrate\n", + dev->name, err); + return err; + } + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMENABLED, + priv->pm_on); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMULTICASTRECEIVE, + priv->pm_mcast); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + priv->pm_period); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + priv->preamble); + if (err) { + printk(KERN_ERR "%s: Error %d setting preamble\n", + dev->name, err); + return err; + } + } + + /* Set up encryption */ + if (priv->has_wep || priv->has_wpa) { + err = __orinoco_hw_setup_enc(priv); + if (err) { + printk(KERN_ERR "%s: Error %d activating encryption\n", + dev->name, err); + return err; + } + } + + if (priv->iw_mode == IW_MODE_MONITOR) { + /* Enable monitor mode */ + dev->type = ARPHRD_IEEE80211; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_MONITOR, 0, NULL); + } else { + /* Disable monitor mode */ + dev->type = ARPHRD_ETHER; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_STOP, 0, NULL); + } + if (err) + return err; + + /* Set promiscuity / multicast*/ + priv->promiscuous = 0; + priv->mc_count = 0; + + /* FIXME: what about netif_tx_lock */ + __orinoco_set_multicast_list(dev); + + return 0; +} + +/* FIXME: return int? */ +static void +__orinoco_set_multicast_list(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, mc_count; + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > MAX_MULTICAST(priv)) ) { + promisc = 1; + mc_count = 0; + } else { + promisc = 0; + mc_count = dev->mc_count; + } + + if (promisc != priv->promiscuous) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPROMISCUOUSMODE, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", + dev->name, err); + } else + priv->promiscuous = promisc; + } + + /* If we're not in promiscuous mode, then we need to set the + * group address if either we want to multicast, or if we were + * multicasting and want to stop */ + if (! promisc && (mc_count || priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + struct hermes_multicast mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* paranoia: is list shorter than mc_count? */ + BUG_ON(! p); + /* paranoia: bad address size in list? */ + BUG_ON(p->dmi_addrlen != ETH_ALEN); + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + if (p) + printk(KERN_WARNING "%s: Multicast list is " + "longer than mc_count\n", dev->name); + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFGROUPADDRESSES, + HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->mc_count = mc_count; + } +} + +/* This must be called from user context, without locks held - use + * schedule_work() */ +static void orinoco_reset(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, reset_work); + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + int err; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + /* When the hardware becomes available again, whatever + * detects that is responsible for re-initializing + * it. So no need for anything further */ + return; + + netif_stop_queue(dev); + + /* Shut off interrupts. Depending on what state the hardware + * is in, this might not work, but we'll try anyway */ + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + priv->hw_unavailable++; + priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ + netif_carrier_off(dev); + + orinoco_unlock(priv, &flags); + + /* Scanning support: Cleanup of driver struct */ + orinoco_clear_scan_results(priv, 0); + priv->scan_inprogress = 0; + + if (priv->hard_reset) { + err = (*priv->hard_reset)(priv); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d " + "performing hard reset\n", dev->name, err); + goto disable; + } + } + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", + dev->name, err); + goto disable; + } + + spin_lock_irq(&priv->lock); /* This has to be called from user context */ + + priv->hw_unavailable--; + + /* priv->open or priv->hw_unavailable might have changed while + * we dropped the lock */ + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", + dev->name, err); + } else + dev->trans_start = jiffies; + } + + spin_unlock_irq(&priv->lock); + + return; + disable: + hermes_set_irqmask(hw, 0); + netif_device_detach(dev); + printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); +} + +/********************************************************************/ +/* Interrupt handler */ +/********************************************************************/ + +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) +{ + printk(KERN_DEBUG "%s: TICK\n", dev->name); +} + +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) +{ + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", + dev->name); +} + +irqreturn_t orinoco_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int count = MAX_IRQLOOPS_PER_IRQ; + u16 evstat, events; + /* These are used to detect a runaway interrupt situation */ + /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, + * we panic and shut down the hardware */ + static int last_irq_jiffy = 0; /* jiffies value the last time + * we were called */ + static int loops_this_jiffy = 0; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) { + /* If hw is unavailable - we don't know if the irq was + * for us or not */ + return IRQ_HANDLED; + } + + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + if (! events) { + orinoco_unlock(priv, &flags); + return IRQ_NONE; + } + + if (jiffies != last_irq_jiffy) + loops_this_jiffy = 0; + last_irq_jiffy = jiffies; + + while (events && count--) { + if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { + printk(KERN_WARNING "%s: IRQ handler is looping too " + "much! Resetting.\n", dev->name); + /* Disable interrupts for now */ + hermes_set_irqmask(hw, 0); + schedule_work(&priv->reset_work); + break; + } + + /* Check the card hasn't been removed */ + if (! hermes_present(hw)) { + DEBUG(0, "orinoco_interrupt(): card removed\n"); + break; + } + + if (events & HERMES_EV_TICK) + __orinoco_ev_tick(dev, hw); + if (events & HERMES_EV_WTERR) + __orinoco_ev_wterr(dev, hw); + if (events & HERMES_EV_INFDROP) + __orinoco_ev_infdrop(dev, hw); + if (events & HERMES_EV_INFO) + __orinoco_ev_info(dev, hw); + if (events & HERMES_EV_RX) + __orinoco_ev_rx(dev, hw); + if (events & HERMES_EV_TXEXC) + __orinoco_ev_txexc(dev, hw); + if (events & HERMES_EV_TX) + __orinoco_ev_tx(dev, hw); + if (events & HERMES_EV_ALLOC) + __orinoco_ev_alloc(dev, hw); + + hermes_write_regn(hw, EVACK, evstat); + + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + }; + + orinoco_unlock(priv, &flags); + return IRQ_HANDLED; +} + +/********************************************************************/ +/* Initialization */ +/********************************************************************/ + +struct comp_id { + u16 id, variant, major, minor; +} __attribute__ ((packed)); + +static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) +{ + if (nic_id->id < 0x8000) + return FIRMWARE_TYPE_AGERE; + else if (nic_id->id == 0x8000 && nic_id->major == 0) + return FIRMWARE_TYPE_SYMBOL; + else + return FIRMWARE_TYPE_INTERSIL; +} + +/* Set priv->firmware type, determine firmware properties */ +static int determine_firmware(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err; + struct comp_id nic_id, sta_id; + unsigned int firmver; + char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); + + /* Get the hardware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); + if (err) { + printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&nic_id.id); + le16_to_cpus(&nic_id.variant); + le16_to_cpus(&nic_id.major); + le16_to_cpus(&nic_id.minor); + printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", + dev->name, nic_id.id, nic_id.variant, + nic_id.major, nic_id.minor); + + priv->firmware_type = determine_firmware_type(&nic_id); + + /* Get the firmware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); + if (err) { + printk(KERN_ERR "%s: Cannot read station identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&sta_id.id); + le16_to_cpus(&sta_id.variant); + le16_to_cpus(&sta_id.major); + le16_to_cpus(&sta_id.minor); + printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", + dev->name, sta_id.id, sta_id.variant, + sta_id.major, sta_id.minor); + + switch (sta_id.id) { + case 0x15: + printk(KERN_ERR "%s: Primary firmware is active\n", + dev->name); + return -ENODEV; + case 0x14b: + printk(KERN_ERR "%s: Tertiary firmware is active\n", + dev->name); + return -ENODEV; + case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ + case 0x21: /* Symbol Spectrum24 Trilogy */ + break; + default: + printk(KERN_NOTICE "%s: Unknown station ID, please report\n", + dev->name); + break; + } + + /* Default capabilities */ + priv->has_sensitivity = 1; + priv->has_mwo = 0; + priv->has_preamble = 0; + priv->has_port3 = 1; + priv->has_ibss = 1; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_alt_txcntl = 0; + priv->has_ext_scan = 0; + priv->has_wpa = 0; + priv->do_fw_download = 0; + + /* Determine capabilities from the firmware version */ + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); + + firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; + + priv->has_ibss = (firmver >= 0x60006); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ + priv->ibss_port = 1; + priv->has_hostscan = (firmver >= 0x8000a); + priv->do_fw_download = 1; + priv->broken_monitor = (firmver >= 0x80000); + priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_wpa = (firmver >= 0x9002a); + /* Tested with Agere firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case FIRMWARE_TYPE_SYMBOL: + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ + /* Intel MAC : 00:02:B3:* */ + /* 3Com MAC : 00:50:DA:* */ + memset(tmp, 0, sizeof(tmp)); + /* Get the Symbol firmware version */ + err = hermes_read_ltv(hw, USER_BAP, + HERMES_RID_SECONDARYVERSION_SYMBOL, + SYMBOL_MAX_VER_LEN, NULL, &tmp); + if (err) { + printk(KERN_WARNING + "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n", + dev->name, err); + firmver = 0; + tmp[0] = '\0'; + } else { + /* The firmware revision is a string, the format is + * something like : "V2.20-01". + * Quick and dirty parsing... - Jean II + */ + firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12) + | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4) + | (tmp[7] - '0'); + + tmp[SYMBOL_MAX_VER_LEN] = '\0'; + } + + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Symbol %s", tmp); + + priv->has_ibss = (firmver >= 0x20000); + priv->has_wep = (firmver >= 0x15012); + priv->has_big_wep = (firmver >= 0x20000); + priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || + (firmver >= 0x29000 && firmver < 0x30000) || + firmver >= 0x31000; + priv->has_preamble = (firmver >= 0x20000); + priv->ibss_port = 4; + + /* Symbol firmware is found on various cards, but + * there has been no attempt to check firmware + * download on non-spectrum_cs based cards. + * + * Given that the Agere firmware download works + * differently, we should avoid doing a firmware + * download with the Symbol algorithm on non-spectrum + * cards. + * + * For now we can identify a spectrum_cs based card + * because it has a firmware reset function. + */ + priv->do_fw_download = (priv->stop_fw != NULL); + + priv->broken_disableport = (firmver == 0x25013) || + (firmver >= 0x30000 && firmver <= 0x31000); + priv->has_hostscan = (firmver >= 0x31001) || + (firmver >= 0x29057 && firmver < 0x30000); + /* Tested with Intel firmware : 0x20015 => Jean II */ + /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ + break; + case FIRMWARE_TYPE_INTERSIL: + /* D-Link, Linksys, Adtron, ZoomAir, and many others... + * Samsung, Compaq 100/200 and Proxim are slightly + * different and less well tested */ + /* D-Link MAC : 00:40:05:* */ + /* Addtron MAC : 00:90:D1:* */ + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Intersil %d.%d.%d", sta_id.major, sta_id.minor, + sta_id.variant); + + firmver = ((unsigned long)sta_id.major << 16) | + ((unsigned long)sta_id.minor << 8) | sta_id.variant; + + priv->has_ibss = (firmver >= 0x000700); /* FIXME */ + priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); + priv->has_pm = (firmver >= 0x000700); + priv->has_hostscan = (firmver >= 0x010301); + + if (firmver >= 0x000800) + priv->ibss_port = 0; + else { + printk(KERN_NOTICE "%s: Intersil firmware earlier " + "than v0.8.x - several features not supported\n", + dev->name); + priv->ibss_port = 1; + } + break; + } + printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, + priv->fw_name); + + return 0; +} + +static int orinoco_init(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + struct hermes_idstring nickbuf; + u16 reclen; + int len; + + /* No need to lock, the hw_unavailable flag is already set in + * alloc_orinocodev() */ + priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; + + /* Initialize the firmware */ + err = hermes_init(hw); + if (err != 0) { + printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", + dev->name, err); + goto out; + } + + err = determine_firmware(dev); + if (err != 0) { + printk(KERN_ERR "%s: Incompatible firmware, aborting\n", + dev->name); + goto out; + } + + if (priv->do_fw_download) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + + /* Check firmware version again */ + err = determine_firmware(dev); + if (err != 0) { + printk(KERN_ERR "%s: Incompatible firmware, aborting\n", + dev->name); + goto out; + } + } + + if (priv->has_port3) + printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); + if (priv->has_ibss) + printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", + dev->name); + if (priv->has_wep) { + printk(KERN_DEBUG "%s: WEP supported, ", dev->name); + if (priv->has_big_wep) + printk("104-bit key\n"); + else + printk("40-bit key\n"); + } + if (priv->has_wpa) { + printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); + if (orinoco_mic_init(priv)) { + printk(KERN_ERR "%s: Failed to setup MIC crypto " + "algorithm. Disabling WPA support\n", dev->name); + priv->has_wpa = 0; + } + } + + /* Now we have the firmware capabilities, allocate appropiate + * sized scan buffers */ + if (orinoco_bss_data_allocate(priv)) + goto out; + orinoco_bss_data_init(priv); + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + ETH_ALEN, NULL, dev->dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_DEBUG "%s: MAC address %pM\n", + dev->name, dev->dev_addr); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name\n", + dev->name); + goto out; + } + if (nickbuf.len) + len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); + else + len = min(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); + + err = orinoco_allocate_fid(dev); + if (err) { + printk(KERN_ERR "%s: failed to allocate NIC buffer!\n", + dev->name); + goto out; + } + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, + &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, + &priv->ap_density); + if (err || priv->ap_density < 1 || priv->ap_density > 3) { + priv->has_sensitivity = 0; + } + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", + dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", + dev->name); + goto out; + } + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management period!\n", + dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management timeout!\n", + dev->name); + goto out; + } + } + + /* Preamble setup */ + if (priv->has_preamble) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + &priv->preamble); + if (err) + goto out; + } + + /* Set up the default configuration */ + priv->iw_mode = IW_MODE_INFRA; + /* By default use IEEE/IBSS ad-hoc mode if we have it */ + priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); + set_port_type(priv); + priv->channel = 0; /* use firmware default */ + + priv->promiscuous = 0; + priv->encode_alg = IW_ENCODE_ALG_NONE; + priv->tx_key = 0; + priv->wpa_enabled = 0; + priv->tkip_cm_active = 0; + priv->key_mgmt = 0; + priv->wpa_ie_len = 0; + priv->wpa_ie = NULL; + + /* Make the hardware available, as long as it hasn't been + * removed elsewhere (e.g. by PCMCIA hot unplug) */ + spin_lock_irq(&priv->lock); + priv->hw_unavailable--; + spin_unlock_irq(&priv->lock); + + printk(KERN_DEBUG "%s: ready\n", dev->name); + + out: + return err; +} + +struct net_device +*alloc_orinocodev(int sizeof_card, + struct device *device, + int (*hard_reset)(struct orinoco_private *), + int (*stop_fw)(struct orinoco_private *, int)) +{ + struct net_device *dev; + struct orinoco_private *priv; + + dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); + if (! dev) + return NULL; + priv = netdev_priv(dev); + priv->ndev = dev; + if (sizeof_card) + priv->card = (void *)((unsigned long)priv + + sizeof(struct orinoco_private)); + else + priv->card = NULL; + priv->dev = device; + + /* Setup / override net_device fields */ + dev->init = orinoco_init; + dev->hard_start_xmit = orinoco_xmit; + dev->tx_timeout = orinoco_tx_timeout; + dev->watchdog_timeo = HZ; /* 1 second timeout */ + dev->get_stats = orinoco_get_stats; + dev->ethtool_ops = &orinoco_ethtool_ops; + dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def; +#ifdef WIRELESS_SPY + priv->wireless_data.spy_data = &priv->spy_data; + dev->wireless_data = &priv->wireless_data; +#endif + dev->change_mtu = orinoco_change_mtu; + dev->set_multicast_list = orinoco_set_multicast_list; + /* we use the default eth_mac_addr for setting the MAC addr */ + + /* Reserve space in skb for the SNAP header */ + dev->hard_header_len += ENCAPS_OVERHEAD; + + /* Set up default callbacks */ + dev->open = orinoco_open; + dev->stop = orinoco_stop; + priv->hard_reset = hard_reset; + priv->stop_fw = stop_fw; + + spin_lock_init(&priv->lock); + priv->open = 0; + priv->hw_unavailable = 1; /* orinoco_init() must clear this + * before anything else touches the + * hardware */ + INIT_WORK(&priv->reset_work, orinoco_reset); + INIT_WORK(&priv->join_work, orinoco_join_ap); + INIT_WORK(&priv->wevent_work, orinoco_send_wevents); + + INIT_LIST_HEAD(&priv->rx_list); + tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, + (unsigned long) dev); + + netif_carrier_off(dev); + priv->last_linkstatus = 0xffff; + + priv->cached_fw = NULL; + + return dev; +} + +void free_orinocodev(struct net_device *dev) +{ + struct orinoco_private *priv = netdev_priv(dev); + + /* No need to empty priv->rx_list: if the tasklet is scheduled + * when we call tasklet_kill it will run one final time, + * emptying the list */ + tasklet_kill(&priv->rx_tasklet); + if (priv->cached_fw) + release_firmware(priv->cached_fw); + priv->cached_fw = NULL; + priv->wpa_ie_len = 0; + kfree(priv->wpa_ie); + orinoco_mic_free(priv); + orinoco_bss_data_free(priv); + free_netdev(dev); +} + +/********************************************************************/ +/* Wireless extensions */ +/********************************************************************/ + +/* Return : < 0 -> error code ; >= 0 -> length */ +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + struct hermes_idstring essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWNSSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + u16 rid; + + *active = 1; + + rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : + HERMES_RID_CNFDESIREDSSID; + + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; + } + + len = le16_to_cpu(essidbuf.len); + BUG_ON(len > IW_ESSID_MAX_SIZE); + + memset(buf, 0, IW_ESSID_MAX_SIZE); + memcpy(buf, p, len); + err = len; + + fail_unlock: + orinoco_unlock(priv, &flags); + + return err; +} + +static long orinoco_hw_get_freq(struct orinoco_private *priv) +{ + + hermes_t *hw = &priv->hw; + int err = 0; + u16 channel; + long freq = 0; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); + if (err) + goto out; + + /* Intersil firmware 1.3.5 returns 0 when the interface is down */ + if (channel == 0) { + err = -EBUSY; + goto out; + } + + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", + priv->ndev->name, channel); + err = -EBUSY; + goto out; + + } + freq = channel_frequency[channel-1] * 100000; + + out: + orinoco_unlock(priv, &flags); + + if (err > 0) + err = -EBUSY; + return err ? err : freq; +} + +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, + int *numrates, s32 *rates, int max) +{ + hermes_t *hw = &priv->hw; + struct hermes_idstring list; + unsigned char *p = (unsigned char *)&list.val; + int err = 0; + int num; + int i; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, + sizeof(list), NULL, &list); + orinoco_unlock(priv, &flags); + + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = min(num, max); + + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ + } + + return 0; +} + +static int orinoco_ioctl_getname(struct net_device *dev, + struct iw_request_info *info, + char *name, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int numrates; + int err; + + err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0); + + if (!err && (numrates > 2)) + strcpy(name, "IEEE 802.11b"); + else + strcpy(name, "IEEE 802.11-DS"); + + return 0; +} + +static int orinoco_ioctl_setwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = -EINPROGRESS; /* Call commit handler */ + unsigned long flags; + static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Enable automatic roaming - no sanity checks are needed */ + if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 || + memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) { + priv->bssid_fixed = 0; + memset(priv->desired_bssid, 0, ETH_ALEN); + + /* "off" means keep existing connection */ + if (ap_addr->sa_data[0] == 0) { + __orinoco_hw_set_wap(priv); + err = 0; + } + goto out; + } + + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { + printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " + "support manual roaming\n", + dev->name); + err = -EOPNOTSUPP; + goto out; + } + + if (priv->iw_mode != IW_MODE_INFRA) { + printk(KERN_WARNING "%s: Manual roaming supported only in " + "managed mode\n", dev->name); + err = -EOPNOTSUPP; + goto out; + } + + /* Intersil firmware hangs without Desired ESSID */ + if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && + strlen(priv->desired_essid) == 0) { + printk(KERN_WARNING "%s: Desired ESSID must be set for " + "manual roaming\n", dev->name); + err = -EOPNOTSUPP; + goto out; + } + + /* Finally, enable manual roaming */ + priv->bssid_fixed = 1; + memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); + + out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_getwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + + hermes_t *hw = &priv->hw; + int err = 0; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + ap_addr->sa_family = ARPHRD_ETHER; + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, + ETH_ALEN, NULL, ap_addr->sa_data); + + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_setmode(struct net_device *dev, + struct iw_request_info *info, + u32 *mode, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = -EINPROGRESS; /* Call commit handler */ + unsigned long flags; + + if (priv->iw_mode == *mode) + return 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (*mode) { + case IW_MODE_ADHOC: + if (!priv->has_ibss && !priv->has_port3) + err = -EOPNOTSUPP; + break; + + case IW_MODE_INFRA: + break; + + case IW_MODE_MONITOR: + if (priv->broken_monitor && !force_monitor) { + printk(KERN_WARNING "%s: Monitor mode support is " + "buggy in this firmware, not enabling\n", + dev->name); + err = -EOPNOTSUPP; + } + break; + + default: + err = -EOPNOTSUPP; + break; + } + + if (err == -EINPROGRESS) { + priv->iw_mode = *mode; + set_port_type(priv); + } + + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_getmode(struct net_device *dev, + struct iw_request_info *info, + u32 *mode, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + + *mode = priv->iw_mode; + return 0; +} + +static int orinoco_ioctl_getiwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *rrq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = 0; + struct iw_range *range = (struct iw_range *) extra; + int numrates; + int i, k; + + rrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 22; + + /* Set available channels/frequencies */ + range->num_channels = NUM_CHANNELS; + k = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + range->freq[k].i = i + 1; + range->freq[k].m = channel_frequency[i] * 100000; + range->freq[k].e = 1; + k++; + } + + if (k >= IW_MAX_FREQUENCIES) + break; + } + range->num_frequency = k; + range->sensitivity = 3; + + if (priv->has_wep) { + range->max_encoding_tokens = ORINOCO_MAX_KEYS; + range->encoding_size[0] = SMALL_KEY_SIZE; + range->num_encoding_sizes = 1; + + if (priv->has_big_wep) { + range->encoding_size[1] = LARGE_KEY_SIZE; + range->num_encoding_sizes = 2; + } + } + + if (priv->has_wpa) + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; + + if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ + /* Quality stats meaningless in ad-hoc mode */ + } else { + range->max_qual.qual = 0x8b - 0x2f; + range->max_qual.level = 0x2f - 0x95 - 1; + range->max_qual.noise = 0x2f - 0x95 - 1; + /* Need to get better values */ + range->avg_qual.qual = 0x24; + range->avg_qual.level = 0xC2; + range->avg_qual.noise = 0x9E; + } + + err = orinoco_hw_get_bitratelist(priv, &numrates, + range->bitrate, IW_MAX_BITRATES); + if (err) + return err; + range->num_bitrates = numrates; + + /* Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface. May be use for QoS stuff... + * Jean II */ + if (numrates > 2) + range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ + else + range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->min_pmp = 0; + range->max_pmp = 65535000; + range->min_pmt = 0; + range->max_pmt = 65535 * 1000; /* ??? */ + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; + + range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = IW_RETRY_LIFETIME; + range->min_retry = 0; + range->max_retry = 65535; /* ??? */ + range->min_r_time = 0; + range->max_r_time = 65535 * 1000; /* ??? */ + + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) + range->scan_capa = IW_SCAN_CAPA_ESSID; + else + range->scan_capa = IW_SCAN_CAPA_NONE; + + /* Event capability (kernel) */ + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + /* Event capability (driver) */ + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); + + return 0; +} + +static int orinoco_ioctl_setiwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, + char *keybuf) +{ + struct orinoco_private *priv = netdev_priv(dev); + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + int setindex = priv->tx_key; + int encode_alg = priv->encode_alg; + int restricted = priv->wep_restrict; + u16 xlen = 0; + int err = -EINPROGRESS; /* Call commit handler */ + unsigned long flags; + + if (! priv->has_wep) + return -EOPNOTSUPP; + + if (erq->pointer) { + /* We actually have a key to set - check its length */ + if (erq->length > LARGE_KEY_SIZE) + return -E2BIG; + + if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) + return -E2BIG; + } + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Clear any TKIP key we have */ + if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) + (void) orinoco_clear_tkip_key(priv, setindex); + + if (erq->length > 0) { + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) + index = priv->tx_key; + + /* Adjust key length to a supported value */ + if (erq->length > SMALL_KEY_SIZE) { + xlen = LARGE_KEY_SIZE; + } else if (erq->length > 0) { + xlen = SMALL_KEY_SIZE; + } else + xlen = 0; + + /* Switch on WEP if off */ + if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { + setindex = index; + encode_alg = IW_ENCODE_ALG_WEP; + } + } else { + /* Important note : if the user do "iwconfig eth0 enc off", + * we will arrive there with an index of -1. This is valid + * but need to be taken care off... Jean II */ + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { + if((index != -1) || (erq->flags == 0)) { + err = -EINVAL; + goto out; + } + } else { + /* Set the index : Check that the key is valid */ + if(priv->keys[index].len == 0) { + err = -EINVAL; + goto out; + } + setindex = index; + } + } + + if (erq->flags & IW_ENCODE_DISABLED) + encode_alg = IW_ENCODE_ALG_NONE; + if (erq->flags & IW_ENCODE_OPEN) + restricted = 0; + if (erq->flags & IW_ENCODE_RESTRICTED) + restricted = 1; + + if (erq->pointer && erq->length > 0) { + priv->keys[index].len = cpu_to_le16(xlen); + memset(priv->keys[index].data, 0, + sizeof(priv->keys[index].data)); + memcpy(priv->keys[index].data, keybuf, erq->length); + } + priv->tx_key = setindex; + + /* Try fast key change if connected and only keys are changed */ + if ((priv->encode_alg == encode_alg) && + (priv->wep_restrict == restricted) && + netif_carrier_ok(dev)) { + err = __orinoco_hw_setup_wepkeys(priv); + /* No need to commit if successful */ + goto out; + } + + priv->encode_alg = encode_alg; + priv->wep_restrict = restricted; + + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_getiwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, + char *keybuf) +{ + struct orinoco_private *priv = netdev_priv(dev); + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + u16 xlen = 0; + unsigned long flags; + + if (! priv->has_wep) + return -EOPNOTSUPP; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) + index = priv->tx_key; + + erq->flags = 0; + if (!priv->encode_alg) + erq->flags |= IW_ENCODE_DISABLED; + erq->flags |= index + 1; + + if (priv->wep_restrict) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; + + xlen = le16_to_cpu(priv->keys[index].len); + + erq->length = xlen; + + memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); + + orinoco_unlock(priv, &flags); + return 0; +} + +static int orinoco_ioctl_setessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, + char *essidbuf) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it + * anyway... - Jean II */ + + /* Hum... Should not use Wireless Extension constant (may change), + * should use our own... - Jean II */ + if (erq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ + memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); + + /* If not ANY, get the new ESSID */ + if (erq->flags) { + memcpy(priv->desired_essid, essidbuf, erq->length); + } + + orinoco_unlock(priv, &flags); + + return -EINPROGRESS; /* Call commit handler */ +} + +static int orinoco_ioctl_getessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, + char *essidbuf) +{ + struct orinoco_private *priv = netdev_priv(dev); + int active; + int err = 0; + unsigned long flags; + + if (netif_running(dev)) { + err = orinoco_hw_get_essid(priv, &active, essidbuf); + if (err < 0) + return err; + erq->length = err; + } else { + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); + erq->length = strlen(priv->desired_essid); + orinoco_unlock(priv, &flags); + } + + erq->flags = 1; + + return 0; +} + +static int orinoco_ioctl_setnick(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *nrq, + char *nickbuf) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + if (nrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + memset(priv->nick, 0, sizeof(priv->nick)); + memcpy(priv->nick, nickbuf, nrq->length); + + orinoco_unlock(priv, &flags); + + return -EINPROGRESS; /* Call commit handler */ +} + +static int orinoco_ioctl_getnick(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *nrq, + char *nickbuf) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE); + orinoco_unlock(priv, &flags); + + nrq->length = strlen(priv->nick); + + return 0; +} + +static int orinoco_ioctl_setfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *frq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int chan = -1; + unsigned long flags; + int err = -EINPROGRESS; /* Call commit handler */ + + /* In infrastructure mode the AP sets the channel */ + if (priv->iw_mode == IW_MODE_INFRA) + return -EBUSY; + + if ( (frq->e == 0) && (frq->m <= 1000) ) { + /* Setting by channel number */ + chan = frq->m; + } else { + /* Setting by frequency - search the table */ + int mult = 1; + int i; + + for (i = 0; i < (6 - frq->e); i++) + mult *= 10; + + for (i = 0; i < NUM_CHANNELS; i++) + if (frq->m == (channel_frequency[i] * mult)) + chan = i+1; + } + + if ( (chan < 1) || (chan > NUM_CHANNELS) || + ! (priv->channel_mask & (1 << (chan-1)) ) ) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + priv->channel = chan; + if (priv->iw_mode == IW_MODE_MONITOR) { + /* Fast channel change - no commit if successful */ + hermes_t *hw = &priv->hw; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_SET_CHANNEL, + chan, NULL); + } + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_getfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *frq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int tmp; + + /* Locking done in there */ + tmp = orinoco_hw_get_freq(priv); + if (tmp < 0) { + return tmp; + } + + frq->m = tmp; + frq->e = 1; + + return 0; +} + +static int orinoco_ioctl_getsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *srq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + u16 val; + int err; + unsigned long flags; + + if (!priv->has_sensitivity) + return -EOPNOTSUPP; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, &val); + orinoco_unlock(priv, &flags); + + if (err) + return err; + + srq->value = val; + srq->fixed = 0; /* auto */ + + return 0; +} + +static int orinoco_ioctl_setsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *srq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int val = srq->value; + unsigned long flags; + + if (!priv->has_sensitivity) + return -EOPNOTSUPP; + + if ((val < 1) || (val > 3)) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + priv->ap_density = val; + orinoco_unlock(priv, &flags); + + return -EINPROGRESS; /* Call commit handler */ +} + +static int orinoco_ioctl_setrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int val = rrq->value; + unsigned long flags; + + if (rrq->disabled) + val = 2347; + + if ( (val < 0) || (val > 2347) ) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + priv->rts_thresh = val; + orinoco_unlock(priv, &flags); + + return -EINPROGRESS; /* Call commit handler */ +} + +static int orinoco_ioctl_getrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + + rrq->value = priv->rts_thresh; + rrq->disabled = (rrq->value == 2347); + rrq->fixed = 1; + + return 0; +} + +static int orinoco_ioctl_setfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = -EINPROGRESS; /* Call commit handler */ + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (priv->has_mwo) { + if (frq->disabled) + priv->mwo_robust = 0; + else { + if (frq->fixed) + printk(KERN_WARNING "%s: Fixed fragmentation is " + "not supported on this firmware. " + "Using MWO robust instead.\n", dev->name); + priv->mwo_robust = 1; + } + } else { + if (frq->disabled) + priv->frag_thresh = 2346; + else { + if ( (frq->value < 256) || (frq->value > 2346) ) + err = -EINVAL; + else + priv->frag_thresh = frq->value & ~0x1; /* must be even */ + } + } + + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_getfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err; + u16 val; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (priv->has_mwo) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + &val); + if (err) + val = 0; + + frq->value = val ? 2347 : 0; + frq->disabled = ! val; + frq->fixed = 0; + } else { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + &val); + if (err) + val = 0; + + frq->value = val; + frq->disabled = (val >= 2346); + frq->fixed = 1; + } + + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_setrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int ratemode = -1; + int bitrate; /* 100s of kilobits */ + int i; + unsigned long flags; + + /* As the user space doesn't know our highest rate, it uses -1 + * to ask us to set the highest rate. Test it using "iwconfig + * ethX rate auto" - Jean II */ + if (rrq->value == -1) + bitrate = 110; + else { + if (rrq->value % 100000) + return -EINVAL; + bitrate = rrq->value / 100000; + } + + if ( (bitrate != 10) && (bitrate != 20) && + (bitrate != 55) && (bitrate != 110) ) + return -EINVAL; + + for (i = 0; i < BITRATE_TABLE_SIZE; i++) + if ( (bitrate_table[i].bitrate == bitrate) && + (bitrate_table[i].automatic == ! rrq->fixed) ) { + ratemode = i; + break; + } + + if (ratemode == -1) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + priv->bitratemode = ratemode; + orinoco_unlock(priv, &flags); + + return -EINPROGRESS; +} + +static int orinoco_ioctl_getrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + int ratemode; + int i; + u16 val; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + ratemode = priv->bitratemode; + + BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); + + rrq->value = bitrate_table[ratemode].bitrate * 100000; + rrq->fixed = ! bitrate_table[ratemode].automatic; + rrq->disabled = 0; + + /* If the interface is running we try to find more about the + current mode */ + if (netif_running(dev)) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CURRENTTXRATE, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ + /* Note : in Lucent firmware, the return value of + * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, + * and therefore is totally different from the + * encoding of HERMES_RID_CNFTXRATECONTROL. + * Don't forget that 6Mb/s is really 5.5Mb/s */ + if (val == 6) + rrq->value = 5500000; + else + rrq->value = val * 1000000; + break; + case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + for (i = 0; i < BITRATE_TABLE_SIZE; i++) + if (bitrate_table[i].intersil_txratectrl == val) { + ratemode = i; + break; + } + if (i >= BITRATE_TABLE_SIZE) + printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", + dev->name, val); + + rrq->value = bitrate_table[ratemode].bitrate * 100000; + break; + default: + BUG(); + } + } + + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_setpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *prq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = -EINPROGRESS; /* Call commit handler */ + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (prq->disabled) { + priv->pm_on = 0; + } else { + switch (prq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + priv->pm_mcast = 0; + priv->pm_on = 1; + break; + case IW_POWER_ALL_R: + priv->pm_mcast = 1; + priv->pm_on = 1; + break; + case IW_POWER_ON: + /* No flags : but we may have a value - Jean II */ + break; + default: + err = -EINVAL; + goto out; + } + + if (prq->flags & IW_POWER_TIMEOUT) { + priv->pm_on = 1; + priv->pm_timeout = prq->value / 1000; + } + if (prq->flags & IW_POWER_PERIOD) { + priv->pm_on = 1; + priv->pm_period = prq->value / 1000; + } + /* It's valid to not have a value if we are just toggling + * the flags... Jean II */ + if(!priv->pm_on) { + err = -EINVAL; + goto out; + } + } + + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_getpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *prq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + u16 enable, period, timeout, mcast; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, &period); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast); + if (err) + goto out; + + prq->disabled = !enable; + /* Note : by default, display the period */ + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + prq->flags = IW_POWER_TIMEOUT; + prq->value = timeout * 1000; + } else { + prq->flags = IW_POWER_PERIOD; + prq->value = period * 1000; + } + if (mcast) + prq->flags |= IW_POWER_ALL_R; + else + prq->flags |= IW_POWER_UNICAST_R; + + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, alg = ext->alg, set_key = 1; + unsigned long flags; + int err = -EINVAL; + u16 key_len; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Determine and validate the key index */ + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if ((idx < 1) || (idx > 4)) + goto out; + idx--; + } else + idx = priv->tx_key; + + if (encoding->flags & IW_ENCODE_DISABLED) + alg = IW_ENCODE_ALG_NONE; + + if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { + /* Clear any TKIP TX key we had */ + (void) orinoco_clear_tkip_key(priv, priv->tx_key); + } + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + priv->tx_key = idx; + set_key = ((alg == IW_ENCODE_ALG_TKIP) || + (ext->key_len > 0)) ? 1 : 0; + } + + if (set_key) { + /* Set the requested key first */ + switch (alg) { + case IW_ENCODE_ALG_NONE: + priv->encode_alg = alg; + priv->keys[idx].len = 0; + break; + + case IW_ENCODE_ALG_WEP: + if (ext->key_len > SMALL_KEY_SIZE) + key_len = LARGE_KEY_SIZE; + else if (ext->key_len > 0) + key_len = SMALL_KEY_SIZE; + else + goto out; + + priv->encode_alg = alg; + priv->keys[idx].len = cpu_to_le16(key_len); + + key_len = min(ext->key_len, key_len); + + memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); + memcpy(priv->keys[idx].data, ext->key, key_len); + break; + + case IW_ENCODE_ALG_TKIP: + { + hermes_t *hw = &priv->hw; + u8 *tkip_iv = NULL; + + if (!priv->has_wpa || + (ext->key_len > sizeof(priv->tkip_key[0]))) + goto out; + + priv->encode_alg = alg; + memset(&priv->tkip_key[idx], 0, + sizeof(priv->tkip_key[idx])); + memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); + + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) + tkip_iv = &ext->rx_seq[0]; + + err = __orinoco_hw_set_tkip_key(hw, idx, + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, + (u8 *) &priv->tkip_key[idx], + tkip_iv, NULL); + if (err) + printk(KERN_ERR "%s: Error %d setting TKIP key" + "\n", dev->name, err); + + goto out; + } + default: + goto out; + } + } + err = -EINPROGRESS; + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, max_key_len; + unsigned long flags; + int err; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = -EINVAL; + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if ((idx < 1) || (idx > 4)) + goto out; + idx--; + } else + idx = priv->tx_key; + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + ext->alg = priv->encode_alg; + switch (priv->encode_alg) { + case IW_ENCODE_ALG_NONE: + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + break; + case IW_ENCODE_ALG_WEP: + ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), + max_key_len); + memcpy(ext->key, priv->keys[idx].data, ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + break; + case IW_ENCODE_ALG_TKIP: + ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), + max_key_len); + memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + break; + } + + err = 0; + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_param *param = &wrqu->param; + unsigned long flags; + int ret = -EINPROGRESS; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_PRIVACY_INVOKED: + case IW_AUTH_DROP_UNENCRYPTED: + /* + * orinoco does not use these parameters + */ + break; + + case IW_AUTH_KEY_MGMT: + /* wl_lkm implies value 2 == PSK for Hermes I + * which ties in with WEXT + * no other hints tho :( + */ + priv->key_mgmt = param->value; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + /* When countermeasures are enabled, shut down the + * card; when disabled, re-enable the card. This must + * take effect immediately. + * + * TODO: Make sure that the EAPOL message is getting + * out before card disabled + */ + if (param->value) { + priv->tkip_cm_active = 1; + ret = hermes_enable_port(hw, 0); + } else { + priv->tkip_cm_active = 0; + ret = hermes_disable_port(hw, 0); + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (param->value & IW_AUTH_ALG_SHARED_KEY) + priv->wep_restrict = 1; + else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) + priv->wep_restrict = 0; + else + ret = -EINVAL; + break; + + case IW_AUTH_WPA_ENABLED: + if (priv->has_wpa) { + priv->wpa_enabled = param->value ? 1 : 0; + } else { + if (param->value) + ret = -EOPNOTSUPP; + /* else silently accept disable of WPA */ + priv->wpa_enabled = 0; + } + break; + + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_param *param = &wrqu->param; + unsigned long flags; + int ret = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + param->value = priv->key_mgmt; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + param->value = priv->tkip_cm_active; + break; + + case IW_AUTH_80211_AUTH_ALG: + if (priv->wep_restrict) + param->value = IW_AUTH_ALG_SHARED_KEY; + else + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = priv->wpa_enabled; + break; + + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + u8 *buf; + unsigned long flags; + int err = 0; + + /* cut off at IEEE80211_MAX_DATA_LEN */ + if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || + (wrqu->data.length && (extra == NULL))) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (wrqu->data.length) { + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto out; + } + + memcpy(buf, extra, wrqu->data.length); + kfree(priv->wpa_ie); + priv->wpa_ie = buf; + priv->wpa_ie_len = wrqu->data.length; + } else { + kfree(priv->wpa_ie); + priv->wpa_ie = NULL; + priv->wpa_ie_len = 0; + } + + if (priv->wpa_ie) { + /* Looks like wl_lkm wants to check the auth alg, and + * somehow pass it to the firmware. + * Instead it just calls the key mgmt rid + * - we do this in set auth. + */ + } + +out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { + wrqu->data.length = 0; + goto out; + } + + if (wrqu->data.length < priv->wpa_ie_len) { + err = -E2BIG; + goto out; + } + + wrqu->data.length = priv->wpa_ie_len; + memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); + +out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + unsigned long flags; + int ret = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + /* silently ignore */ + break; + + case IW_MLME_DISASSOC: + { + struct { + u8 addr[ETH_ALEN]; + __le16 reason_code; + } __attribute__ ((packed)) buf; + + memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); + buf.reason_code = cpu_to_le16(mlme->reason_code); + ret = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFDISASSOCIATE, + &buf); + break; + } + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_getretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int err = 0; + u16 short_limit, long_limit, lifetime; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, + &short_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, + &long_limit); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, + &lifetime); + if (err) + goto out; + + rrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the retry number */ + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1000; /* ??? */ + } else { + /* By default, display the min number */ + if ((rrq->flags & IW_RETRY_LONG)) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + rrq->value = long_limit; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = short_limit; + if(short_limit != long_limit) + rrq->flags |= IW_RETRY_SHORT; + } + } + + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_reset(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + + if (! capable(CAP_NET_ADMIN)) + return -EPERM; + + if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); + + /* Firmware reset */ + orinoco_reset(&priv->reset_work); + } else { + printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); + + schedule_work(&priv->reset_work); + } + + return 0; +} + +static int orinoco_ioctl_setibssport(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) + +{ + struct orinoco_private *priv = netdev_priv(dev); + int val = *( (int *) extra ); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + priv->ibss_port = val ; + + /* Actually update the mode we are using */ + set_port_type(priv); + + orinoco_unlock(priv, &flags); + return -EINPROGRESS; /* Call commit handler */ +} + +static int orinoco_ioctl_getibssport(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int *val = (int *) extra; + + *val = priv->ibss_port; + return 0; +} + +static int orinoco_ioctl_setport3(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int val = *( (int *) extra ); + int err = 0; + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (val) { + case 0: /* Try to do IEEE ad-hoc mode */ + if (! priv->has_ibss) { + err = -EINVAL; + break; + } + priv->prefer_port3 = 0; + + break; + + case 1: /* Try to do Lucent proprietary ad-hoc mode */ + if (! priv->has_port3) { + err = -EINVAL; + break; + } + priv->prefer_port3 = 1; + break; + + default: + err = -EINVAL; + } + + if (! err) { + /* Actually update the mode we are using */ + set_port_type(priv); + err = -EINPROGRESS; + } + + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_getport3(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int *val = (int *) extra; + + *val = priv->prefer_port3; + return 0; +} + +static int orinoco_ioctl_setpreamble(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int val; + + if (! priv->has_preamble) + return -EOPNOTSUPP; + + /* 802.11b has recently defined some short preamble. + * Basically, the Phy header has been reduced in size. + * This increase performance, especially at high rates + * (the preamble is transmitted at 1Mb/s), unfortunately + * this give compatibility troubles... - Jean II */ + val = *( (int *) extra ); + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (val) + priv->preamble = 1; + else + priv->preamble = 0; + + orinoco_unlock(priv, &flags); + + return -EINPROGRESS; /* Call commit handler */ +} + +static int orinoco_ioctl_getpreamble(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int *val = (int *) extra; + + if (! priv->has_preamble) + return -EOPNOTSUPP; + + *val = priv->preamble; + return 0; +} + +/* ioctl interface to hermes_read_ltv() + * To use with iwpriv, pass the RID as the token argument, e.g. + * iwpriv get_rid [0xfc00] + * At least Wireless Tools 25 is required to use iwpriv. + * For Wireless Tools 25 and 26 append "dummy" are the end. */ +static int orinoco_ioctl_getrid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + int rid = data->flags; + u16 length; + int err; + unsigned long flags; + + /* It's a "get" function, but we don't want users to access the + * WEP key and other raw firmware data */ + if (! capable(CAP_NET_ADMIN)) + return -EPERM; + + if (rid < 0xfc00 || rid > 0xffff) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, + extra); + if (err) + goto out; + + data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), + MAX_RID_LEN); + + out: + orinoco_unlock(priv, &flags); + return err; +} + +/* Trigger a scan (look for other cells in the vicinity) */ +static int orinoco_ioctl_setscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *srq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_scan_req *si = (struct iw_scan_req *) extra; + int err = 0; + unsigned long flags; + + /* Note : you may have realised that, as this is a SET operation, + * this is privileged and therefore a normal user can't + * perform scanning. + * This is not an error, while the device perform scanning, + * traffic doesn't flow, so it's a perfect DoS... + * Jean II */ + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Scanning with port 0 disabled would fail */ + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + /* In monitor mode, the scan results are always empty. + * Probe responses are passed to the driver as received + * frames and could be processed in software. */ + if (priv->iw_mode == IW_MODE_MONITOR) { + err = -EOPNOTSUPP; + goto out; + } + + /* Note : because we don't lock out the irq handler, the way + * we access scan variables in priv is critical. + * o scan_inprogress : not touched by irq handler + * o scan_mode : not touched by irq handler + * Before modifying anything on those variables, please think hard ! + * Jean II */ + + /* Save flags */ + priv->scan_mode = srq->flags; + + /* Always trigger scanning, even if it's in progress. + * This way, if the info frame get lost, we will recover somewhat + * gracefully - Jean II */ + + if (priv->has_hostscan) { + switch (priv->firmware_type) { + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFHOSTSCAN_SYMBOL, + HERMES_HOSTSCAN_SYMBOL_ONCE | + HERMES_HOSTSCAN_SYMBOL_BCAST); + break; + case FIRMWARE_TYPE_INTERSIL: { + __le16 req[3]; + + req[0] = cpu_to_le16(0x3fff); /* All channels */ + req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ + req[2] = 0; /* Any ESSID */ + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFHOSTSCAN, &req); + } + break; + case FIRMWARE_TYPE_AGERE: + if (priv->scan_mode & IW_SCAN_THIS_ESSID) { + struct hermes_idstring idbuf; + size_t len = min(sizeof(idbuf.val), + (size_t) si->essid_len); + idbuf.len = cpu_to_le16(len); + memcpy(idbuf.val, si->essid, len); + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + HERMES_BYTES_TO_RECLEN(len + 2), + &idbuf); + } else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + 0); /* Any ESSID */ + if (err) + break; + + if (priv->has_ext_scan) { + /* Clear scan results at the start of + * an extended scan */ + orinoco_clear_scan_results(priv, + msecs_to_jiffies(15000)); + + /* TODO: Is this available on older firmware? + * Can we use it to scan specific channels + * for IW_SCAN_THIS_FREQ? */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANCHANNELS2GHZ, + 0x7FFF); + if (err) + goto out; + + err = hermes_inquire(hw, + HERMES_INQ_CHANNELINFO); + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); + break; + } + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); + + /* One more client */ + if (! err) + priv->scan_inprogress = 1; + + out: + orinoco_unlock(priv, &flags); + return err; +} + +#define MAX_CUSTOM_LEN 64 + +/* Translate scan data returned from the card to a card independant + * format that the Wireless Tools will understand - Jean II */ +static inline char *orinoco_translate_scan(struct net_device *dev, + struct iw_request_info *info, + char *current_ev, + char *end_buf, + union hermes_scan_info *bss, + unsigned int last_scanned) +{ + struct orinoco_private *priv = netdev_priv(dev); + u16 capabilities; + u16 channel; + struct iw_event iwe; /* Temporary buffer */ + char custom[MAX_CUSTOM_LEN]; + + memset(&iwe, 0, sizeof(iwe)); + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + /* Add the ESSID */ + iwe.u.data.length = le16_to_cpu(bss->a.essid_len); + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, bss->a.essid); + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + capabilities = le16_to_cpu(bss->a.capabilities); + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (capabilities & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); + } + + channel = bss->s.channel; + if ((channel >= 1) && (channel <= NUM_CHANNELS)) { + /* Add channel and frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + + iwe.u.freq.m = channel_frequency[channel-1] * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + } + + /* Add quality statistics. level and noise in dB. No link quality */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; + iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; + iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; + /* Wireless tools prior to 27.pre22 will show link quality + * anyway, so we provide a reasonable value. */ + if (iwe.u.qual.level > iwe.u.qual.noise) + iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; + else + iwe.u.qual.qual = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (capabilities & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, NULL); + + /* Bit rate is not available in Lucent/Agere firmwares */ + if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { + char *current_val = current_ev + iwe_stream_lcp_len(info); + int i; + int step; + + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) + step = 2; + else + step = 1; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + /* Max 10 values */ + for (i = 0; i < 10; i += step) { + /* NULL terminated */ + if (bss->p.rates[i] == 0x0) + break; + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = + ((bss->p.rates[i] & 0x7f) * 500000); + current_val = iwe_stream_add_value(info, current_ev, + current_val, + end_buf, &iwe, + IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if ((current_val - current_ev) > iwe_stream_lcp_len(info)) + current_ev = current_val; + } + + /* Beacon interval */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "bcn_int=%d", + le16_to_cpu(bss->a.beacon_interv)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Capabilites */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "capab=0x%04x", + capabilities); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + return current_ev; +} + +static inline char *orinoco_translate_ext_scan(struct net_device *dev, + struct iw_request_info *info, + char *current_ev, + char *end_buf, + struct agere_ext_scan_info *bss, + unsigned int last_scanned) +{ + u16 capabilities; + u16 channel; + struct iw_event iwe; /* Temporary buffer */ + char custom[MAX_CUSTOM_LEN]; + u8 *ie; + + memset(&iwe, 0, sizeof(iwe)); + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + /* Add the ESSID */ + ie = bss->data; + iwe.u.data.length = ie[1]; + if (iwe.u.data.length) { + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, &ie[2]); + } + + /* Add mode */ + capabilities = le16_to_cpu(bss->capabilities); + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + iwe.cmd = SIOCGIWMODE; + if (capabilities & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); + } + + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); + channel = ie ? ie[2] : 0; + if ((channel >= 1) && (channel <= NUM_CHANNELS)) { + /* Add channel and frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + + iwe.u.freq.m = channel_frequency[channel-1] * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + } + + /* Add quality statistics. level and noise in dB. No link quality */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; + iwe.u.qual.level = bss->level - 0x95; + iwe.u.qual.noise = bss->noise - 0x95; + /* Wireless tools prior to 27.pre22 will show link quality + * anyway, so we provide a reasonable value. */ + if (iwe.u.qual.level > iwe.u.qual.noise) + iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; + else + iwe.u.qual.qual = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (capabilities & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, NULL); + + /* WPA IE */ + ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); + if (ie) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie[1] + 2; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie); + } + + /* RSN IE */ + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); + if (ie) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie[1] + 2; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie); + } + + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); + if (ie) { + char *p = current_ev + iwe_stream_lcp_len(info); + int i; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + for (i = 2; i < (ie[1] + 2); i++) { + iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); + p = iwe_stream_add_value(info, current_ev, p, end_buf, + &iwe, IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if (p > (current_ev + iwe_stream_lcp_len(info))) + current_ev = p; + } + + /* Timestamp */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = + snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", + (unsigned long long) le64_to_cpu(bss->timestamp)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Beacon interval */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "bcn_int=%d", + le16_to_cpu(bss->beacon_interval)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Capabilites */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "capab=0x%04x", + capabilities); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + return current_ev; +} + +/* Return results of a scan */ +static int orinoco_ioctl_getscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *srq, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + int err = 0; + unsigned long flags; + char *current_ev = extra; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (priv->scan_inprogress) { + /* Important note : we don't want to block the caller + * until results are ready for various reasons. + * First, managing wait queues is complex and racy. + * Second, we grab some rtnetlink lock before comming + * here (in dev_ioctl()). + * Third, we generate an Wireless Event, so the + * caller can wait itself on that - Jean II */ + err = -EAGAIN; + goto out; + } + + if (priv->has_ext_scan) { + struct xbss_element *bss; + + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate this entry to WE format */ + current_ev = + orinoco_translate_ext_scan(dev, info, + current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); + + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) + <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a + * bigger buffer */ + err = -E2BIG; + goto out; + } + } + + } else { + struct bss_element *bss; + + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate this entry to WE format */ + current_ev = orinoco_translate_scan(dev, info, + current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); + + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) + <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a + * bigger buffer */ + err = -E2BIG; + goto out; + } + } + } + + srq->length = (current_ev - extra); + srq->flags = (__u16) priv->scan_mode; + +out: + orinoco_unlock(priv, &flags); + return err; +} + +/* Commit handler, called after set operations */ +static int orinoco_ioctl_commit(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct hermes *hw = &priv->hw; + unsigned long flags; + int err = 0; + + if (!priv->open) + return 0; + + if (priv->broken_disableport) { + orinoco_reset(&priv->reset_work); + return 0; + } + + if (orinoco_lock(priv, &flags) != 0) + return err; + + err = hermes_disable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to disable port " + "while reconfiguring card\n", dev->name); + priv->broken_disableport = 1; + goto out; + } + + err = __orinoco_program_rids(dev); + if (err) { + printk(KERN_WARNING "%s: Unable to reconfigure card\n", + dev->name); + goto out; + } + + err = hermes_enable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + dev->name); + goto out; + } + + out: + if (err) { + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); + schedule_work(&priv->reset_work); + err = 0; + } + + orinoco_unlock(priv, &flags); + return err; +} + +static const struct iw_priv_args orinoco_privtab[] = { + { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, + { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, + { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" }, + { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_preamble" }, + { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_preamble" }, + { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_ibssport" }, + { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ibssport" }, + { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, + "get_rid" }, +}; + + +/* + * Structures to export the Wireless Handlers + */ + +#define STD_IW_HANDLER(id, func) \ + [IW_IOCTL_IDX(id)] = (iw_handler) func +static const iw_handler orinoco_handler[] = { + STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), + STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), + STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), + STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), + STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), + STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), + STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), + STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), + STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), + STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), + STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), + STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), + STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), + STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), + STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), + STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), + STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), + STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), + STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), + STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), + STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), + STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), + STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), + STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), + STD_IW_HANDLER(SIOCGIWRTS, orinoco_ioctl_getrts), + STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag), + STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag), + STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry), + STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), + STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), + STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), + STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), + STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), + STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), + STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), + STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), + STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), + STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), + STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), +}; + + +/* + Added typecasting since we no longer use iwreq_data -- Moustafa + */ +static const iw_handler orinoco_private_handler[] = { + [0] = (iw_handler) orinoco_ioctl_reset, + [1] = (iw_handler) orinoco_ioctl_reset, + [2] = (iw_handler) orinoco_ioctl_setport3, + [3] = (iw_handler) orinoco_ioctl_getport3, + [4] = (iw_handler) orinoco_ioctl_setpreamble, + [5] = (iw_handler) orinoco_ioctl_getpreamble, + [6] = (iw_handler) orinoco_ioctl_setibssport, + [7] = (iw_handler) orinoco_ioctl_getibssport, + [9] = (iw_handler) orinoco_ioctl_getrid, +}; + +static const struct iw_handler_def orinoco_handler_def = { + .num_standard = ARRAY_SIZE(orinoco_handler), + .num_private = ARRAY_SIZE(orinoco_private_handler), + .num_private_args = ARRAY_SIZE(orinoco_privtab), + .standard = orinoco_handler, + .private = orinoco_private_handler, + .private_args = orinoco_privtab, + .get_wireless_stats = orinoco_get_wireless_stats, +}; + +static void orinoco_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct orinoco_private *priv = netdev_priv(dev); + + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); + strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); + strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); + if (dev->dev.parent) + strncpy(info->bus_info, dev->dev.parent->bus_id, + sizeof(info->bus_info) - 1); + else + snprintf(info->bus_info, sizeof(info->bus_info) - 1, + "PCMCIA %p", priv->hw.iobase); +} + +static const struct ethtool_ops orinoco_ethtool_ops = { + .get_drvinfo = orinoco_get_drvinfo, + .get_link = ethtool_op_get_link, +}; + +/********************************************************************/ +/* Module initialization */ +/********************************************************************/ + +EXPORT_SYMBOL(alloc_orinocodev); +EXPORT_SYMBOL(free_orinocodev); + +EXPORT_SYMBOL(__orinoco_up); +EXPORT_SYMBOL(__orinoco_down); +EXPORT_SYMBOL(orinoco_reinit_firmware); + +EXPORT_SYMBOL(orinoco_interrupt); + +/* Can't be declared "const" or the whole __initdata section will + * become const */ +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (David Gibson , " + "Pavel Roskin , et al)"; + +static int __init init_orinoco(void) +{ + printk(KERN_DEBUG "%s\n", version); + return 0; +} + +static void __exit exit_orinoco(void) +{ +} + +module_init(init_orinoco); +module_exit(exit_orinoco); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h new file mode 100644 index 0000000..8c29538 --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -0,0 +1,218 @@ +/* orinoco.h + * + * Common definitions to all pieces of the various orinoco + * drivers + */ + +#ifndef _ORINOCO_H +#define _ORINOCO_H + +#define DRIVER_VERSION "0.15" + +#include +#include +#include +#include + +#include "hermes.h" + +/* To enable debug messages */ +//#define ORINOCO_DEBUG 3 + +#define WIRELESS_SPY // enable iwspy support + +#define MAX_SCAN_LEN 4096 + +#define ORINOCO_MAX_KEY_SIZE 14 +#define ORINOCO_MAX_KEYS 4 + +struct orinoco_key { + __le16 len; /* always stored as little-endian */ + char data[ORINOCO_MAX_KEY_SIZE]; +} __attribute__ ((packed)); + +#define TKIP_KEYLEN 16 +#define MIC_KEYLEN 8 + +struct orinoco_tkip_key { + u8 tkip[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; +}; + +typedef enum { + FIRMWARE_TYPE_AGERE, + FIRMWARE_TYPE_INTERSIL, + FIRMWARE_TYPE_SYMBOL +} fwtype_t; + +struct bss_element { + union hermes_scan_info bss; + unsigned long last_scanned; + struct list_head list; +}; + +struct xbss_element { + struct agere_ext_scan_info bss; + unsigned long last_scanned; + struct list_head list; +}; + +struct hermes_rx_descriptor; + +struct orinoco_rx_data { + struct hermes_rx_descriptor *desc; + struct sk_buff *skb; + struct list_head list; +}; + +struct firmware; + +struct orinoco_private { + void *card; /* Pointer to card dependent structure */ + struct device *dev; + int (*hard_reset)(struct orinoco_private *); + int (*stop_fw)(struct orinoco_private *, int); + + /* Synchronisation stuff */ + spinlock_t lock; + int hw_unavailable; + struct work_struct reset_work; + + /* Interrupt tasklets */ + struct tasklet_struct rx_tasklet; + struct list_head rx_list; + struct orinoco_rx_data *rx_data; + + /* driver state */ + int open; + u16 last_linkstatus; + struct work_struct join_work; + struct work_struct wevent_work; + + /* Net device stuff */ + struct net_device *ndev; + struct net_device_stats stats; + struct iw_statistics wstats; + + /* Hardware control variables */ + hermes_t hw; + u16 txfid; + + /* Capabilities of the hardware/firmware */ + fwtype_t firmware_type; + char fw_name[32]; + int ibss_port; + int nicbuf_size; + u16 channel_mask; + + /* Boolean capabilities */ + unsigned int has_ibss:1; + unsigned int has_port3:1; + unsigned int has_wep:1; + unsigned int has_big_wep:1; + unsigned int has_mwo:1; + unsigned int has_pm:1; + unsigned int has_preamble:1; + unsigned int has_sensitivity:1; + unsigned int has_hostscan:1; + unsigned int has_alt_txcntl:1; + unsigned int has_ext_scan:1; + unsigned int has_wpa:1; + unsigned int do_fw_download:1; + unsigned int broken_disableport:1; + unsigned int broken_monitor:1; + + /* Configuration paramaters */ + u32 iw_mode; + int prefer_port3; + u16 encode_alg, wep_restrict, tx_key; + struct orinoco_key keys[ORINOCO_MAX_KEYS]; + int bitratemode; + char nick[IW_ESSID_MAX_SIZE+1]; + char desired_essid[IW_ESSID_MAX_SIZE+1]; + char desired_bssid[ETH_ALEN]; + int bssid_fixed; + u16 frag_thresh, mwo_robust; + u16 channel; + u16 ap_density, rts_thresh; + u16 pm_on, pm_mcast, pm_period, pm_timeout; + u16 preamble; +#ifdef WIRELESS_SPY + struct iw_spy_data spy_data; /* iwspy support */ + struct iw_public_data wireless_data; +#endif + + /* Configuration dependent variables */ + int port_type, createibss; + int promiscuous, mc_count; + + /* Scanning support */ + struct list_head bss_list; + struct list_head bss_free_list; + void *bss_xbss_data; + + int scan_inprogress; /* Scan pending... */ + u32 scan_mode; /* Type of scan done */ + + /* WPA support */ + u8 *wpa_ie; + int wpa_ie_len; + + struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; + struct crypto_hash *rx_tfm_mic; + struct crypto_hash *tx_tfm_mic; + + unsigned int wpa_enabled:1; + unsigned int tkip_cm_active:1; + unsigned int key_mgmt:3; + + /* Cached in memory firmware to use in ->resume */ + const struct firmware *cached_fw; +}; + +#ifdef ORINOCO_DEBUG +extern int orinoco_debug; +#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0) +#else +#define DEBUG(n, args...) do { } while (0) +#endif /* ORINOCO_DEBUG */ + +/********************************************************************/ +/* Exported prototypes */ +/********************************************************************/ + +extern struct net_device *alloc_orinocodev( + int sizeof_card, struct device *device, + int (*hard_reset)(struct orinoco_private *), + int (*stop_fw)(struct orinoco_private *, int)); +extern void free_orinocodev(struct net_device *dev); +extern int __orinoco_up(struct net_device *dev); +extern int __orinoco_down(struct net_device *dev); +extern int orinoco_reinit_firmware(struct net_device *dev); +extern irqreturn_t orinoco_interrupt(int irq, void * dev_id); + +/********************************************************************/ +/* Locking and synchronization functions */ +/********************************************************************/ + +static inline int orinoco_lock(struct orinoco_private *priv, + unsigned long *flags) +{ + spin_lock_irqsave(&priv->lock, *flags); + if (priv->hw_unavailable) { + DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n", + priv->ndev); + spin_unlock_irqrestore(&priv->lock, *flags); + return -EBUSY; + } + return 0; +} + +static inline void orinoco_unlock(struct orinoco_private *priv, + unsigned long *flags) +{ + spin_unlock_irqrestore(&priv->lock, *flags); +} + +#endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c new file mode 100644 index 0000000..6fcf2bd --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -0,0 +1,533 @@ +/* orinoco_cs.c (formerly known as dldwd_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright notice & release notes in file orinoco.c + */ + +#define DRIVER_NAME "orinoco_cs" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "orinoco.h" + +/********************************************************************/ +/* Module stuff */ +/********************************************************************/ + +MODULE_AUTHOR("David Gibson "); +MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); +MODULE_LICENSE("Dual MPL/GPL"); + +/* Module parameters */ + +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but + * don't have any CIS entry for it. This workaround it... */ +static int ignore_cis_vcc; /* = 0 */ +module_param(ignore_cis_vcc, int, 0); +MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); + +/********************************************************************/ +/* Data structures */ +/********************************************************************/ + +/* PCMCIA specific device information (goes in the card field of + * struct orinoco_private */ +struct orinoco_pccard { + struct pcmcia_device *p_dev; + dev_node_t node; + + /* Used to handle hard reset */ + /* yuck, we need this hack to work around the insanity of the + * PCMCIA layer */ + unsigned long hard_reset_in_progress; +}; + + +/********************************************************************/ +/* Function prototypes */ +/********************************************************************/ + +static int orinoco_cs_config(struct pcmcia_device *link); +static void orinoco_cs_release(struct pcmcia_device *link); +static void orinoco_cs_detach(struct pcmcia_device *p_dev); + +/********************************************************************/ +/* Device methods */ +/********************************************************************/ + +static int +orinoco_cs_hard_reset(struct orinoco_private *priv) +{ + struct orinoco_pccard *card = priv->card; + struct pcmcia_device *link = card->p_dev; + int err; + + /* We need atomic ops here, because we're not holding the lock */ + set_bit(0, &card->hard_reset_in_progress); + + err = pcmcia_reset_card(link->socket); + if (err) + return err; + + msleep(100); + clear_bit(0, &card->hard_reset_in_progress); + + return 0; +} + +/********************************************************************/ +/* PCMCIA stuff */ +/********************************************************************/ + +/* + * This creates an "instance" of the driver, allocating local data + * structures for one device. The device is registered with Card + * Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a card + * insertion event. */ +static int +orinoco_cs_probe(struct pcmcia_device *link) +{ + struct net_device *dev; + struct orinoco_private *priv; + struct orinoco_pccard *card; + + dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + orinoco_cs_hard_reset, NULL); + if (! dev) + return -ENOMEM; + priv = netdev_priv(dev); + card = priv->card; + + /* Link both structures together */ + card->p_dev = link; + link->priv = dev; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Handler = orinoco_interrupt; + link->irq.Instance = dev; + + /* General socket configuration defaults can go here. In this + * client, we assume very little, and rely on the CIS for + * almost everything. In most clients, many details (i.e., + * number, sizes, and attributes of IO windows) are fixed by + * the nature of the device, and can be hard-wired here. */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + return orinoco_cs_config(link); +} /* orinoco_cs_attach */ + +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void orinoco_cs_detach(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + + if (link->dev_node) + unregister_netdev(dev); + + orinoco_cs_release(link); + + free_orinocodev(dev); +} /* orinoco_cs_detach */ + +/* + * orinoco_cs_config() is scheduled to run after a CARD_INSERTION + * event is received, to configure the PCMCIA socket, and to make the + * device available to the system. + */ + +#define CS_CHECK(fn, ret) do { \ + last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ + } while (0) + +static int orinoco_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + goto next_entry; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + goto next_entry; + } + return 0; + +next_entry: + pcmcia_disable_device(p_dev); + return -ENODEV; +}; + +static int +orinoco_cs_config(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pccard *card = priv->card; + hermes_t *hw = &priv->hw; + int last_fn, last_ret; + void __iomem *mem; + + /* + * In this loop, we scan the CIS for configuration table + * entries, each of which describes a valid card + * configuration, including voltage, IO window, memory window, + * and interrupt settings. + * + * We make no assumptions about the card to be configured: we + * use just the information available in the CIS. In an ideal + * world, this would work for any PCMCIA card, but it requires + * a complete and accurate CIS. In practice, a driver usually + * "knows" most of these things without consulting the CIS, + * and most client drivers will only use the CIS to fill in + * implementation-defined details. + */ + last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); + if (last_ret) { + if (!ignore_cis_vcc) + printk(KERN_ERR PFX "GetNextTuple(): No matching " + "CIS configuration. Maybe you need the " + "ignore_cis_vcc=1 parameter.\n"); + cs_error(link, RequestIO, last_ret); + goto failed; + } + + /* + * Allocate an interrupt line. Note that this does not assign + * a handler to the interrupt, unless the 'Handler' member of + * the irq structure is initialized. + */ + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + + /* We initialize the hermes structure before completing PCMCIA + * configuration just in case the interrupt handler gets + * called. */ + mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); + if (!mem) + goto cs_failed; + + hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping, and putting the + * card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, + pcmcia_request_configuration(link, &link->conf)); + + /* Ok, we have the configuration, prepare to register the netdev */ + dev->base_addr = link->io.BasePort1; + dev->irq = link->irq.AssignedIRQ; + card->node.major = card->node.minor = 0; + + SET_NETDEV_DEV(dev, &handle_to_dev(link)); + /* Tell the stack we exist */ + if (register_netdev(dev) != 0) { + printk(KERN_ERR PFX "register_netdev() failed\n"); + goto failed; + } + + /* At this point, the dev_node_t structure(s) needs to be + * initialized and arranged in a linked list at link->dev_node. */ + strcpy(card->node.dev_name, dev->name); + link->dev_node = &card->node; /* link->dev_node being non-NULL is also + used to indicate that the + net_device has been registered */ + + /* Finally, report what we've done */ + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + link->irq.AssignedIRQ, link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + return 0; + + cs_failed: + cs_error(link, last_fn, last_ret); + + failed: + orinoco_cs_release(link); + return -ENODEV; +} /* orinoco_cs_config */ + +/* + * After a card is removed, orinoco_cs_release() will unregister the + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void +orinoco_cs_release(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + /* We're committed to taking the device away now, so mark the + * hardware as unavailable */ + spin_lock_irqsave(&priv->lock, flags); + priv->hw_unavailable++; + spin_unlock_irqrestore(&priv->lock, flags); + + pcmcia_disable_device(link); + if (priv->hw.iobase) + ioport_unmap(priv->hw.iobase); +} /* orinoco_cs_release */ + +static int orinoco_cs_suspend(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pccard *card = priv->card; + int err = 0; + unsigned long flags; + + /* This is probably racy, but I can't think of + a better way, short of rewriting the PCMCIA + layer to not suck :-( */ + if (! test_bit(0, &card->hard_reset_in_progress)) { + spin_lock_irqsave(&priv->lock, flags); + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: Error %d downing interface\n", + dev->name, err); + + netif_device_detach(dev); + priv->hw_unavailable++; + + spin_unlock_irqrestore(&priv->lock, flags); + } + + return 0; +} + +static int orinoco_cs_resume(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pccard *card = priv->card; + int err = 0; + unsigned long flags; + + if (! test_bit(0, &card->hard_reset_in_progress)) { + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + priv->hw_unavailable--; + + if (priv->open && ! priv->hw_unavailable) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); + } + + return err; +} + + +/********************************************************************/ +/* Module initialization */ +/********************************************************************/ + +/* Can't be declared "const" or the whole __initdata section will + * become const */ +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (David Gibson , " + "Pavel Roskin , et al)"; + +static struct pcmcia_device_id orinoco_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ + PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ + PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ + PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ + PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ + PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ + PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ + PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ + PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ + PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */ + PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ + PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ + PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ + PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ + PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ + PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), + PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), + PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), + PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), + PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), + PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), + PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), + PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), + PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), + PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), + PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), + PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), + PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), + PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), + PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), + PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), + PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), + PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), + PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), + PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), + PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), + PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), + PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), + PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), + PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), + PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), + PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), + PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), + PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), + PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), + PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), + PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), + PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), + PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), + PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), + PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), + PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); + +static struct pcmcia_driver orinoco_driver = { + .owner = THIS_MODULE, + .drv = { + .name = DRIVER_NAME, + }, + .probe = orinoco_cs_probe, + .remove = orinoco_cs_detach, + .id_table = orinoco_cs_ids, + .suspend = orinoco_cs_suspend, + .resume = orinoco_cs_resume, +}; + +static int __init +init_orinoco_cs(void) +{ + printk(KERN_DEBUG "%s\n", version); + + return pcmcia_register_driver(&orinoco_driver); +} + +static void __exit +exit_orinoco_cs(void) +{ + pcmcia_unregister_driver(&orinoco_driver); +} + +module_init(init_orinoco_cs); +module_exit(exit_orinoco_cs); diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c new file mode 100644 index 0000000..2fc8659 --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -0,0 +1,324 @@ +/* orinoco_nortel.c + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in + * Nortel emobility, Symbol LA-4113 and Symbol LA-4123. + * + * Copyright (C) 2002 Tobias Hoffmann + * (C) 2003 Christoph Jungegger + * + * Some of this code is borrowed from orinoco_plx.c + * Copyright (C) 2001 Daniel Barlow + * Some of this code is borrowed from orinoco_pci.c + * Copyright (C) 2001 Jean Tourrilhes + * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing + * has been copied from it. linux-wlan-ng-0.1.10 is originally : + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#define DRIVER_NAME "orinoco_nortel" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include +#include + +#include "orinoco.h" +#include "orinoco_pci.h" + +#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ + + +/* + * Do a soft reset of the card using the Configuration Option Register + * We need this to get going... + * This is the part of the code that is strongly inspired from wlan-ng + * + * Note bis : Don't try to access HERMES_CMD during the reset phase. + * It just won't work ! + */ +static int orinoco_nortel_cor_reset(struct orinoco_private *priv) +{ + struct orinoco_pci_card *card = priv->card; + + /* Assert the reset until the card notices */ + iowrite16(8, card->bridge_io + 2); + ioread16(card->attr_io + COR_OFFSET); + iowrite16(0x80, card->attr_io + COR_OFFSET); + mdelay(1); + + /* Give time for the card to recover from this hard effort */ + iowrite16(0, card->attr_io + COR_OFFSET); + iowrite16(0, card->attr_io + COR_OFFSET); + mdelay(1); + + /* Set COR as usual */ + iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); + iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); + mdelay(1); + + iowrite16(0x228, card->bridge_io + 2); + + return 0; +} + +static int orinoco_nortel_hw_init(struct orinoco_pci_card *card) +{ + int i; + u32 reg; + + /* Setup bridge */ + if (ioread16(card->bridge_io) & 1) { + printk(KERN_ERR PFX "brg1 answer1 wrong\n"); + return -EBUSY; + } + iowrite16(0x118, card->bridge_io + 2); + iowrite16(0x108, card->bridge_io + 2); + mdelay(30); + iowrite16(0x8, card->bridge_io + 2); + for (i = 0; i < 30; i++) { + mdelay(30); + if (ioread16(card->bridge_io) & 0x10) { + break; + } + } + if (i == 30) { + printk(KERN_ERR PFX "brg1 timed out\n"); + return -EBUSY; + } + if (ioread16(card->attr_io + COR_OFFSET) & 1) { + printk(KERN_ERR PFX "brg2 answer1 wrong\n"); + return -EBUSY; + } + if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) { + printk(KERN_ERR PFX "brg2 answer2 wrong\n"); + return -EBUSY; + } + if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) { + printk(KERN_ERR PFX "brg2 answer3 wrong\n"); + return -EBUSY; + } + + /* Set the PCMCIA COR register */ + iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); + mdelay(1); + reg = ioread16(card->attr_io + COR_OFFSET); + if (reg != COR_VALUE) { + printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", + reg); + return -EBUSY; + } + + /* Set LEDs */ + iowrite16(1, card->bridge_io + 10); + return 0; +} + +static int orinoco_nortel_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct orinoco_private *priv; + struct orinoco_pci_card *card; + struct net_device *dev; + void __iomem *hermes_io, *bridge_io, *attr_io; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } + + bridge_io = pci_iomap(pdev, 0, 0); + if (!bridge_io) { + printk(KERN_ERR PFX "Cannot map bridge registers\n"); + err = -EIO; + goto fail_map_bridge; + } + + attr_io = pci_iomap(pdev, 1, 0); + if (!attr_io) { + printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); + err = -EIO; + goto fail_map_attr; + } + + hermes_io = pci_iomap(pdev, 2, 0); + if (!hermes_io) { + printk(KERN_ERR PFX "Cannot map chipset registers\n"); + err = -EIO; + goto fail_map_hermes; + } + + /* Allocate network device */ + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_nortel_cor_reset, NULL); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); + err = -ENOMEM; + goto fail_alloc; + } + + priv = netdev_priv(dev); + card = priv->card; + card->bridge_io = bridge_io; + card->attr_io = attr_io; + SET_NETDEV_DEV(dev, &pdev->dev); + + hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); + + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) { + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); + err = -EBUSY; + goto fail_irq; + } + + err = orinoco_nortel_hw_init(card); + if (err) { + printk(KERN_ERR PFX "Hardware initialization failed\n"); + goto fail; + } + + err = orinoco_nortel_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); + goto fail; + } + + pci_set_drvdata(pdev, dev); + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, + pci_name(pdev)); + + return 0; + + fail: + free_irq(pdev->irq, dev); + + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + + fail_alloc: + pci_iounmap(pdev, hermes_io); + + fail_map_hermes: + pci_iounmap(pdev, attr_io); + + fail_map_attr: + pci_iounmap(pdev, bridge_io); + + fail_map_bridge: + pci_release_regions(pdev); + + fail_resources: + pci_disable_device(pdev); + + return err; +} + +static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pci_card *card = priv->card; + + /* Clear LEDs */ + iowrite16(0, card->bridge_io + 10); + + unregister_netdev(dev); + free_irq(pdev->irq, dev); + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_iounmap(pdev, card->attr_io); + pci_iounmap(pdev, card->bridge_io); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id orinoco_nortel_id_table[] = { + /* Nortel emobility PCI */ + {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, + /* Symbol LA-4123 PCI */ + {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,}, + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table); + +static struct pci_driver orinoco_nortel_driver = { + .name = DRIVER_NAME, + .id_table = orinoco_nortel_id_table, + .probe = orinoco_nortel_init_one, + .remove = __devexit_p(orinoco_nortel_remove_one), + .suspend = orinoco_pci_suspend, + .resume = orinoco_pci_resume, +}; + +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Tobias Hoffmann & Christoph Jungegger )"; +MODULE_AUTHOR("Christoph Jungegger "); +MODULE_DESCRIPTION + ("Driver for wireless LAN cards using the Nortel PCI bridge"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int __init orinoco_nortel_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_register_driver(&orinoco_nortel_driver); +} + +static void __exit orinoco_nortel_exit(void) +{ + pci_unregister_driver(&orinoco_nortel_driver); +} + +module_init(orinoco_nortel_init); +module_exit(orinoco_nortel_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c new file mode 100644 index 0000000..4ebd638 --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -0,0 +1,264 @@ +/* orinoco_pci.c + * + * Driver for Prism 2.5/3 devices that have a direct PCI interface + * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge). + * The card contains only one PCI region, which contains all the usual + * hermes registers, as well as the COR register. + * + * Current maintainers are: + * Pavel Roskin + * and David Gibson + * + * Some of this code is borrowed from orinoco_plx.c + * Copyright (C) 2001 Daniel Barlow + * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing + * has been copied from it. linux-wlan-ng-0.1.10 is originally : + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * This file originally written by: + * Copyright (C) 2001 Jean Tourrilhes + * And is now maintained by: + * (C) Copyright David Gibson, IBM Corp. 2002-2003. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#define DRIVER_NAME "orinoco_pci" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include + +#include "orinoco.h" +#include "orinoco_pci.h" + +/* Offset of the COR register of the PCI card */ +#define HERMES_PCI_COR (0x26) + +/* Bitmask to reset the card */ +#define HERMES_PCI_COR_MASK (0x0080) + +/* Magic timeouts for doing the reset. + * Those times are straight from wlan-ng, and it is claimed that they + * are necessary. Alan will kill me. Take your time and grab a coffee. */ +#define HERMES_PCI_COR_ONT (250) /* ms */ +#define HERMES_PCI_COR_OFFT (500) /* ms */ +#define HERMES_PCI_COR_BUSYT (500) /* ms */ + +/* + * Do a soft reset of the card using the Configuration Option Register + * We need this to get going... + * This is the part of the code that is strongly inspired from wlan-ng + * + * Note : This code is done with irq enabled. This mean that many + * interrupts will occur while we are there. This is why we use the + * jiffies to regulate time instead of a straight mdelay(). Usually we + * need only around 245 iteration of the loop to do 250 ms delay. + * + * Note bis : Don't try to access HERMES_CMD during the reset phase. + * It just won't work ! + */ +static int orinoco_pci_cor_reset(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + unsigned long timeout; + u16 reg; + + /* Assert the reset until the card notices */ + hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); + mdelay(HERMES_PCI_COR_ONT); + + /* Give time for the card to recover from this hard effort */ + hermes_write_regn(hw, PCI_COR, 0x0000); + mdelay(HERMES_PCI_COR_OFFT); + + /* The card is ready when it's no longer busy */ + timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); + reg = hermes_read_regn(hw, CMD); + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { + mdelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* Still busy? */ + if (reg & HERMES_CMD_BUSY) { + printk(KERN_ERR PFX "Busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int orinoco_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct orinoco_private *priv; + struct orinoco_pci_card *card; + struct net_device *dev; + void __iomem *hermes_io; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } + + hermes_io = pci_iomap(pdev, 0, 0); + if (!hermes_io) { + printk(KERN_ERR PFX "Cannot remap chipset registers\n"); + err = -EIO; + goto fail_map_hermes; + } + + /* Allocate network device */ + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_pci_cor_reset, NULL); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); + err = -ENOMEM; + goto fail_alloc; + } + + priv = netdev_priv(dev); + card = priv->card; + SET_NETDEV_DEV(dev, &pdev->dev); + + hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); + + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) { + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); + err = -EBUSY; + goto fail_irq; + } + + err = orinoco_pci_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); + goto fail; + } + + pci_set_drvdata(pdev, dev); + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, + pci_name(pdev)); + + return 0; + + fail: + free_irq(pdev->irq, dev); + + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + + fail_alloc: + pci_iounmap(pdev, hermes_io); + + fail_map_hermes: + pci_release_regions(pdev); + + fail_resources: + pci_disable_device(pdev); + + return err; +} + +static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + + unregister_netdev(dev); + free_irq(pdev->irq, dev); + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id orinoco_pci_id_table[] = { + /* Intersil Prism 3 */ + {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, + /* Intersil Prism 2.5 */ + {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, + /* Samsung MagicLAN SWL-2210P */ + {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table); + +static struct pci_driver orinoco_pci_driver = { + .name = DRIVER_NAME, + .id_table = orinoco_pci_id_table, + .probe = orinoco_pci_init_one, + .remove = __devexit_p(orinoco_pci_remove_one), + .suspend = orinoco_pci_suspend, + .resume = orinoco_pci_resume, +}; + +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson &" + " Jean Tourrilhes )"; +MODULE_AUTHOR("Pavel Roskin & David Gibson "); +MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int __init orinoco_pci_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_register_driver(&orinoco_pci_driver); +} + +static void __exit orinoco_pci_exit(void) +{ + pci_unregister_driver(&orinoco_pci_driver); +} + +module_init(orinoco_pci_init); +module_exit(orinoco_pci_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h new file mode 100644 index 0000000..f4e5e06 --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco_pci.h @@ -0,0 +1,109 @@ +/* orinoco_pci.h + * + * Common code for all Orinoco drivers for PCI devices, including + * both native PCI and PCMCIA-to-PCI bridges. + * + * Copyright (C) 2005, Pavel Roskin. + * See orinoco.c for license. + */ + +#ifndef _ORINOCO_PCI_H +#define _ORINOCO_PCI_H + +#include + +/* Driver specific data */ +struct orinoco_pci_card { + void __iomem *bridge_io; + void __iomem *attr_io; +}; + +#ifdef CONFIG_PM +static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: cannot lock hardware for suspend\n", + dev->name); + return err; + } + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: error %d bringing interface down " + "for suspend\n", dev->name, err); + + netif_device_detach(dev); + + priv->hw_unavailable++; + + orinoco_unlock(priv, &flags); + + free_irq(pdev->irq, dev); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int orinoco_pci_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + pci_set_power_state(pdev, 0); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s: pci_enable_device failed on resume\n", + dev->name); + return err; + } + pci_restore_state(pdev); + + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) { + printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", + dev->name); + pci_disable_device(pdev); + return -EBUSY; + } + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: error %d re-initializing firmware " + "on resume\n", dev->name, err); + return err; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on resume\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +#else +#define orinoco_pci_suspend NULL +#define orinoco_pci_resume NULL +#endif + +#endif /* _ORINOCO_PCI_H */ diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c new file mode 100644 index 0000000..ef76185 --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -0,0 +1,371 @@ +/* orinoco_plx.c + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a PLX9052. + * + * Current maintainers are: + * Pavel Roskin + * and David Gibson + * + * (C) Copyright David Gibson, IBM Corp. 2001-2003. + * Copyright (C) 2001 Daniel Barlow + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + * + * Here's the general details on how the PLX9052 adapter works: + * + * - Two PCI I/O address spaces, one 0x80 long which contains the + * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA + * slot I/O address space. + * + * - One PCI memory address space, mapped to the PCMCIA attribute space + * (containing the CIS). + * + * Using the later, you can read through the CIS data to make sure the + * card is compatible with the driver. Keep in mind that the PCMCIA + * spec specifies the CIS as the lower 8 bits of each word read from + * the CIS, so to read the bytes of the CIS, read every other byte + * (0,2,4,...). Passing that test, you need to enable the I/O address + * space on the PCMCIA card via the PCMCIA COR register. This is the + * first byte following the CIS. In my case (which may not have any + * relation to what's on the PRISM2 cards), COR was at offset 0x800 + * within the PCI memory space. Write 0x41 to the COR register to + * enable I/O mode and to select level triggered interrupts. To + * confirm you actually succeeded, read the COR register back and make + * sure it actually got set to 0x41, in case you have an unexpected + * card inserted. + * + * Following that, you can treat the second PCI I/O address space (the + * one that's not 0x80 in length) as the PCMCIA I/O space. + * + * Note that in the Eumitcom's source for their drivers, they register + * the interrupt as edge triggered when registering it with the + * Windows kernel. I don't recall how to register edge triggered on + * Linux (if it can be done at all). But in some experimentation, I + * don't see much operational difference between using either + * interrupt mode. Don't mess with the interrupt mode in the COR + * register though, as the PLX9052 wants level triggers with the way + * the serial EEPROM configures it on the WL11000. + * + * There's some other little quirks related to timing that I bumped + * into, but I don't recall right now. Also, there's two variants of + * the WL11000 I've seen, revision A1 and T2. These seem to differ + * slightly in the timings configured in the wait-state generator in + * the PLX9052. There have also been some comments from Eumitcom that + * cards shouldn't be hot swapped, apparently due to risk of cooking + * the PLX9052. I'm unsure why they believe this, as I can't see + * anything in the design that would really cause a problem, except + * for crashing drivers not written to expect it. And having developed + * drivers for the WL11000, I'd say it's quite tricky to write code + * that will successfully deal with a hot unplug. Very odd things + * happen on the I/O side of things. But anyway, be warned. Despite + * that, I've hot-swapped a number of times during debugging and + * driver development for various reasons (stuck WAIT# line after the + * radio card's firmware locks up). + */ + +#define DRIVER_NAME "orinoco_plx" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include +#include + +#include "orinoco.h" +#include "orinoco_pci.h" + +#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ +#define COR_RESET (0x80) /* reset bit in the COR register */ +#define PLX_RESET_TIME (500) /* milliseconds */ + +#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ +#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ + +/* + * Do a soft reset of the card using the Configuration Option Register + */ +static int orinoco_plx_cor_reset(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + struct orinoco_pci_card *card = priv->card; + unsigned long timeout; + u16 reg; + + iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); + mdelay(1); + + iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); + mdelay(1); + + /* Just in case, wait more until the card is no longer busy */ + timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); + reg = hermes_read_regn(hw, CMD); + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { + mdelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* Still busy? */ + if (reg & HERMES_CMD_BUSY) { + printk(KERN_ERR PFX "Busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int orinoco_plx_hw_init(struct orinoco_pci_card *card) +{ + int i; + u32 csr_reg; + static const u8 cis_magic[] = { + 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 + }; + + printk(KERN_DEBUG PFX "CIS: "); + for (i = 0; i < 16; i++) { + printk("%02X:", ioread8(card->attr_io + (i << 1))); + } + printk("\n"); + + /* Verify whether a supported PC card is present */ + /* FIXME: we probably need to be smarted about this */ + for (i = 0; i < sizeof(cis_magic); i++) { + if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { + printk(KERN_ERR PFX "The CIS value of Prism2 PC " + "card is unexpected\n"); + return -ENODEV; + } + } + + /* bjoern: We need to tell the card to enable interrupts, in + case the serial eprom didn't do this already. See the + PLX9052 data book, p8-1 and 8-24 for reference. */ + csr_reg = ioread32(card->bridge_io + PLX_INTCSR); + if (!(csr_reg & PLX_INTCSR_INTEN)) { + csr_reg |= PLX_INTCSR_INTEN; + iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); + csr_reg = ioread32(card->bridge_io + PLX_INTCSR); + if (!(csr_reg & PLX_INTCSR_INTEN)) { + printk(KERN_ERR PFX "Cannot enable interrupts\n"); + return -EIO; + } + } + + return 0; +} + +static int orinoco_plx_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct orinoco_private *priv; + struct orinoco_pci_card *card; + struct net_device *dev; + void __iomem *hermes_io, *attr_io, *bridge_io; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } + + bridge_io = pci_iomap(pdev, 1, 0); + if (!bridge_io) { + printk(KERN_ERR PFX "Cannot map bridge registers\n"); + err = -EIO; + goto fail_map_bridge; + } + + attr_io = pci_iomap(pdev, 2, 0); + if (!attr_io) { + printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); + err = -EIO; + goto fail_map_attr; + } + + hermes_io = pci_iomap(pdev, 3, 0); + if (!hermes_io) { + printk(KERN_ERR PFX "Cannot map chipset registers\n"); + err = -EIO; + goto fail_map_hermes; + } + + /* Allocate network device */ + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_plx_cor_reset, NULL); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); + err = -ENOMEM; + goto fail_alloc; + } + + priv = netdev_priv(dev); + card = priv->card; + card->bridge_io = bridge_io; + card->attr_io = attr_io; + SET_NETDEV_DEV(dev, &pdev->dev); + + hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); + + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) { + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); + err = -EBUSY; + goto fail_irq; + } + + err = orinoco_plx_hw_init(card); + if (err) { + printk(KERN_ERR PFX "Hardware initialization failed\n"); + goto fail; + } + + err = orinoco_plx_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); + goto fail; + } + + pci_set_drvdata(pdev, dev); + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, + pci_name(pdev)); + + return 0; + + fail: + free_irq(pdev->irq, dev); + + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + + fail_alloc: + pci_iounmap(pdev, hermes_io); + + fail_map_hermes: + pci_iounmap(pdev, attr_io); + + fail_map_attr: + pci_iounmap(pdev, bridge_io); + + fail_map_bridge: + pci_release_regions(pdev); + + fail_resources: + pci_disable_device(pdev); + + return err; +} + +static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pci_card *card = priv->card; + + unregister_netdev(dev); + free_irq(pdev->irq, dev); + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_iounmap(pdev, card->attr_io); + pci_iounmap(pdev, card->bridge_io); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id orinoco_plx_id_table[] = { + {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ + {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ + {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ + {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, + Eumitcom PCI WL11000, + Addtron AWA-100 */ + {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ + {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ + {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ + {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ + {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by + Brendan W. McAdams */ + {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by + Damien Persohn */ + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); + +static struct pci_driver orinoco_plx_driver = { + .name = DRIVER_NAME, + .id_table = orinoco_plx_id_table, + .probe = orinoco_plx_init_one, + .remove = __devexit_p(orinoco_plx_remove_one), + .suspend = orinoco_pci_suspend, + .resume = orinoco_pci_resume, +}; + +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson ," + " Daniel Barlow )"; +MODULE_AUTHOR("Daniel Barlow "); +MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int __init orinoco_plx_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_register_driver(&orinoco_plx_driver); +} + +static void __exit orinoco_plx_exit(void) +{ + pci_unregister_driver(&orinoco_plx_driver); +} + +module_init(orinoco_plx_init); +module_exit(orinoco_plx_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c new file mode 100644 index 0000000..ede24ec --- /dev/null +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -0,0 +1,248 @@ +/* orinoco_tmd.c + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a TMD7160. + * + * Copyright (C) 2003 Joerg Dorchain + * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + * + * The actual driving is done by orinoco.c, this is just resource + * allocation stuff. + * + * This driver is modeled after the orinoco_plx driver. The main + * difference is that the TMD chip has only IO port ranges and doesn't + * provide access to the PCMCIA attribute space. + * + * Pheecom sells cards with the TMD chip as "ASIC version" + */ + +#define DRIVER_NAME "orinoco_tmd" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include +#include + +#include "orinoco.h" +#include "orinoco_pci.h" + +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ +#define COR_RESET (0x80) /* reset bit in the COR register */ +#define TMD_RESET_TIME (500) /* milliseconds */ + +/* + * Do a soft reset of the card using the Configuration Option Register + */ +static int orinoco_tmd_cor_reset(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + struct orinoco_pci_card *card = priv->card; + unsigned long timeout; + u16 reg; + + iowrite8(COR_VALUE | COR_RESET, card->bridge_io); + mdelay(1); + + iowrite8(COR_VALUE, card->bridge_io); + mdelay(1); + + /* Just in case, wait more until the card is no longer busy */ + timeout = jiffies + (TMD_RESET_TIME * HZ / 1000); + reg = hermes_read_regn(hw, CMD); + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { + mdelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* Still busy? */ + if (reg & HERMES_CMD_BUSY) { + printk(KERN_ERR PFX "Busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + + +static int orinoco_tmd_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct orinoco_private *priv; + struct orinoco_pci_card *card; + struct net_device *dev; + void __iomem *hermes_io, *bridge_io; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } + + bridge_io = pci_iomap(pdev, 1, 0); + if (!bridge_io) { + printk(KERN_ERR PFX "Cannot map bridge registers\n"); + err = -EIO; + goto fail_map_bridge; + } + + hermes_io = pci_iomap(pdev, 2, 0); + if (!hermes_io) { + printk(KERN_ERR PFX "Cannot map chipset registers\n"); + err = -EIO; + goto fail_map_hermes; + } + + /* Allocate network device */ + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_tmd_cor_reset, NULL); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); + err = -ENOMEM; + goto fail_alloc; + } + + priv = netdev_priv(dev); + card = priv->card; + card->bridge_io = bridge_io; + SET_NETDEV_DEV(dev, &pdev->dev); + + hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); + + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) { + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); + err = -EBUSY; + goto fail_irq; + } + + err = orinoco_tmd_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); + goto fail; + } + + pci_set_drvdata(pdev, dev); + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, + pci_name(pdev)); + + return 0; + + fail: + free_irq(pdev->irq, dev); + + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + + fail_alloc: + pci_iounmap(pdev, hermes_io); + + fail_map_hermes: + pci_iounmap(pdev, bridge_io); + + fail_map_bridge: + pci_release_regions(pdev); + + fail_resources: + pci_disable_device(pdev); + + return err; +} + +static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pci_card *card = priv->card; + + unregister_netdev(dev); + free_irq(pdev->irq, dev); + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_iounmap(pdev, card->bridge_io); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id orinoco_tmd_id_table[] = { + {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table); + +static struct pci_driver orinoco_tmd_driver = { + .name = DRIVER_NAME, + .id_table = orinoco_tmd_id_table, + .probe = orinoco_tmd_init_one, + .remove = __devexit_p(orinoco_tmd_remove_one), + .suspend = orinoco_pci_suspend, + .resume = orinoco_pci_resume, +}; + +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Joerg Dorchain )"; +MODULE_AUTHOR("Joerg Dorchain "); +MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int __init orinoco_tmd_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_register_driver(&orinoco_tmd_driver); +} + +static void __exit orinoco_tmd_exit(void) +{ + pci_unregister_driver(&orinoco_tmd_driver); +} + +module_init(orinoco_tmd_init); +module_exit(orinoco_tmd_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c new file mode 100644 index 0000000..852789a --- /dev/null +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -0,0 +1,507 @@ +/* + * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as + * Symbol Wireless Networker LA4137, CompactFlash cards by Socket + * Communications and Intel PRO/Wireless 2011B. + * + * The driver implements Symbol firmware download. The rest is handled + * in hermes.c and orinoco.c. + * + * Utilities for downloading the Symbol firmware are available at + * http://sourceforge.net/projects/orinoco/ + * + * Copyright (C) 2002-2005 Pavel Roskin + * Portions based on orinoco_cs.c: + * Copyright (C) David Gibson, Linuxcare Australia + * Portions based on Spectrum24tDnld.c from original spectrum24 driver: + * Copyright (C) Symbol Technologies. + * + * See copyright notice in file orinoco.c. + */ + +#define DRIVER_NAME "spectrum_cs" +#define PFX DRIVER_NAME ": " + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "orinoco.h" + +/********************************************************************/ +/* Module stuff */ +/********************************************************************/ + +MODULE_AUTHOR("Pavel Roskin "); +MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader"); +MODULE_LICENSE("Dual MPL/GPL"); + +/* Module parameters */ + +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but + * don't have any CIS entry for it. This workaround it... */ +static int ignore_cis_vcc; /* = 0 */ +module_param(ignore_cis_vcc, int, 0); +MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); + +/********************************************************************/ +/* Data structures */ +/********************************************************************/ + +/* PCMCIA specific device information (goes in the card field of + * struct orinoco_private */ +struct orinoco_pccard { + struct pcmcia_device *p_dev; + dev_node_t node; +}; + +/********************************************************************/ +/* Function prototypes */ +/********************************************************************/ + +static int spectrum_cs_config(struct pcmcia_device *link); +static void spectrum_cs_release(struct pcmcia_device *link); + +/* Constants for the CISREG_CCSR register */ +#define HCR_RUN 0x07 /* run firmware after reset */ +#define HCR_IDLE 0x0E /* don't run firmware after reset */ +#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ + + +#define CS_CHECK(fn, ret) \ + do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +/* + * Reset the card using configuration registers COR and CCSR. + * If IDLE is 1, stop the firmware, so that it can be safely rewritten. + */ +static int +spectrum_reset(struct pcmcia_device *link, int idle) +{ + int last_ret, last_fn; + conf_reg_t reg; + u_int save_cor; + + /* Doing it if hardware is gone is guaranteed crash */ + if (!pcmcia_dev_present(link)) + return -ENODEV; + + /* Save original COR value */ + reg.Function = 0; + reg.Action = CS_READ; + reg.Offset = CISREG_COR; + CS_CHECK(AccessConfigurationRegister, + pcmcia_access_configuration_register(link, ®)); + save_cor = reg.Value; + + /* Soft-Reset card */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + reg.Value = (save_cor | COR_SOFT_RESET); + CS_CHECK(AccessConfigurationRegister, + pcmcia_access_configuration_register(link, ®)); + udelay(1000); + + /* Read CCSR */ + reg.Action = CS_READ; + reg.Offset = CISREG_CCSR; + CS_CHECK(AccessConfigurationRegister, + pcmcia_access_configuration_register(link, ®)); + + /* + * Start or stop the firmware. Memory width bit should be + * preserved from the value we've just read. + */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_CCSR; + reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16); + CS_CHECK(AccessConfigurationRegister, + pcmcia_access_configuration_register(link, ®)); + udelay(1000); + + /* Restore original COR configuration index */ + reg.Action = CS_WRITE; + reg.Offset = CISREG_COR; + reg.Value = (save_cor & ~COR_SOFT_RESET); + CS_CHECK(AccessConfigurationRegister, + pcmcia_access_configuration_register(link, ®)); + udelay(1000); + return 0; + + cs_failed: + cs_error(link, last_fn, last_ret); + return -ENODEV; +} + +/********************************************************************/ +/* Device methods */ +/********************************************************************/ + +static int +spectrum_cs_hard_reset(struct orinoco_private *priv) +{ + struct orinoco_pccard *card = priv->card; + struct pcmcia_device *link = card->p_dev; + + /* Soft reset using COR and HCR */ + spectrum_reset(link, 0); + + return 0; +} + +static int +spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) +{ + struct orinoco_pccard *card = priv->card; + struct pcmcia_device *link = card->p_dev; + + return spectrum_reset(link, idle); +} + +/********************************************************************/ +/* PCMCIA stuff */ +/********************************************************************/ + +/* + * This creates an "instance" of the driver, allocating local data + * structures for one device. The device is registered with Card + * Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a card + * insertion event. */ +static int +spectrum_cs_probe(struct pcmcia_device *link) +{ + struct net_device *dev; + struct orinoco_private *priv; + struct orinoco_pccard *card; + + dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + spectrum_cs_hard_reset, + spectrum_cs_stop_firmware); + if (! dev) + return -ENOMEM; + priv = netdev_priv(dev); + card = priv->card; + + /* Link both structures together */ + card->p_dev = link; + link->priv = dev; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Handler = orinoco_interrupt; + link->irq.Instance = dev; + + /* General socket configuration defaults can go here. In this + * client, we assume very little, and rely on the CIS for + * almost everything. In most clients, many details (i.e., + * number, sizes, and attributes of IO windows) are fixed by + * the nature of the device, and can be hard-wired here. */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + return spectrum_cs_config(link); +} /* spectrum_cs_attach */ + +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void spectrum_cs_detach(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + + if (link->dev_node) + unregister_netdev(dev); + + spectrum_cs_release(link); + + free_orinocodev(dev); +} /* spectrum_cs_detach */ + +/* + * spectrum_cs_config() is scheduled to run after a CARD_INSERTION + * event is received, to configure the PCMCIA socket, and to make the + * device available to the system. + */ + +static int spectrum_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + goto next_entry; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + goto next_entry; + } + return 0; + +next_entry: + pcmcia_disable_device(p_dev); + return -ENODEV; +}; + +static int +spectrum_cs_config(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_pccard *card = priv->card; + hermes_t *hw = &priv->hw; + int last_fn, last_ret; + void __iomem *mem; + + /* + * In this loop, we scan the CIS for configuration table + * entries, each of which describes a valid card + * configuration, including voltage, IO window, memory window, + * and interrupt settings. + * + * We make no assumptions about the card to be configured: we + * use just the information available in the CIS. In an ideal + * world, this would work for any PCMCIA card, but it requires + * a complete and accurate CIS. In practice, a driver usually + * "knows" most of these things without consulting the CIS, + * and most client drivers will only use the CIS to fill in + * implementation-defined details. + */ + last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); + if (last_ret) { + if (!ignore_cis_vcc) + printk(KERN_ERR PFX "GetNextTuple(): No matching " + "CIS configuration. Maybe you need the " + "ignore_cis_vcc=1 parameter.\n"); + cs_error(link, RequestIO, last_ret); + goto failed; + } + + /* + * Allocate an interrupt line. Note that this does not assign + * a handler to the interrupt, unless the 'Handler' member of + * the irq structure is initialized. + */ + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + + /* We initialize the hermes structure before completing PCMCIA + * configuration just in case the interrupt handler gets + * called. */ + mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); + if (!mem) + goto cs_failed; + + hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping, and putting the + * card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, + pcmcia_request_configuration(link, &link->conf)); + + /* Ok, we have the configuration, prepare to register the netdev */ + dev->base_addr = link->io.BasePort1; + dev->irq = link->irq.AssignedIRQ; + card->node.major = card->node.minor = 0; + + /* Reset card */ + if (spectrum_cs_hard_reset(priv) != 0) { + goto failed; + } + + SET_NETDEV_DEV(dev, &handle_to_dev(link)); + /* Tell the stack we exist */ + if (register_netdev(dev) != 0) { + printk(KERN_ERR PFX "register_netdev() failed\n"); + goto failed; + } + + /* At this point, the dev_node_t structure(s) needs to be + * initialized and arranged in a linked list at link->dev_node. */ + strcpy(card->node.dev_name, dev->name); + link->dev_node = &card->node; /* link->dev_node being non-NULL is also + used to indicate that the + net_device has been registered */ + + /* Finally, report what we've done */ + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + link->irq.AssignedIRQ, link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + + return 0; + + cs_failed: + cs_error(link, last_fn, last_ret); + + failed: + spectrum_cs_release(link); + return -ENODEV; +} /* spectrum_cs_config */ + +/* + * After a card is removed, spectrum_cs_release() will unregister the + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void +spectrum_cs_release(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + + /* We're committed to taking the device away now, so mark the + * hardware as unavailable */ + spin_lock_irqsave(&priv->lock, flags); + priv->hw_unavailable++; + spin_unlock_irqrestore(&priv->lock, flags); + + pcmcia_disable_device(link); + if (priv->hw.iobase) + ioport_unmap(priv->hw.iobase); +} /* spectrum_cs_release */ + + +static int +spectrum_cs_suspend(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err = 0; + + /* Mark the device as stopped, to block IO until later */ + spin_lock_irqsave(&priv->lock, flags); + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: Error %d downing interface\n", + dev->name, err); + + netif_device_detach(dev); + priv->hw_unavailable++; + + spin_unlock_irqrestore(&priv->lock, flags); + + return err; +} + +static int +spectrum_cs_resume(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + struct orinoco_private *priv = netdev_priv(dev); + + netif_device_attach(dev); + priv->hw_unavailable--; + schedule_work(&priv->reset_work); + + return 0; +} + + +/********************************************************************/ +/* Module initialization */ +/********************************************************************/ + +/* Can't be declared "const" or the whole __initdata section will + * become const */ +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Pavel Roskin ," + " David Gibson , et al)"; + +static struct pcmcia_device_id spectrum_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ + PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); + +static struct pcmcia_driver orinoco_driver = { + .owner = THIS_MODULE, + .drv = { + .name = DRIVER_NAME, + }, + .probe = spectrum_cs_probe, + .remove = spectrum_cs_detach, + .suspend = spectrum_cs_suspend, + .resume = spectrum_cs_resume, + .id_table = spectrum_cs_ids, +}; + +static int __init +init_spectrum_cs(void) +{ + printk(KERN_DEBUG "%s\n", version); + + return pcmcia_register_driver(&orinoco_driver); +} + +static void __exit +exit_spectrum_cs(void) +{ + pcmcia_unregister_driver(&orinoco_driver); +} + +module_init(init_spectrum_cs); +module_exit(exit_spectrum_cs); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c deleted file mode 100644 index 6fcf2bd..0000000 --- a/drivers/net/wireless/orinoco_cs.c +++ /dev/null @@ -1,533 +0,0 @@ -/* orinoco_cs.c (formerly known as dldwd_cs.c) - * - * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - * It should also be usable on various Prism II based cards such as the - * Linksys, D-Link and Farallon Skyline. It should also work on Symbol - * cards such as the 3Com AirConnect and Ericsson WLAN. - * - * Copyright notice & release notes in file orinoco.c - */ - -#define DRIVER_NAME "orinoco_cs" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("David Gibson "); -MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; - dev_node_t node; - - /* Used to handle hard reset */ - /* yuck, we need this hack to work around the insanity of the - * PCMCIA layer */ - unsigned long hard_reset_in_progress; -}; - - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int orinoco_cs_config(struct pcmcia_device *link); -static void orinoco_cs_release(struct pcmcia_device *link); -static void orinoco_cs_detach(struct pcmcia_device *p_dev); - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -orinoco_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - int err; - - /* We need atomic ops here, because we're not holding the lock */ - set_bit(0, &card->hard_reset_in_progress); - - err = pcmcia_reset_card(link->socket); - if (err) - return err; - - msleep(100); - clear_bit(0, &card->hard_reset_in_progress); - - return 0; -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -/* - * This creates an "instance" of the driver, allocating local data - * structures for one device. The device is registered with Card - * Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a card - * insertion event. */ -static int -orinoco_cs_probe(struct pcmcia_device *link) -{ - struct net_device *dev; - struct orinoco_private *priv; - struct orinoco_pccard *card; - - dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), - orinoco_cs_hard_reset, NULL); - if (! dev) - return -ENOMEM; - priv = netdev_priv(dev); - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = dev; - - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; - - /* General socket configuration defaults can go here. In this - * client, we assume very little, and rely on the CIS for - * almost everything. In most clients, many details (i.e., - * number, sizes, and attributes of IO windows) are fixed by - * the nature of the device, and can be hard-wired here. */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - - return orinoco_cs_config(link); -} /* orinoco_cs_attach */ - -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ -static void orinoco_cs_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->dev_node) - unregister_netdev(dev); - - orinoco_cs_release(link); - - free_orinocodev(dev); -} /* orinoco_cs_detach */ - -/* - * orinoco_cs_config() is scheduled to run after a CARD_INSERTION - * event is received, to configure the PCMCIA socket, and to make the - * device available to the system. - */ - -#define CS_CHECK(fn, ret) do { \ - last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ - } while (0) - -static int orinoco_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) -{ - if (cfg->index == 0) - goto next_entry; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->io.BasePort1 = io->win[0].base; - p_dev->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - p_dev->io.Attributes2 = p_dev->io.Attributes1; - p_dev->io.BasePort2 = io->win[1].base; - p_dev->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev, &p_dev->io) != 0) - goto next_entry; - } - return 0; - -next_entry: - pcmcia_disable_device(p_dev); - return -ENODEV; -}; - -static int -orinoco_cs_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pccard *card = priv->card; - hermes_t *hw = &priv->hw; - int last_fn, last_ret; - void __iomem *mem; - - /* - * In this loop, we scan the CIS for configuration table - * entries, each of which describes a valid card - * configuration, including voltage, IO window, memory window, - * and interrupt settings. - * - * We make no assumptions about the card to be configured: we - * use just the information available in the CIS. In an ideal - * world, this would work for any PCMCIA card, but it requires - * a complete and accurate CIS. In practice, a driver usually - * "knows" most of these things without consulting the CIS, - * and most client drivers will only use the CIS to fill in - * implementation-defined details. - */ - last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); - if (last_ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - cs_error(link, RequestIO, last_ret); - goto failed; - } - - /* - * Allocate an interrupt line. Note that this does not assign - * a handler to the interrupt, unless the 'Handler' member of - * the irq structure is initialized. - */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); - if (!mem) - goto cs_failed; - - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping, and putting the - * card and host interface into "Memory and IO" mode. - */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); - - /* Ok, we have the configuration, prepare to register the netdev */ - dev->base_addr = link->io.BasePort1; - dev->irq = link->irq.AssignedIRQ; - card->node.major = card->node.minor = 0; - - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); - goto failed; - } - - /* At this point, the dev_node_t structure(s) needs to be - * initialized and arranged in a linked list at link->dev_node. */ - strcpy(card->node.dev_name, dev->name); - link->dev_node = &card->node; /* link->dev_node being non-NULL is also - used to indicate that the - net_device has been registered */ - - /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, - link->irq.AssignedIRQ, link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - return 0; - - cs_failed: - cs_error(link, last_fn, last_ret); - - failed: - orinoco_cs_release(link); - return -ENODEV; -} /* orinoco_cs_config */ - -/* - * After a card is removed, orinoco_cs_release() will unregister the - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ -static void -orinoco_cs_release(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - spin_lock_irqsave(&priv->lock, flags); - priv->hw_unavailable++; - spin_unlock_irqrestore(&priv->lock, flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* orinoco_cs_release */ - -static int orinoco_cs_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pccard *card = priv->card; - int err = 0; - unsigned long flags; - - /* This is probably racy, but I can't think of - a better way, short of rewriting the PCMCIA - layer to not suck :-( */ - if (! test_bit(0, &card->hard_reset_in_progress)) { - spin_lock_irqsave(&priv->lock, flags); - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - - spin_unlock_irqrestore(&priv->lock, flags); - } - - return 0; -} - -static int orinoco_cs_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pccard *card = priv->card; - int err = 0; - unsigned long flags; - - if (! test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && ! priv->hw_unavailable) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - } - - return err; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (David Gibson , " - "Pavel Roskin , et al)"; - -static struct pcmcia_device_id orinoco_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */ - PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */ - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */ - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ - PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */ - PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ - PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ - PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */ - PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */ - PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */ - PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */ - PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */ - PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */ - PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */ - PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */ - PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */ - PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */ - PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */ - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */ - PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9), - PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), - PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5), - PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2), - PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092), - PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), - PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), - PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169), - PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18), - PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), - PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b), - PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), - PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), - PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), - PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), - PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), - PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916), - PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146), - PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), - PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c), - PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), - PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77), - PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf), - PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2), - PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92), - PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395), - PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410), - PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3), - PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01), - PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1), - PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767), - PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6), - PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed), - PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264), - PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9), - PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26), - PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757), - PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a), - PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e), - PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39), - PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .drv = { - .name = DRIVER_NAME, - }, - .probe = orinoco_cs_probe, - .remove = orinoco_cs_detach, - .id_table = orinoco_cs_ids, - .suspend = orinoco_cs_suspend, - .resume = orinoco_cs_resume, -}; - -static int __init -init_orinoco_cs(void) -{ - printk(KERN_DEBUG "%s\n", version); - - return pcmcia_register_driver(&orinoco_driver); -} - -static void __exit -exit_orinoco_cs(void) -{ - pcmcia_unregister_driver(&orinoco_driver); -} - -module_init(init_orinoco_cs); -module_exit(exit_orinoco_cs); diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c deleted file mode 100644 index 2fc8659..0000000 --- a/drivers/net/wireless/orinoco_nortel.c +++ /dev/null @@ -1,324 +0,0 @@ -/* orinoco_nortel.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in - * Nortel emobility, Symbol LA-4113 and Symbol LA-4123. - * - * Copyright (C) 2002 Tobias Hoffmann - * (C) 2003 Christoph Jungegger - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is borrowed from orinoco_pci.c - * Copyright (C) 2001 Jean Tourrilhes - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_nortel" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ - - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_nortel_cor_reset(struct orinoco_private *priv) -{ - struct orinoco_pci_card *card = priv->card; - - /* Assert the reset until the card notices */ - iowrite16(8, card->bridge_io + 2); - ioread16(card->attr_io + COR_OFFSET); - iowrite16(0x80, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Give time for the card to recover from this hard effort */ - iowrite16(0, card->attr_io + COR_OFFSET); - iowrite16(0, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Set COR as usual */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite16(0x228, card->bridge_io + 2); - - return 0; -} - -static int orinoco_nortel_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 reg; - - /* Setup bridge */ - if (ioread16(card->bridge_io) & 1) { - printk(KERN_ERR PFX "brg1 answer1 wrong\n"); - return -EBUSY; - } - iowrite16(0x118, card->bridge_io + 2); - iowrite16(0x108, card->bridge_io + 2); - mdelay(30); - iowrite16(0x8, card->bridge_io + 2); - for (i = 0; i < 30; i++) { - mdelay(30); - if (ioread16(card->bridge_io) & 0x10) { - break; - } - } - if (i == 30) { - printk(KERN_ERR PFX "brg1 timed out\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET) & 1) { - printk(KERN_ERR PFX "brg2 answer1 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) { - printk(KERN_ERR PFX "brg2 answer2 wrong\n"); - return -EBUSY; - } - if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) { - printk(KERN_ERR PFX "brg2 answer3 wrong\n"); - return -EBUSY; - } - - /* Set the PCMCIA COR register */ - iowrite16(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - reg = ioread16(card->attr_io + COR_OFFSET); - if (reg != COR_VALUE) { - printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", - reg); - return -EBUSY; - } - - /* Set LEDs */ - iowrite16(1, card->bridge_io + 10); - return 0; -} - -static int orinoco_nortel_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - struct net_device *dev; - void __iomem *hermes_io, *bridge_io, *attr_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 0, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 1, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_nortel_cor_reset, NULL); - if (!dev) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - priv = netdev_priv(dev); - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - SET_NETDEV_DEV(dev, &pdev->dev); - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_nortel_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_nortel_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = register_netdev(dev); - if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); - goto fail; - } - - pci_set_drvdata(pdev, dev); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); - - return 0; - - fail: - free_irq(pdev->irq, dev); - - fail_irq: - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pci_card *card = priv->card; - - /* Clear LEDs */ - iowrite16(0, card->bridge_io + 10); - - unregister_netdev(dev); - free_irq(pdev->irq, dev); - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static struct pci_device_id orinoco_nortel_id_table[] = { - /* Nortel emobility PCI */ - {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, - /* Symbol LA-4123 PCI */ - {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table); - -static struct pci_driver orinoco_nortel_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_nortel_id_table, - .probe = orinoco_nortel_init_one, - .remove = __devexit_p(orinoco_nortel_remove_one), - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Tobias Hoffmann & Christoph Jungegger )"; -MODULE_AUTHOR("Christoph Jungegger "); -MODULE_DESCRIPTION - ("Driver for wireless LAN cards using the Nortel PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_nortel_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_nortel_driver); -} - -static void __exit orinoco_nortel_exit(void) -{ - pci_unregister_driver(&orinoco_nortel_driver); -} - -module_init(orinoco_nortel_init); -module_exit(orinoco_nortel_exit); - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c deleted file mode 100644 index 4ebd638..0000000 --- a/drivers/net/wireless/orinoco_pci.c +++ /dev/null @@ -1,264 +0,0 @@ -/* orinoco_pci.c - * - * Driver for Prism 2.5/3 devices that have a direct PCI interface - * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge). - * The card contains only one PCI region, which contains all the usual - * hermes registers, as well as the COR register. - * - * Current maintainers are: - * Pavel Roskin - * and David Gibson - * - * Some of this code is borrowed from orinoco_plx.c - * Copyright (C) 2001 Daniel Barlow - * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing - * has been copied from it. linux-wlan-ng-0.1.10 is originally : - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * This file originally written by: - * Copyright (C) 2001 Jean Tourrilhes - * And is now maintained by: - * (C) Copyright David Gibson, IBM Corp. 2002-2003. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - */ - -#define DRIVER_NAME "orinoco_pci" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -/* Offset of the COR register of the PCI card */ -#define HERMES_PCI_COR (0x26) - -/* Bitmask to reset the card */ -#define HERMES_PCI_COR_MASK (0x0080) - -/* Magic timeouts for doing the reset. - * Those times are straight from wlan-ng, and it is claimed that they - * are necessary. Alan will kill me. Take your time and grab a coffee. */ -#define HERMES_PCI_COR_ONT (250) /* ms */ -#define HERMES_PCI_COR_OFFT (500) /* ms */ -#define HERMES_PCI_COR_BUSYT (500) /* ms */ - -/* - * Do a soft reset of the card using the Configuration Option Register - * We need this to get going... - * This is the part of the code that is strongly inspired from wlan-ng - * - * Note : This code is done with irq enabled. This mean that many - * interrupts will occur while we are there. This is why we use the - * jiffies to regulate time instead of a straight mdelay(). Usually we - * need only around 245 iteration of the loop to do 250 ms delay. - * - * Note bis : Don't try to access HERMES_CMD during the reset phase. - * It just won't work ! - */ -static int orinoco_pci_cor_reset(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - unsigned long timeout; - u16 reg; - - /* Assert the reset until the card notices */ - hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); - mdelay(HERMES_PCI_COR_ONT); - - /* Give time for the card to recover from this hard effort */ - hermes_write_regn(hw, PCI_COR, 0x0000); - mdelay(HERMES_PCI_COR_OFFT); - - /* The card is ready when it's no longer busy */ - timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - struct net_device *dev; - void __iomem *hermes_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - hermes_io = pci_iomap(pdev, 0, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot remap chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_pci_cor_reset, NULL); - if (!dev) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - priv = netdev_priv(dev); - card = priv->card; - SET_NETDEV_DEV(dev, &pdev->dev); - - hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_pci_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = register_netdev(dev); - if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); - goto fail; - } - - pci_set_drvdata(pdev, dev); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); - - return 0; - - fail: - free_irq(pdev->irq, dev); - - fail_irq: - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - - unregister_netdev(dev); - free_irq(pdev->irq, dev); - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - pci_iounmap(pdev, priv->hw.iobase); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static struct pci_device_id orinoco_pci_id_table[] = { - /* Intersil Prism 3 */ - {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, - /* Intersil Prism 2.5 */ - {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, - /* Samsung MagicLAN SWL-2210P */ - {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table); - -static struct pci_driver orinoco_pci_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_pci_id_table, - .probe = orinoco_pci_init_one, - .remove = __devexit_p(orinoco_pci_remove_one), - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson &" - " Jean Tourrilhes )"; -MODULE_AUTHOR("Pavel Roskin & David Gibson "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_pci_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_pci_driver); -} - -static void __exit orinoco_pci_exit(void) -{ - pci_unregister_driver(&orinoco_pci_driver); -} - -module_init(orinoco_pci_init); -module_exit(orinoco_pci_exit); - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco_pci.h deleted file mode 100644 index f4e5e06..0000000 --- a/drivers/net/wireless/orinoco_pci.h +++ /dev/null @@ -1,109 +0,0 @@ -/* orinoco_pci.h - * - * Common code for all Orinoco drivers for PCI devices, including - * both native PCI and PCMCIA-to-PCI bridges. - * - * Copyright (C) 2005, Pavel Roskin. - * See orinoco.c for license. - */ - -#ifndef _ORINOCO_PCI_H -#define _ORINOCO_PCI_H - -#include - -/* Driver specific data */ -struct orinoco_pci_card { - void __iomem *bridge_io; - void __iomem *attr_io; -}; - -#ifdef CONFIG_PM -static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: cannot lock hardware for suspend\n", - dev->name); - return err; - } - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: error %d bringing interface down " - "for suspend\n", dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - - orinoco_unlock(priv, &flags); - - free_irq(pdev->irq, dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int orinoco_pci_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - pci_set_power_state(pdev, 0); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - return err; - } - pci_restore_state(pdev); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); - if (err) { - printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", - dev->name); - pci_disable_device(pdev); - return -EBUSY; - } - - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: error %d re-initializing firmware " - "on resume\n", dev->name, err); - return err; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - - priv->hw_unavailable--; - - if (priv->open && (! priv->hw_unavailable)) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on resume\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} -#else -#define orinoco_pci_suspend NULL -#define orinoco_pci_resume NULL -#endif - -#endif /* _ORINOCO_PCI_H */ diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c deleted file mode 100644 index ef76185..0000000 --- a/drivers/net/wireless/orinoco_plx.c +++ /dev/null @@ -1,371 +0,0 @@ -/* orinoco_plx.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a PLX9052. - * - * Current maintainers are: - * Pavel Roskin - * and David Gibson - * - * (C) Copyright David Gibson, IBM Corp. 2001-2003. - * Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * Here's the general details on how the PLX9052 adapter works: - * - * - Two PCI I/O address spaces, one 0x80 long which contains the - * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA - * slot I/O address space. - * - * - One PCI memory address space, mapped to the PCMCIA attribute space - * (containing the CIS). - * - * Using the later, you can read through the CIS data to make sure the - * card is compatible with the driver. Keep in mind that the PCMCIA - * spec specifies the CIS as the lower 8 bits of each word read from - * the CIS, so to read the bytes of the CIS, read every other byte - * (0,2,4,...). Passing that test, you need to enable the I/O address - * space on the PCMCIA card via the PCMCIA COR register. This is the - * first byte following the CIS. In my case (which may not have any - * relation to what's on the PRISM2 cards), COR was at offset 0x800 - * within the PCI memory space. Write 0x41 to the COR register to - * enable I/O mode and to select level triggered interrupts. To - * confirm you actually succeeded, read the COR register back and make - * sure it actually got set to 0x41, in case you have an unexpected - * card inserted. - * - * Following that, you can treat the second PCI I/O address space (the - * one that's not 0x80 in length) as the PCMCIA I/O space. - * - * Note that in the Eumitcom's source for their drivers, they register - * the interrupt as edge triggered when registering it with the - * Windows kernel. I don't recall how to register edge triggered on - * Linux (if it can be done at all). But in some experimentation, I - * don't see much operational difference between using either - * interrupt mode. Don't mess with the interrupt mode in the COR - * register though, as the PLX9052 wants level triggers with the way - * the serial EEPROM configures it on the WL11000. - * - * There's some other little quirks related to timing that I bumped - * into, but I don't recall right now. Also, there's two variants of - * the WL11000 I've seen, revision A1 and T2. These seem to differ - * slightly in the timings configured in the wait-state generator in - * the PLX9052. There have also been some comments from Eumitcom that - * cards shouldn't be hot swapped, apparently due to risk of cooking - * the PLX9052. I'm unsure why they believe this, as I can't see - * anything in the design that would really cause a problem, except - * for crashing drivers not written to expect it. And having developed - * drivers for the WL11000, I'd say it's quite tricky to write code - * that will successfully deal with a hot unplug. Very odd things - * happen on the I/O side of things. But anyway, be warned. Despite - * that, I've hot-swapped a number of times during debugging and - * driver development for various reasons (stuck WAIT# line after the - * radio card's firmware locks up). - */ - -#define DRIVER_NAME "orinoco_plx" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define PLX_RESET_TIME (500) /* milliseconds */ - -#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ -#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_plx_cor_reset(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); - mdelay(1); - - iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int orinoco_plx_hw_init(struct orinoco_pci_card *card) -{ - int i; - u32 csr_reg; - static const u8 cis_magic[] = { - 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 - }; - - printk(KERN_DEBUG PFX "CIS: "); - for (i = 0; i < 16; i++) { - printk("%02X:", ioread8(card->attr_io + (i << 1))); - } - printk("\n"); - - /* Verify whether a supported PC card is present */ - /* FIXME: we probably need to be smarted about this */ - for (i = 0; i < sizeof(cis_magic); i++) { - if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { - printk(KERN_ERR PFX "The CIS value of Prism2 PC " - "card is unexpected\n"); - return -ENODEV; - } - } - - /* bjoern: We need to tell the card to enable interrupts, in - case the serial eprom didn't do this already. See the - PLX9052 data book, p8-1 and 8-24 for reference. */ - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - csr_reg |= PLX_INTCSR_INTEN; - iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); - csr_reg = ioread32(card->bridge_io + PLX_INTCSR); - if (!(csr_reg & PLX_INTCSR_INTEN)) { - printk(KERN_ERR PFX "Cannot enable interrupts\n"); - return -EIO; - } - } - - return 0; -} - -static int orinoco_plx_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - struct net_device *dev; - void __iomem *hermes_io, *attr_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - attr_io = pci_iomap(pdev, 2, 0); - if (!attr_io) { - printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); - err = -EIO; - goto fail_map_attr; - } - - hermes_io = pci_iomap(pdev, 3, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_plx_cor_reset, NULL); - if (!dev) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - priv = netdev_priv(dev); - card = priv->card; - card->bridge_io = bridge_io; - card->attr_io = attr_io; - SET_NETDEV_DEV(dev, &pdev->dev); - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_plx_hw_init(card); - if (err) { - printk(KERN_ERR PFX "Hardware initialization failed\n"); - goto fail; - } - - err = orinoco_plx_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = register_netdev(dev); - if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); - goto fail; - } - - pci_set_drvdata(pdev, dev); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); - - return 0; - - fail: - free_irq(pdev->irq, dev); - - fail_irq: - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, attr_io); - - fail_map_attr: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pci_card *card = priv->card; - - unregister_netdev(dev); - free_irq(pdev->irq, dev); - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->attr_io); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static struct pci_device_id orinoco_plx_id_table[] = { - {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ - {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ - {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ - {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, - Eumitcom PCI WL11000, - Addtron AWA-100 */ - {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ - {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ - {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ - {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ - {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by - Brendan W. McAdams */ - {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by - Damien Persohn */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); - -static struct pci_driver orinoco_plx_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_plx_id_table, - .probe = orinoco_plx_init_one, - .remove = __devexit_p(orinoco_plx_remove_one), - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson ," - " Daniel Barlow )"; -MODULE_AUTHOR("Daniel Barlow "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_plx_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_plx_driver); -} - -static void __exit orinoco_plx_exit(void) -{ - pci_unregister_driver(&orinoco_plx_driver); -} - -module_init(orinoco_plx_init); -module_exit(orinoco_plx_exit); - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c deleted file mode 100644 index ede24ec..0000000 --- a/drivers/net/wireless/orinoco_tmd.c +++ /dev/null @@ -1,248 +0,0 @@ -/* orinoco_tmd.c - * - * Driver for Prism II devices which would usually be driven by orinoco_cs, - * but are connected to the PCI bus by a TMD7160. - * - * Copyright (C) 2003 Joerg Dorchain - * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License version 2 (the "GPL"), in - * which case the provisions of the GPL are applicable instead of the - * above. If you wish to allow the use of your version of this file - * only under the terms of the GPL and not to allow others to use your - * version of this file under the MPL, indicate your decision by - * deleting the provisions above and replace them with the notice and - * other provisions required by the GPL. If you do not delete the - * provisions above, a recipient may use your version of this file - * under either the MPL or the GPL. - * - * The actual driving is done by orinoco.c, this is just resource - * allocation stuff. - * - * This driver is modeled after the orinoco_plx driver. The main - * difference is that the TMD chip has only IO port ranges and doesn't - * provide access to the PCMCIA attribute space. - * - * Pheecom sells cards with the TMD chip as "ASIC version" - */ - -#define DRIVER_NAME "orinoco_tmd" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" -#include "orinoco_pci.h" - -#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ -#define COR_RESET (0x80) /* reset bit in the COR register */ -#define TMD_RESET_TIME (500) /* milliseconds */ - -/* - * Do a soft reset of the card using the Configuration Option Register - */ -static int orinoco_tmd_cor_reset(struct orinoco_private *priv) -{ - hermes_t *hw = &priv->hw; - struct orinoco_pci_card *card = priv->card; - unsigned long timeout; - u16 reg; - - iowrite8(COR_VALUE | COR_RESET, card->bridge_io); - mdelay(1); - - iowrite8(COR_VALUE, card->bridge_io); - mdelay(1); - - /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + (TMD_RESET_TIME * HZ / 1000); - reg = hermes_read_regn(hw, CMD); - while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { - mdelay(1); - reg = hermes_read_regn(hw, CMD); - } - - /* Still busy? */ - if (reg & HERMES_CMD_BUSY) { - printk(KERN_ERR PFX "Busy timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - - -static int orinoco_tmd_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err; - struct orinoco_private *priv; - struct orinoco_pci_card *card; - struct net_device *dev; - void __iomem *hermes_io, *bridge_io; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR PFX "Cannot enable PCI device\n"); - return err; - } - - err = pci_request_regions(pdev, DRIVER_NAME); - if (err) { - printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); - goto fail_resources; - } - - bridge_io = pci_iomap(pdev, 1, 0); - if (!bridge_io) { - printk(KERN_ERR PFX "Cannot map bridge registers\n"); - err = -EIO; - goto fail_map_bridge; - } - - hermes_io = pci_iomap(pdev, 2, 0); - if (!hermes_io) { - printk(KERN_ERR PFX "Cannot map chipset registers\n"); - err = -EIO; - goto fail_map_hermes; - } - - /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_tmd_cor_reset, NULL); - if (!dev) { - printk(KERN_ERR PFX "Cannot allocate network device\n"); - err = -ENOMEM; - goto fail_alloc; - } - - priv = netdev_priv(dev); - card = priv->card; - card->bridge_io = bridge_io; - SET_NETDEV_DEV(dev, &pdev->dev); - - hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); - - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); - if (err) { - printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); - err = -EBUSY; - goto fail_irq; - } - - err = orinoco_tmd_cor_reset(priv); - if (err) { - printk(KERN_ERR PFX "Initial reset failed\n"); - goto fail; - } - - err = register_netdev(dev); - if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); - goto fail; - } - - pci_set_drvdata(pdev, dev); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); - - return 0; - - fail: - free_irq(pdev->irq, dev); - - fail_irq: - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - - fail_alloc: - pci_iounmap(pdev, hermes_io); - - fail_map_hermes: - pci_iounmap(pdev, bridge_io); - - fail_map_bridge: - pci_release_regions(pdev); - - fail_resources: - pci_disable_device(pdev); - - return err; -} - -static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pci_card *card = priv->card; - - unregister_netdev(dev); - free_irq(pdev->irq, dev); - pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); - pci_iounmap(pdev, priv->hw.iobase); - pci_iounmap(pdev, card->bridge_io); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static struct pci_device_id orinoco_tmd_id_table[] = { - {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table); - -static struct pci_driver orinoco_tmd_driver = { - .name = DRIVER_NAME, - .id_table = orinoco_tmd_id_table, - .probe = orinoco_tmd_init_one, - .remove = __devexit_p(orinoco_tmd_remove_one), - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, -}; - -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Joerg Dorchain )"; -MODULE_AUTHOR("Joerg Dorchain "); -MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); -MODULE_LICENSE("Dual MPL/GPL"); - -static int __init orinoco_tmd_init(void) -{ - printk(KERN_DEBUG "%s\n", version); - return pci_register_driver(&orinoco_tmd_driver); -} - -static void __exit orinoco_tmd_exit(void) -{ - pci_unregister_driver(&orinoco_tmd_driver); -} - -module_init(orinoco_tmd_init); -module_exit(orinoco_tmd_exit); - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c deleted file mode 100644 index 852789a..0000000 --- a/drivers/net/wireless/spectrum_cs.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as - * Symbol Wireless Networker LA4137, CompactFlash cards by Socket - * Communications and Intel PRO/Wireless 2011B. - * - * The driver implements Symbol firmware download. The rest is handled - * in hermes.c and orinoco.c. - * - * Utilities for downloading the Symbol firmware are available at - * http://sourceforge.net/projects/orinoco/ - * - * Copyright (C) 2002-2005 Pavel Roskin - * Portions based on orinoco_cs.c: - * Copyright (C) David Gibson, Linuxcare Australia - * Portions based on Spectrum24tDnld.c from original spectrum24 driver: - * Copyright (C) Symbol Technologies. - * - * See copyright notice in file orinoco.c. - */ - -#define DRIVER_NAME "spectrum_cs" -#define PFX DRIVER_NAME ": " - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "orinoco.h" - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Pavel Roskin "); -MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader"); -MODULE_LICENSE("Dual MPL/GPL"); - -/* Module parameters */ - -/* Some D-Link cards have buggy CIS. They do work at 5v properly, but - * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ -module_param(ignore_cis_vcc, int, 0); -MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -/* PCMCIA specific device information (goes in the card field of - * struct orinoco_private */ -struct orinoco_pccard { - struct pcmcia_device *p_dev; - dev_node_t node; -}; - -/********************************************************************/ -/* Function prototypes */ -/********************************************************************/ - -static int spectrum_cs_config(struct pcmcia_device *link); -static void spectrum_cs_release(struct pcmcia_device *link); - -/* Constants for the CISREG_CCSR register */ -#define HCR_RUN 0x07 /* run firmware after reset */ -#define HCR_IDLE 0x0E /* don't run firmware after reset */ -#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ - - -#define CS_CHECK(fn, ret) \ - do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - -/* - * Reset the card using configuration registers COR and CCSR. - * If IDLE is 1, stop the firmware, so that it can be safely rewritten. - */ -static int -spectrum_reset(struct pcmcia_device *link, int idle) -{ - int last_ret, last_fn; - conf_reg_t reg; - u_int save_cor; - - /* Doing it if hardware is gone is guaranteed crash */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - - /* Save original COR value */ - reg.Function = 0; - reg.Action = CS_READ; - reg.Offset = CISREG_COR; - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); - save_cor = reg.Value; - - /* Soft-Reset card */ - reg.Action = CS_WRITE; - reg.Offset = CISREG_COR; - reg.Value = (save_cor | COR_SOFT_RESET); - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); - udelay(1000); - - /* Read CCSR */ - reg.Action = CS_READ; - reg.Offset = CISREG_CCSR; - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); - - /* - * Start or stop the firmware. Memory width bit should be - * preserved from the value we've just read. - */ - reg.Action = CS_WRITE; - reg.Offset = CISREG_CCSR; - reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16); - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); - udelay(1000); - - /* Restore original COR configuration index */ - reg.Action = CS_WRITE; - reg.Offset = CISREG_COR; - reg.Value = (save_cor & ~COR_SOFT_RESET); - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); - udelay(1000); - return 0; - - cs_failed: - cs_error(link, last_fn, last_ret); - return -ENODEV; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -spectrum_cs_hard_reset(struct orinoco_private *priv) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - /* Soft reset using COR and HCR */ - spectrum_reset(link, 0); - - return 0; -} - -static int -spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) -{ - struct orinoco_pccard *card = priv->card; - struct pcmcia_device *link = card->p_dev; - - return spectrum_reset(link, idle); -} - -/********************************************************************/ -/* PCMCIA stuff */ -/********************************************************************/ - -/* - * This creates an "instance" of the driver, allocating local data - * structures for one device. The device is registered with Card - * Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a card - * insertion event. */ -static int -spectrum_cs_probe(struct pcmcia_device *link) -{ - struct net_device *dev; - struct orinoco_private *priv; - struct orinoco_pccard *card; - - dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), - spectrum_cs_hard_reset, - spectrum_cs_stop_firmware); - if (! dev) - return -ENOMEM; - priv = netdev_priv(dev); - card = priv->card; - - /* Link both structures together */ - card->p_dev = link; - link->priv = dev; - - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; - - /* General socket configuration defaults can go here. In this - * client, we assume very little, and rely on the CIS for - * almost everything. In most clients, many details (i.e., - * number, sizes, and attributes of IO windows) are fixed by - * the nature of the device, and can be hard-wired here. */ - link->conf.Attributes = 0; - link->conf.IntType = INT_MEMORY_AND_IO; - - return spectrum_cs_config(link); -} /* spectrum_cs_attach */ - -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ -static void spectrum_cs_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->dev_node) - unregister_netdev(dev); - - spectrum_cs_release(link); - - free_orinocodev(dev); -} /* spectrum_cs_detach */ - -/* - * spectrum_cs_config() is scheduled to run after a CARD_INSERTION - * event is received, to configure the PCMCIA socket, and to make the - * device available to the system. - */ - -static int spectrum_cs_config_check(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) -{ - if (cfg->index == 0) - goto next_entry; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); - if (!ignore_cis_vcc) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = - dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - p_dev->io.BasePort1 = io->win[0].base; - p_dev->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - p_dev->io.Attributes2 = p_dev->io.Attributes1; - p_dev->io.BasePort2 = io->win[1].base; - p_dev->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev, &p_dev->io) != 0) - goto next_entry; - } - return 0; - -next_entry: - pcmcia_disable_device(p_dev); - return -ENODEV; -}; - -static int -spectrum_cs_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - struct orinoco_pccard *card = priv->card; - hermes_t *hw = &priv->hw; - int last_fn, last_ret; - void __iomem *mem; - - /* - * In this loop, we scan the CIS for configuration table - * entries, each of which describes a valid card - * configuration, including voltage, IO window, memory window, - * and interrupt settings. - * - * We make no assumptions about the card to be configured: we - * use just the information available in the CIS. In an ideal - * world, this would work for any PCMCIA card, but it requires - * a complete and accurate CIS. In practice, a driver usually - * "knows" most of these things without consulting the CIS, - * and most client drivers will only use the CIS to fill in - * implementation-defined details. - */ - last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); - if (last_ret) { - if (!ignore_cis_vcc) - printk(KERN_ERR PFX "GetNextTuple(): No matching " - "CIS configuration. Maybe you need the " - "ignore_cis_vcc=1 parameter.\n"); - cs_error(link, RequestIO, last_ret); - goto failed; - } - - /* - * Allocate an interrupt line. Note that this does not assign - * a handler to the interrupt, unless the 'Handler' member of - * the irq structure is initialized. - */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ - mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); - if (!mem) - goto cs_failed; - - hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); - - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping, and putting the - * card and host interface into "Memory and IO" mode. - */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); - - /* Ok, we have the configuration, prepare to register the netdev */ - dev->base_addr = link->io.BasePort1; - dev->irq = link->irq.AssignedIRQ; - card->node.major = card->node.minor = 0; - - /* Reset card */ - if (spectrum_cs_hard_reset(priv) != 0) { - goto failed; - } - - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); - goto failed; - } - - /* At this point, the dev_node_t structure(s) needs to be - * initialized and arranged in a linked list at link->dev_node. */ - strcpy(card->node.dev_name, dev->name); - link->dev_node = &card->node; /* link->dev_node being non-NULL is also - used to indicate that the - net_device has been registered */ - - /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, - link->irq.AssignedIRQ, link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - - return 0; - - cs_failed: - cs_error(link, last_fn, last_ret); - - failed: - spectrum_cs_release(link); - return -ENODEV; -} /* spectrum_cs_config */ - -/* - * After a card is removed, spectrum_cs_release() will unregister the - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ -static void -spectrum_cs_release(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - - /* We're committed to taking the device away now, so mark the - * hardware as unavailable */ - spin_lock_irqsave(&priv->lock, flags); - priv->hw_unavailable++; - spin_unlock_irqrestore(&priv->lock, flags); - - pcmcia_disable_device(link); - if (priv->hw.iobase) - ioport_unmap(priv->hw.iobase); -} /* spectrum_cs_release */ - - -static int -spectrum_cs_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err = 0; - - /* Mark the device as stopped, to block IO until later */ - spin_lock_irqsave(&priv->lock, flags); - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - - spin_unlock_irqrestore(&priv->lock, flags); - - return err; -} - -static int -spectrum_cs_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); - - netif_device_attach(dev); - priv->hw_unavailable--; - schedule_work(&priv->reset_work); - - return 0; -} - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -/* Can't be declared "const" or the whole __initdata section will - * become const */ -static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION - " (Pavel Roskin ," - " David Gibson , et al)"; - -static struct pcmcia_device_id spectrum_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ - PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ - PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids); - -static struct pcmcia_driver orinoco_driver = { - .owner = THIS_MODULE, - .drv = { - .name = DRIVER_NAME, - }, - .probe = spectrum_cs_probe, - .remove = spectrum_cs_detach, - .suspend = spectrum_cs_suspend, - .resume = spectrum_cs_resume, - .id_table = spectrum_cs_ids, -}; - -static int __init -init_spectrum_cs(void) -{ - printk(KERN_DEBUG "%s\n", version); - - return pcmcia_register_driver(&orinoco_driver); -} - -static void __exit -exit_spectrum_cs(void) -{ - pcmcia_unregister_driver(&orinoco_driver); -} - -module_init(init_spectrum_cs); -module_exit(exit_spectrum_cs); -- cgit v1.1 From c4832467a5c8c2ae96d6dad882be4d4ab9eefad7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 09:40:44 -0700 Subject: rtl8187: Change TX power settings The latest vendor driver (rtl8187B_linux_26.1036.0708.2008) has a different CCK power setting code as compared with the Linux driver. Signed-off-by: Larry Finger Tested-by: Piter Punk Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_rtl8225.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index 38333b1..69030be 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -625,7 +625,7 @@ static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power]); + rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); msleep(1); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, -- cgit v1.1 From fb28ad35906af2f042c94e2f9c0f898ef9acfa37 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 10 Nov 2008 13:55:14 -0800 Subject: net: struct device - replace bus_id with dev_name(), dev_set_name() Acked-by: Marcel Holtmann Acked-by: Greg Kroah-Hartman Signed-off-by: Kay Sievers Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/defs.h | 2 +- drivers/net/wireless/orinoco/orinoco.c | 2 +- drivers/net/wireless/orinoco/orinoco_cs.c | 2 +- drivers/net/wireless/orinoco/spectrum_cs.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 076a636..2d4666f 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -79,7 +79,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args) #define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args) #define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args) -#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) +#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index f4ea08f..072be44 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -5987,7 +5987,7 @@ static void orinoco_get_drvinfo(struct net_device *dev, strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); if (dev->dev.parent) - strncpy(info->bus_info, dev->dev.parent->bus_id, + strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info) - 1); else snprintf(info->bus_info, sizeof(info->bus_info) - 1, diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 6fcf2bd..bf6a51d 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -308,7 +308,7 @@ orinoco_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); return 0; diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 852789a..0bae3dc 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -383,7 +383,7 @@ spectrum_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); -- cgit v1.1 From 9757d55652f98836b9a4cac307a01f8b0232dbd9 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 4 Nov 2008 18:25:27 +0530 Subject: ath9k: Fix compilation failure when RFKILL is enabled Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index fb50aa0..f830fe1 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -37,6 +37,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { 0 } }; +static void ath_detach(struct ath_softc *sc); + static int ath_get_channel(struct ath_softc *sc, struct ieee80211_channel *chan) { @@ -813,7 +815,7 @@ static int ath_start_rfkill_poll(struct ath_softc *sc) pci_iounmap(sc->pdev, sc->mem); pci_release_region(sc->pdev, 0); pci_disable_device(sc->pdev); - ieee80211_free_hw(hw); + ieee80211_free_hw(sc->hw); return -EIO; } else { sc->sc_flags |= SC_OP_RFKILL_REGISTERED; -- cgit v1.1 From 8f15ea42b64941001a401cf855a0869e24f3a845 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Wed, 12 Nov 2008 23:38:36 -0800 Subject: netdevice: safe convert to netdev_priv() #part-3 We have some reasons to kill netdev->priv: 1. netdev->priv is equal to netdev_priv(). 2. netdev_priv() wraps the calculation of netdev->priv's offset, obviously netdev_priv() is more flexible than netdev->priv. But we cann't kill netdev->priv, because so many drivers reference to it directly. This patch is a safe convert for netdev->priv to netdev_priv(netdev). Since all of the netdev->priv is only for read. But it is too big to be sent in one mail. I split it to 4 parts and make every part smaller than 100,000 bytes, which is max size allowed by vger. Signed-off-by: Wang Chen Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/ethtool.c | 12 ++++++------ drivers/net/wireless/libertas/persistcfg.c | 16 ++++++++-------- drivers/net/wireless/libertas/scan.c | 4 ++-- drivers/net/wireless/libertas/tx.c | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 688d60d..156f471 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -23,7 +23,7 @@ static const char * mesh_stat_strings[]= { static void lbs_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); snprintf(info->fw_version, 32, "%u.%u.%u.p%u", priv->fwrelease >> 24 & 0xff, @@ -47,7 +47,7 @@ static int lbs_ethtool_get_eeprom_len(struct net_device *dev) static int lbs_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct cmd_ds_802_11_eeprom_access cmd; int ret; @@ -76,7 +76,7 @@ out: static void lbs_ethtool_get_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct cmd_ds_mesh_access mesh_access; int ret; @@ -113,7 +113,7 @@ static void lbs_ethtool_get_stats(struct net_device *dev, static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); if (sset == ETH_SS_STATS && dev == priv->mesh_dev) return MESH_STATS_NUM; @@ -143,7 +143,7 @@ static void lbs_ethtool_get_strings(struct net_device *dev, static void lbs_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); if (priv->wol_criteria == 0xffffffff) { /* Interface driver didn't configure wake */ @@ -166,7 +166,7 @@ static void lbs_ethtool_get_wol(struct net_device *dev, static int lbs_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); uint32_t criteria = 0; if (priv->wol_criteria == 0xffffffff && wol->wolopts) diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 56e2401..d42b7a5a 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -18,7 +18,7 @@ static int mesh_get_default_parameters(struct device *dev, struct mrvl_mesh_defaults *defs) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; int ret; @@ -57,7 +57,7 @@ static ssize_t bootflag_get(struct device *dev, static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -100,7 +100,7 @@ static ssize_t boottime_get(struct device *dev, static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -152,7 +152,7 @@ static ssize_t channel_get(struct device *dev, static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -210,7 +210,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); int len; int ret; @@ -269,7 +269,7 @@ static ssize_t protocol_id_set(struct device *dev, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; @@ -323,7 +323,7 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; @@ -377,7 +377,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 93f7476..57f6c12 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -945,7 +945,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { DECLARE_SSID_BUF(ssid); - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -1008,7 +1008,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { #define SCAN_ITEM_SIZE 128 - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int err = 0; char *ev = extra; char *stop = ev + dwrq->length; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index a4972fe..dac4626 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -60,7 +60,7 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; -- cgit v1.1 From 524ad0a79126efabf58d0a49eace6155ab5b4549 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Wed, 12 Nov 2008 23:39:10 -0800 Subject: netdevice: safe convert to netdev_priv() #part-4 We have some reasons to kill netdev->priv: 1. netdev->priv is equal to netdev_priv(). 2. netdev_priv() wraps the calculation of netdev->priv's offset, obviously netdev_priv() is more flexible than netdev->priv. But we cann't kill netdev->priv, because so many drivers reference to it directly. This patch is a safe convert for netdev->priv to netdev_priv(netdev). Since all of the netdev->priv is only for read. But it is too big to be sent in one mail. I split it to 4 parts and make every part smaller than 100,000 bytes, which is max size allowed by vger. Signed-off-by: Wang Chen Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/wext.c | 72 ++++++++++++++--------------- drivers/net/wireless/rndis_wlan.c | 62 ++++++++++++------------- drivers/net/wireless/wavelan.c | 88 ++++++++++++++++++------------------ 3 files changed, 110 insertions(+), 112 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index fe7498f..c6102e0 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -163,7 +163,7 @@ static int lbs_get_name(struct net_device *dev, struct iw_request_info *info, static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; lbs_deb_enter(LBS_DEB_WEXT); @@ -189,7 +189,7 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -207,7 +207,7 @@ static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -231,7 +231,7 @@ static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -248,7 +248,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -273,7 +273,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); @@ -293,7 +293,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -315,7 +315,7 @@ out: static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u32 val = vwrq->value; @@ -336,7 +336,7 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -359,7 +359,7 @@ out: static int lbs_get_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -385,7 +385,7 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); s16 curlevel = 0; int ret = 0; @@ -418,7 +418,7 @@ out: static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 slimit = 0, llimit = 0; @@ -466,7 +466,7 @@ out: static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -542,7 +542,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int i, j; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_range *range = (struct iw_range *)extra; struct chan_freq_power *cfp; u8 rates[MAX_RATES + 1]; @@ -708,7 +708,7 @@ out: static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -758,7 +758,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -781,7 +781,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) EXCELLENT = 95, PERFECT = 100 }; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u32 rssi_qual; u32 tx_qual; u32 quality = 0; @@ -886,7 +886,7 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { int ret = -EINVAL; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; struct assoc_request * assoc_req; @@ -943,7 +943,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; int ret = -EINVAL; @@ -994,7 +994,7 @@ out: static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u8 new_rate = 0; int ret = -EINVAL; u8 rates[MAX_RATES + 1]; @@ -1054,7 +1054,7 @@ out: static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1079,7 +1079,7 @@ static int lbs_set_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); @@ -1124,7 +1124,7 @@ static int lbs_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, u8 * extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; lbs_deb_enter(LBS_DEB_WEXT); @@ -1319,7 +1319,7 @@ static int lbs_set_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; u16 is_default = 0, index = 0, set_tx_key = 0; @@ -1395,7 +1395,7 @@ static int lbs_get_encodeext(struct net_device *dev, char *extra) { int ret = -EINVAL; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int index, max_key_len; @@ -1501,7 +1501,7 @@ static int lbs_set_encodeext(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int alg = ext->alg; struct assoc_request * assoc_req; @@ -1639,7 +1639,7 @@ static int lbs_set_genie(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; struct assoc_request * assoc_req; @@ -1685,7 +1685,7 @@ static int lbs_get_genie(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1713,7 +1713,7 @@ static int lbs_set_auth(struct net_device *dev, struct iw_param *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; int ret = 0; int updated = 0; @@ -1816,7 +1816,7 @@ static int lbs_get_auth(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1857,7 +1857,7 @@ static int lbs_set_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; + struct lbs_private *priv = netdev_priv(dev); s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); @@ -1936,7 +1936,7 @@ out: static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1971,7 +1971,7 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u8 ssid[IW_ESSID_MAX_SIZE]; u8 ssid_len = 0; @@ -2040,7 +2040,7 @@ static int lbs_mesh_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -2058,7 +2058,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -2102,7 +2102,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; int ret = 0; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index a1eeb48..607ce9f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1104,7 +1104,7 @@ static int rndis_iw_get_range(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_range *range = (struct iw_range *)extra; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int len, ret, i, j, num, has_80211g_rates; u8 rates[8]; @@ -1210,7 +1210,7 @@ static int rndis_iw_get_range(struct net_device *dev, static int rndis_iw_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); strcpy(wrqu->name, priv->name); @@ -1223,7 +1223,7 @@ static int rndis_iw_set_essid(struct net_device *dev, { struct ndis_80211_ssid ssid; int length = wrqu->essid.length; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'", wrqu->essid.flags, wrqu->essid.length, essid); @@ -1250,7 +1250,7 @@ static int rndis_iw_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { struct ndis_80211_ssid ssid; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); int ret; ret = get_essid(usbdev, &ssid); @@ -1273,7 +1273,7 @@ static int rndis_iw_get_essid(struct net_device *dev, static int rndis_iw_get_bssid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); unsigned char bssid[ETH_ALEN]; int ret; @@ -1294,7 +1294,7 @@ static int rndis_iw_get_bssid(struct net_device *dev, static int rndis_iw_set_bssid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; int ret; @@ -1316,7 +1316,7 @@ static int rndis_iw_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret = -ENOTSUPP; @@ -1397,7 +1397,7 @@ static int rndis_iw_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { @@ -1429,7 +1429,7 @@ static int rndis_iw_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (priv->infra_mode) { @@ -1452,7 +1452,7 @@ static int rndis_iw_get_mode(struct net_device *dev, static int rndis_iw_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); int mode; devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode); @@ -1477,7 +1477,7 @@ static int rndis_iw_set_mode(struct net_device *dev, static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1540,7 +1540,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct ndis_80211_key ndis_key; int keyidx, ret; @@ -1625,7 +1625,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, static int rndis_iw_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); union iwreq_data evt; int ret = -EINVAL; __le32 tmp; @@ -1650,7 +1650,7 @@ static char *rndis_translate_scan(struct net_device *dev, struct ndis_80211_bssid_ex *bssid) { #ifdef DEBUG - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); #endif u8 *ie; char *current_val; @@ -1773,7 +1773,7 @@ static char *rndis_translate_scan(struct net_device *dev, static int rndis_iw_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); void *buf = NULL; char *cev = extra; struct ndis_80211_bssid_list_ex *bssid_list; @@ -1819,7 +1819,7 @@ out: static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret = 0; @@ -1853,7 +1853,7 @@ static int rndis_iw_set_genie(struct net_device *dev, static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1876,7 +1876,7 @@ static int rndis_iw_get_genie(struct net_device *dev, static int rndis_iw_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; devdbg(usbdev, "SIOCSIWRTS"); @@ -1889,7 +1889,7 @@ static int rndis_iw_set_rts(struct net_device *dev, static int rndis_iw_get_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int len, ret; @@ -1910,7 +1910,7 @@ static int rndis_iw_get_rts(struct net_device *dev, static int rndis_iw_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; devdbg(usbdev, "SIOCSIWFRAG"); @@ -1924,7 +1924,7 @@ static int rndis_iw_set_frag(struct net_device *dev, static int rndis_iw_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int len, ret; @@ -1944,7 +1944,7 @@ static int rndis_iw_get_frag(struct net_device *dev, static int rndis_iw_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); devdbg(usbdev, "SIOCSIWNICK"); @@ -1961,7 +1961,7 @@ static int rndis_iw_set_nick(struct net_device *dev, static int rndis_iw_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); wrqu->data.flags = 1; @@ -1977,7 +1977,7 @@ static int rndis_iw_get_nick(struct net_device *dev, static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct ndis_80211_conf config; unsigned int dsconfig; int len, ret; @@ -2008,7 +2008,7 @@ static int rndis_iw_set_freq(struct net_device *dev, static int rndis_iw_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct ndis_80211_conf config; int len, ret; @@ -2025,7 +2025,7 @@ static int rndis_iw_get_freq(struct net_device *dev, static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power; int ret = 0, len; @@ -2059,7 +2059,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power = 0; int ret = 0; @@ -2111,7 +2111,7 @@ static int rndis_iw_set_txpower(struct net_device *dev, static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int ret, len; @@ -2129,7 +2129,7 @@ static int rndis_iw_get_rate(struct net_device *dev, static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -2154,7 +2154,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); unsigned long flags; @@ -2284,7 +2284,7 @@ get_bssid: static void rndis_wext_set_multicast_list(struct net_device *dev) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 1ac37e8..8326793 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -134,7 +134,7 @@ static inline void wv_16_on(unsigned long ioaddr, u16 hacr) */ static inline void wv_ints_off(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; lp->hacr &= ~HACR_INTRON; @@ -148,7 +148,7 @@ static inline void wv_ints_off(struct net_device * dev) */ static inline void wv_ints_on(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; lp->hacr |= HACR_INTRON; @@ -526,7 +526,7 @@ static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) */ static void wv_ack(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cs; int i; @@ -568,7 +568,7 @@ static void wv_ack(struct net_device * dev) */ static int wv_synchronous_cmd(struct net_device * dev, const char *str) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cmd; ach_t cb; @@ -824,7 +824,7 @@ if (lp->tx_n_in_use > 0) */ static void wv_82586_reconfig(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; /* Arm the flag, will be cleard in wv_82586_config() */ @@ -922,7 +922,7 @@ static void wv_psa_show(psa_t * p) static void wv_mmc_show(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); mmr_t m; /* Basic check */ @@ -1102,8 +1102,6 @@ static void wv_scb_show(unsigned long ioaddr) */ static void wv_ru_show(struct net_device * dev) { - /* net_local *lp = (net_local *) dev->priv; */ - printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n"); printk(KERN_DEBUG "ru:"); @@ -1148,7 +1146,7 @@ static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p */ static void wv_cu_show(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned int i; u16 p; @@ -1190,7 +1188,7 @@ static void wv_local_show(struct net_device * dev) { net_local *lp; - lp = (net_local *) dev->priv; + lp = netdev_priv(dev); printk(KERN_DEBUG "local:"); printk(" tx_n_in_use=%d,", lp->tx_n_in_use); @@ -1250,7 +1248,7 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ static void wv_init_info(struct net_device * dev) { short ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); psa_t psa; /* Read the parameter storage area */ @@ -1360,7 +1358,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev) printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); #endif - return (&((net_local *) dev->priv)->stats); + return &((net_local *)netdev_priv(dev))->stats; } /*------------------------------------------------------------------*/ @@ -1373,7 +1371,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev) */ static void wavelan_set_multicast_list(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", @@ -1707,7 +1705,7 @@ static inline void wl_spy_gather(struct net_device * dev, */ static inline void wl_his_gather(struct net_device * dev, u8 * stats) { /* Statistics to gather */ - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); u8 level = stats[0] & MMR_SIGNAL_LVL; int i; @@ -1744,7 +1742,7 @@ static int wavelan_set_nwid(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; mm_t m; unsigned long flags; @@ -1803,7 +1801,7 @@ static int wavelan_get_nwid(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1835,7 +1833,7 @@ static int wavelan_set_freq(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ unsigned long flags; int ret; @@ -1865,7 +1863,7 @@ static int wavelan_get_freq(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1911,7 +1909,7 @@ static int wavelan_set_sens(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1947,7 +1945,7 @@ static int wavelan_get_sens(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1978,7 +1976,7 @@ static int wavelan_set_encode(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ unsigned long flags; psa_t psa; int ret = 0; @@ -2048,7 +2046,7 @@ static int wavelan_get_encode(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -2095,7 +2093,7 @@ static int wavelan_get_range(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ struct iw_range *range = (struct iw_range *) extra; unsigned long flags; int ret = 0; @@ -2170,7 +2168,7 @@ static int wavelan_set_qthr(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; @@ -2202,7 +2200,7 @@ static int wavelan_get_qthr(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; @@ -2230,7 +2228,7 @@ static int wavelan_set_histo(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ /* Check the number of intervals. */ if (wrqu->data.length > 16) { @@ -2273,7 +2271,7 @@ static int wavelan_get_histo(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ /* Set the number of intervals. */ wrqu->data.length = lp->his_number; @@ -2377,7 +2375,7 @@ static const struct iw_handler_def wavelan_handler_def = static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); mmr_t m; iw_stats *wstats; unsigned long flags; @@ -2452,7 +2450,7 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) static void wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; struct sk_buff *skb; @@ -2546,7 +2544,7 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) static void wv_receive(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); fd_t fd; rbd_t rbd; int nreaped = 0; @@ -2728,7 +2726,7 @@ static void wv_receive(struct net_device * dev) */ static int wv_packet_write(struct net_device * dev, void *buf, short length) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned short txblock; unsigned short txpred; @@ -2859,7 +2857,7 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length) */ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; char data[ETH_ZLEN]; @@ -2927,7 +2925,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) static int wv_mmc_init(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); psa_t psa; mmw_t m; int configured; @@ -3098,7 +3096,7 @@ static int wv_mmc_init(struct net_device * dev) */ static int wv_ru_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cs; fd_t fd; @@ -3190,7 +3188,7 @@ static int wv_ru_start(struct net_device * dev) */ static int wv_cu_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int i; u16 txblock; @@ -3291,7 +3289,7 @@ static int wv_cu_start(struct net_device * dev) */ static int wv_82586_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; scp_t scp; /* system configuration pointer */ iscp_t iscp; /* intermediate scp */ @@ -3423,7 +3421,7 @@ static int wv_82586_start(struct net_device * dev) */ static void wv_82586_config(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned short txblock; unsigned short txpred; @@ -3599,7 +3597,7 @@ static void wv_82586_config(struct net_device * dev) */ static void wv_82586_stop(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cmd; @@ -3636,7 +3634,7 @@ static void wv_82586_stop(struct net_device * dev) */ static int wv_hw_reset(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; #ifdef DEBUG_CONFIG_TRACE @@ -3737,7 +3735,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id) printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); #endif - lp = (net_local *) dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; #ifdef DEBUG_INTERRUPT_INFO @@ -3880,7 +3878,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id) */ static void wavelan_watchdog(struct net_device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; unsigned long flags; unsigned int nreaped; @@ -3960,7 +3958,7 @@ static void wavelan_watchdog(struct net_device * dev) */ static int wavelan_open(struct net_device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE @@ -4015,7 +4013,7 @@ static int wavelan_open(struct net_device * dev) */ static int wavelan_close(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE @@ -4114,8 +4112,8 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) dev->if_port = 0; /* Initialize device structures */ - memset(dev->priv, 0, sizeof(net_local)); - lp = (net_local *) dev->priv; + memset(netdev_priv(dev), 0, sizeof(net_local)); + lp = netdev_priv(dev); /* Back link to the device structure. */ lp->dev = dev; -- cgit v1.1 From 3d29b0c33d431ecc69ec778f8c236d382f59a85f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 31 Oct 2008 14:13:12 -0400 Subject: netdevice zd1201: Convert directly reference of netdev->priv to netdev_priv() We have some reasons to kill netdev->priv: 1. netdev->priv is equal to netdev_priv(). 2. netdev_priv() wraps the calculation of netdev->priv's offset, obviously netdev_priv() is more flexible than netdev->priv. But we cann't kill netdev->priv, because so many drivers reference to it directly. OK, becasue Dave S. Miller said, "every direct netdev->priv usage is a bug", and I want to kill netdev->priv later, I decided to convert all the direct reference of netdev->priv first. (Original patch posted by Wang Chen w/ above changelog but using dev->ml_priv. That doesn't seem appropriate to me for this driver, so I've revamped it to use netdev_priv() instead. -- JWL) Reviewed-by: Wang Chen Signed-off-by: John W. Linville --- drivers/net/wireless/zd1201.c | 115 ++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 1134e2f..3404807 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -743,7 +743,7 @@ static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) static int zd1201_net_open(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); /* Start MAC with wildcard if no essid set */ if (!zd->mac_enabled) @@ -781,7 +781,7 @@ static int zd1201_net_stop(struct net_device *dev) */ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char *txbuf = zd->txdata; int txbuflen, pad = 0, err; struct urb *urb = zd->tx_urb; @@ -831,7 +831,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static void zd1201_tx_timeout(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (!zd) return; @@ -846,7 +846,7 @@ static void zd1201_tx_timeout(struct net_device *dev) static int zd1201_set_mac_address(struct net_device *dev, void *p) { struct sockaddr *addr = p; - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; if (!zd) @@ -863,21 +863,21 @@ static int zd1201_set_mac_address(struct net_device *dev, void *p) static struct net_device_stats *zd1201_get_stats(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return &zd->stats; } static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return &zd->iwstats; } static void zd1201_set_multicast(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); struct dev_mc_list *mc = dev->mc_list; unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; int i; @@ -897,7 +897,7 @@ static void zd1201_set_multicast(struct net_device *dev) static int zd1201_config_commit(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return zd1201_mac_reset(zd); } @@ -912,7 +912,7 @@ static int zd1201_get_name(struct net_device *dev, static int zd1201_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short channel = 0; int err; @@ -937,7 +937,7 @@ static int zd1201_set_freq(struct net_device *dev, static int zd1201_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short channel; int err; @@ -953,7 +953,7 @@ static int zd1201_get_freq(struct net_device *dev, static int zd1201_set_mode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short porttype, monitor = 0; unsigned char buffer[IW_ESSID_MAX_SIZE+2]; int err; @@ -1015,7 +1015,7 @@ static int zd1201_set_mode(struct net_device *dev, static int zd1201_get_mode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short porttype; int err; @@ -1091,7 +1091,7 @@ static int zd1201_get_range(struct net_device *dev, static int zd1201_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char buffer[6]; if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { @@ -1119,7 +1119,7 @@ static int zd1201_set_scan(struct net_device *dev, static int zd1201_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err, i, j, enabled_save; struct iw_event iwe; char *cev = extra; @@ -1211,7 +1211,7 @@ static int zd1201_get_scan(struct net_device *dev, static int zd1201_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (data->length > IW_ESSID_MAX_SIZE) return -EINVAL; @@ -1226,7 +1226,7 @@ static int zd1201_set_essid(struct net_device *dev, static int zd1201_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); memcpy(essid, zd->essid, zd->essidlen); data->flags = 1; @@ -1247,7 +1247,7 @@ static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, static int zd1201_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rate; int err; @@ -1280,7 +1280,7 @@ static int zd1201_set_rate(struct net_device *dev, static int zd1201_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rate; int err; @@ -1313,7 +1313,7 @@ static int zd1201_get_rate(struct net_device *dev, static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; short val = rts->value; @@ -1333,7 +1333,7 @@ static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rtst; int err; @@ -1350,7 +1350,7 @@ static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; short val = frag->value; @@ -1371,7 +1371,7 @@ static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short fragt; int err; @@ -1400,7 +1400,7 @@ static int zd1201_get_retry(struct net_device *dev, static int zd1201_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short i; int err, rid; @@ -1457,7 +1457,7 @@ static int zd1201_set_encode(struct net_device *dev, static int zd1201_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short i; int err; @@ -1490,7 +1490,7 @@ static int zd1201_get_encode(struct net_device *dev, static int zd1201_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short enabled, duration, level; int err; @@ -1529,7 +1529,7 @@ out: static int zd1201_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short enabled, level, duration; int err; @@ -1616,7 +1616,7 @@ static const iw_handler zd1201_iw_handler[] = static int zd1201_set_hostauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (!zd->ap) return -EOPNOTSUPP; @@ -1627,7 +1627,7 @@ static int zd1201_set_hostauth(struct net_device *dev, static int zd1201_get_hostauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short hostauth; int err; @@ -1646,7 +1646,7 @@ static int zd1201_get_hostauth(struct net_device *dev, static int zd1201_auth_sta(struct net_device *dev, struct iw_request_info *info, struct sockaddr *sta, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char buffer[10]; if (!zd->ap) @@ -1662,7 +1662,7 @@ static int zd1201_auth_sta(struct net_device *dev, static int zd1201_set_maxassoc(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; if (!zd->ap) @@ -1677,7 +1677,7 @@ static int zd1201_set_maxassoc(struct net_device *dev, static int zd1201_get_maxassoc(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short maxassoc; int err; @@ -1729,6 +1729,7 @@ static int zd1201_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct zd1201 *zd; + struct net_device *dev; struct usb_device *usb; int err; short porttype; @@ -1736,9 +1737,12 @@ static int zd1201_probe(struct usb_interface *interface, usb = interface_to_usbdev(interface); - zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL); - if (!zd) + dev = alloc_etherdev(sizeof(*zd)); + if (!dev) return -ENOMEM; + zd = netdev_priv(dev); + zd->dev = dev; + zd->ap = ap; zd->usb = usb; zd->removed = 0; @@ -1773,34 +1777,29 @@ static int zd1201_probe(struct usb_interface *interface, if (err) goto err_start; - zd->dev = alloc_etherdev(0); - if (!zd->dev) - goto err_start; - - zd->dev->priv = zd; - zd->dev->open = zd1201_net_open; - zd->dev->stop = zd1201_net_stop; - zd->dev->get_stats = zd1201_get_stats; - zd->dev->wireless_handlers = + dev->open = zd1201_net_open; + dev->stop = zd1201_net_stop; + dev->get_stats = zd1201_get_stats; + dev->wireless_handlers = (struct iw_handler_def *)&zd1201_iw_handlers; - zd->dev->hard_start_xmit = zd1201_hard_start_xmit; - zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - zd->dev->tx_timeout = zd1201_tx_timeout; - zd->dev->set_multicast_list = zd1201_set_multicast; - zd->dev->set_mac_address = zd1201_set_mac_address; - strcpy(zd->dev->name, "wlan%d"); + dev->hard_start_xmit = zd1201_hard_start_xmit; + dev->watchdog_timeo = ZD1201_TX_TIMEOUT; + dev->tx_timeout = zd1201_tx_timeout; + dev->set_multicast_list = zd1201_set_multicast; + dev->set_mac_address = zd1201_set_mac_address; + strcpy(dev->name, "wlan%d"); err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len); + dev->dev_addr, dev->addr_len); if (err) - goto err_net; + goto err_start; /* Set wildcard essid to match zd->essid */ *(__le16 *)buf = cpu_to_le16(0); err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, IW_ESSID_MAX_SIZE+2, 1); if (err) - goto err_net; + goto err_start; if (zd->ap) porttype = ZD1201_PORTTYPE_AP; @@ -1808,30 +1807,28 @@ static int zd1201_probe(struct usb_interface *interface, porttype = ZD1201_PORTTYPE_BSS; err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); if (err) - goto err_net; + goto err_start; - SET_NETDEV_DEV(zd->dev, &usb->dev); + SET_NETDEV_DEV(dev, &usb->dev); - err = register_netdev(zd->dev); + err = register_netdev(dev); if (err) - goto err_net; + goto err_start; dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - zd->dev->name); + dev->name); usb_set_intfdata(interface, zd); zd1201_enable(zd); /* zd1201 likes to startup enabled, */ zd1201_disable(zd); /* interfering with all the wifis in range */ return 0; -err_net: - free_netdev(zd->dev); err_start: /* Leave the device in reset state */ zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); err_zd: usb_free_urb(zd->tx_urb); usb_free_urb(zd->rx_urb); - kfree(zd); + free_netdev(dev); return err; } -- cgit v1.1 From 50da3ead624d46f1b9f1007a184691bbb841eba7 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 10 Nov 2008 13:59:18 -0500 Subject: ipw2100, ipw2200: select LIB80211 Otherwise some configs can result in missing print_ssid... Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 42afaed..35dbc89 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -128,6 +128,7 @@ config IPW2100 depends on PCI && WLAN_80211 select WIRELESS_EXT select FW_LOADER + select LIB80211 select IEEE80211 ---help--- A driver for the Intel PRO/Wireless 2100 Network @@ -186,6 +187,7 @@ config IPW2200 depends on PCI && WLAN_80211 select WIRELESS_EXT select FW_LOADER + select LIB80211 select IEEE80211 ---help--- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network -- cgit v1.1 From 582c1b538fb47a2d6a41dbdadb031086c49446c1 Mon Sep 17 00:00:00 2001 From: Anna Neal Date: Mon, 20 Oct 2008 16:46:56 -0700 Subject: libertas: Fine grained configuration of wake-on-lan. Based on a patch from Shailendra Govardhan . This patch allows implementation of more specific wake-on-lan rules than those of ethtool. Please note that only firmware 5.110.22.p20 and above supports this feature. This patch only implements the driver/firmware interface, not the userspace/driver interface. Signed-off-by: Anna Neal Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 18 +++++++++++++++--- drivers/net/wireless/libertas/cmd.h | 3 ++- drivers/net/wireless/libertas/defs.h | 12 ++++++++++++ drivers/net/wireless/libertas/ethtool.c | 2 +- drivers/net/wireless/libertas/host.h | 8 ++++++++ drivers/net/wireless/libertas/hostcmd.h | 26 +++++++++++++++++++++++++- drivers/net/wireless/libertas/if_usb.c | 3 ++- 7 files changed, 65 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 957fd5a..639dd02 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -159,7 +159,8 @@ out: return ret; } -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config) { struct cmd_ds_host_sleep cmd_config; int ret; @@ -169,10 +170,21 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) cmd_config.gpio = priv->wol_gpio; cmd_config.gap = priv->wol_gap; + if (p_wol_config != NULL) + memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config, + sizeof(struct wol_config)); + else + cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE; + ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config); if (!ret) { - lbs_deb_cmd("Set WOL criteria to %x\n", criteria); - priv->wol_criteria = criteria; + if (criteria) { + lbs_deb_cmd("Set WOL criteria to %x\n", criteria); + priv->wol_criteria = criteria; + } else + memcpy((uint8_t *) p_wol_config, + (uint8_t *)&cmd_config.wol_conf, + sizeof(struct wol_config)); } else { lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 36be4c9..392e578 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -56,7 +56,8 @@ int lbs_mesh_config_send(struct lbs_private *priv, uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config); int lbs_suspend(struct lbs_private *priv); void lbs_resume(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 2d4666f..c364e4c0 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -149,6 +149,18 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define EHS_WAKE_ON_MAC_EVENT 0x0004 #define EHS_WAKE_ON_MULTICAST_DATA 0x0008 #define EHS_REMOVE_WAKEUP 0xFFFFFFFF +/* Wake rules for Host_Sleep_CFG command */ +#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS 0x00 +#define WOL_RULE_NET_TYPE_MESH 0x10 +#define WOL_RULE_ADDR_TYPE_BCAST 0x01 +#define WOL_RULE_ADDR_TYPE_MCAST 0x08 +#define WOL_RULE_ADDR_TYPE_UCAST 0x02 +#define WOL_RULE_OP_AND 0x01 +#define WOL_RULE_OP_OR 0x02 +#define WOL_RULE_OP_INVALID 0xFF +#define WOL_RESULT_VALID_CMD 0 +#define WOL_RESULT_NOSPC_ERR 1 +#define WOL_RESULT_EEXIST_ERR 2 /** Misc constants */ /* This section defines 802.11 specific contants */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 156f471..61d2f50 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -180,7 +180,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev, if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA; if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT; - return lbs_host_sleep_cfg(priv, criteria); + return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); } struct ethtool_ops lbs_ethtool_ops = { diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 5004d76..a17b778 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -220,6 +220,14 @@ enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_TIME, }; +/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */ +enum cmd_wol_cfg_opts { + CMD_ACT_ACTION_NONE = 0, + CMD_ACT_SET_WOL_RULE, + CMD_ACT_GET_WOL_RULE, + CMD_ACT_RESET_WOL_RULE, +}; + /* Define action or option for CMD_MESH_ACCESS */ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_TTL = 1, diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d9f9a12..e173b1b 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -580,13 +580,37 @@ struct MrvlIEtype_keyParamSet { u8 key[32]; }; +#define MAX_WOL_RULES 16 + +struct host_wol_rule { + uint8_t rule_no; + uint8_t rule_ops; + __le16 sig_offset; + __le16 sig_length; + __le16 reserve; + __be32 sig_mask; + __be32 signature; +}; + +struct wol_config { + uint8_t action; + uint8_t pattern; + uint8_t no_rules_in_cmd; + uint8_t result; + struct host_wol_rule rule[MAX_WOL_RULES]; +}; + + struct cmd_ds_host_sleep { struct cmd_header hdr; __le32 criteria; uint8_t gpio; - uint8_t gap; + uint16_t gap; + struct wol_config wol_conf; } __attribute__ ((packed)); + + struct cmd_ds_802_11_key_material { struct cmd_header hdr; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cafbccb..fcd3fe6 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -178,7 +178,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv) priv->wol_gpio = 2; /* Wake via GPIO2... */ priv->wol_gap = 20; /* ... after 20ms */ - lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA); + lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA, + (struct wol_config *) NULL); wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); -- cgit v1.1 From 55b3961953494c340b3625486f484af8ded31dd7 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Fri, 31 Oct 2008 23:23:35 -0700 Subject: mac80211_hwsim: enable Mesh Point operation Initial mesh support: add Mesh Point to supported interfaces mask and allow hwsim to send beacons in mesh mode. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b9230da..d8b5cf3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -368,7 +368,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, hwsim_check_magic(vif); - if (vif->type != NL80211_IFTYPE_AP) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_MESH_POINT) return; skb = ieee80211_beacon_get(hw, vif); @@ -774,7 +775,8 @@ static int __init init_mac80211_hwsim(void) hw->queues = 4; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); hw->ampdu_queues = 1; /* ask mac80211 to reserve space for magic */ -- cgit v1.1 From 1c740ed2210a0d124674a477ea538468aba47810 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 17:19:31 -0700 Subject: Move all rtl818x files to a common directory. This change improves the maintainability of these drivers. No functionality is changed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/Makefile | 8 +- drivers/net/wireless/rtl8180.h | 120 --- drivers/net/wireless/rtl8180_dev.c | 1081 -------------------- drivers/net/wireless/rtl8180_grf5101.c | 180 ---- drivers/net/wireless/rtl8180_grf5101.h | 28 - drivers/net/wireless/rtl8180_max2820.c | 152 --- drivers/net/wireless/rtl8180_max2820.h | 28 - drivers/net/wireless/rtl8180_rtl8225.c | 780 -------------- drivers/net/wireless/rtl8180_rtl8225.h | 23 - drivers/net/wireless/rtl8180_sa2400.c | 202 ---- drivers/net/wireless/rtl8180_sa2400.h | 36 - drivers/net/wireless/rtl8187.h | 220 ---- drivers/net/wireless/rtl8187_dev.c | 1298 ------------------------ drivers/net/wireless/rtl8187_rtl8225.c | 977 ------------------ drivers/net/wireless/rtl8187_rtl8225.h | 44 - drivers/net/wireless/rtl818x.h | 231 ----- drivers/net/wireless/rtl818x/Makefile | 7 + drivers/net/wireless/rtl818x/rtl8180.h | 120 +++ drivers/net/wireless/rtl818x/rtl8180_dev.c | 1081 ++++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8180_grf5101.c | 180 ++++ drivers/net/wireless/rtl818x/rtl8180_grf5101.h | 28 + drivers/net/wireless/rtl818x/rtl8180_max2820.c | 152 +++ drivers/net/wireless/rtl818x/rtl8180_max2820.h | 28 + drivers/net/wireless/rtl818x/rtl8180_rtl8225.c | 780 ++++++++++++++ drivers/net/wireless/rtl818x/rtl8180_rtl8225.h | 23 + drivers/net/wireless/rtl818x/rtl8180_sa2400.c | 202 ++++ drivers/net/wireless/rtl818x/rtl8180_sa2400.h | 36 + drivers/net/wireless/rtl818x/rtl8187.h | 220 ++++ drivers/net/wireless/rtl818x/rtl8187_dev.c | 1298 ++++++++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8187_rtl8225.c | 977 ++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8187_rtl8225.h | 44 + drivers/net/wireless/rtl818x/rtl818x.h | 231 +++++ 32 files changed, 5409 insertions(+), 5406 deletions(-) delete mode 100644 drivers/net/wireless/rtl8180.h delete mode 100644 drivers/net/wireless/rtl8180_dev.c delete mode 100644 drivers/net/wireless/rtl8180_grf5101.c delete mode 100644 drivers/net/wireless/rtl8180_grf5101.h delete mode 100644 drivers/net/wireless/rtl8180_max2820.c delete mode 100644 drivers/net/wireless/rtl8180_max2820.h delete mode 100644 drivers/net/wireless/rtl8180_rtl8225.c delete mode 100644 drivers/net/wireless/rtl8180_rtl8225.h delete mode 100644 drivers/net/wireless/rtl8180_sa2400.c delete mode 100644 drivers/net/wireless/rtl8180_sa2400.h delete mode 100644 drivers/net/wireless/rtl8187.h delete mode 100644 drivers/net/wireless/rtl8187_dev.c delete mode 100644 drivers/net/wireless/rtl8187_rtl8225.c delete mode 100644 drivers/net/wireless/rtl8187_rtl8225.h delete mode 100644 drivers/net/wireless/rtl818x.h create mode 100644 drivers/net/wireless/rtl818x/Makefile create mode 100644 drivers/net/wireless/rtl818x/rtl8180.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_dev.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_grf5101.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_grf5101.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_max2820.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_max2820.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_rtl8225.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_rtl8225.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_sa2400.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_sa2400.h create mode 100644 drivers/net/wireless/rtl818x/rtl8187.h create mode 100644 drivers/net/wireless/rtl818x/rtl8187_dev.c create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.c create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.h create mode 100644 drivers/net/wireless/rtl818x/rtl818x.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 7882084..ed0023d 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -31,6 +31,8 @@ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ +obj-$(CONFIG_RTL8180) += rtl818x/ +obj-$(CONFIG_RTL8187) += rtl818x/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o @@ -43,12 +45,6 @@ obj-$(CONFIG_LIBERTAS) += libertas/ obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/ -rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o - -obj-$(CONFIG_RTL8180) += rtl8180.o -obj-$(CONFIG_RTL8187) += rtl8187.o - obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h deleted file mode 100644 index 8721282..0000000 --- a/drivers/net/wireless/rtl8180.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef RTL8180_H -#define RTL8180_H - -#include "rtl818x.h" - -#define MAX_RX_SIZE IEEE80211_MAX_RTS_THRESHOLD - -#define RF_PARAM_ANALOGPHY (1 << 0) -#define RF_PARAM_ANTBDEFAULT (1 << 1) -#define RF_PARAM_CARRIERSENSE1 (1 << 2) -#define RF_PARAM_CARRIERSENSE2 (1 << 3) - -#define BB_ANTATTEN_CHAN14 0x0C -#define BB_ANTENNA_B 0x40 - -#define BB_HOST_BANG (1 << 30) -#define BB_HOST_BANG_EN (1 << 2) -#define BB_HOST_BANG_CLK (1 << 1) -#define BB_HOST_BANG_DATA 1 - -#define ANAPARAM_TXDACOFF_SHIFT 27 -#define ANAPARAM_PWR0_SHIFT 28 -#define ANAPARAM_PWR0_MASK (0x07 << ANAPARAM_PWR0_SHIFT) -#define ANAPARAM_PWR1_SHIFT 20 -#define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) - -struct rtl8180_tx_desc { - __le32 flags; - __le16 rts_duration; - __le16 plcp_len; - __le32 tx_buf; - __le32 frame_len; - __le32 next_tx_desc; - u8 cw; - u8 retry_limit; - u8 agc; - u8 flags2; - u32 reserved[2]; -} __attribute__ ((packed)); - -struct rtl8180_rx_desc { - __le32 flags; - __le32 flags2; - union { - __le32 rx_buf; - __le64 tsft; - }; -} __attribute__ ((packed)); - -struct rtl8180_tx_ring { - struct rtl8180_tx_desc *desc; - dma_addr_t dma; - unsigned int idx; - unsigned int entries; - struct sk_buff_head queue; -}; - -struct rtl8180_priv { - /* common between rtl818x drivers */ - struct rtl818x_csr __iomem *map; - const struct rtl818x_rf_ops *rf; - struct ieee80211_vif *vif; - int mode; - - /* rtl8180 driver specific */ - spinlock_t lock; - struct rtl8180_rx_desc *rx_ring; - dma_addr_t rx_ring_dma; - unsigned int rx_idx; - struct sk_buff *rx_buf[32]; - struct rtl8180_tx_ring tx_ring[4]; - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; - struct ieee80211_supported_band band; - struct pci_dev *pdev; - u32 rx_conf; - - int r8185; - u32 anaparam; - u16 rfparam; - u8 csthreshold; -}; - -void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); -void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam); - -static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr) -{ - return ioread8(addr); -} - -static inline u16 rtl818x_ioread16(struct rtl8180_priv *priv, __le16 __iomem *addr) -{ - return ioread16(addr); -} - -static inline u32 rtl818x_ioread32(struct rtl8180_priv *priv, __le32 __iomem *addr) -{ - return ioread32(addr); -} - -static inline void rtl818x_iowrite8(struct rtl8180_priv *priv, - u8 __iomem *addr, u8 val) -{ - iowrite8(val, addr); -} - -static inline void rtl818x_iowrite16(struct rtl8180_priv *priv, - __le16 __iomem *addr, u16 val) -{ - iowrite16(val, addr); -} - -static inline void rtl818x_iowrite32(struct rtl8180_priv *priv, - __le32 __iomem *addr, u32 val) -{ - iowrite32(val, addr); -} - -#endif /* RTL8180_H */ diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c deleted file mode 100644 index 6c226c0..0000000 --- a/drivers/net/wireless/rtl8180_dev.c +++ /dev/null @@ -1,1081 +0,0 @@ - -/* - * Linux device driver for RTL8180 / RTL8185 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_rtl8225.h" -#include "rtl8180_sa2400.h" -#include "rtl8180_max2820.h" -#include "rtl8180_grf5101.h" - -MODULE_AUTHOR("Michael Wu "); -MODULE_AUTHOR("Andrea Merello "); -MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); -MODULE_LICENSE("GPL"); - -static struct pci_device_id rtl8180_table[] __devinitdata = { - /* rtl8185 */ - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, - { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) }, - { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) }, - - /* rtl8180 */ - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) }, - { PCI_DEVICE(0x1799, 0x6001) }, - { PCI_DEVICE(0x1799, 0x6020) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, - { } -}; - -MODULE_DEVICE_TABLE(pci, rtl8180_table); - -static const struct ieee80211_rate rtl818x_rates[] = { - { .bitrate = 10, .hw_value = 0, }, - { .bitrate = 20, .hw_value = 1, }, - { .bitrate = 55, .hw_value = 2, }, - { .bitrate = 110, .hw_value = 3, }, - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static const struct ieee80211_channel rtl818x_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - - - - -void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - int i = 10; - u32 buf; - - buf = (data << 8) | addr; - - rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80); - while (i--) { - rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf); - if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF)) - return; - } -} - -static void rtl8180_handle_rx(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - unsigned int count = 32; - - while (count--) { - struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; - struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; - u32 flags = le32_to_cpu(entry->flags); - - if (flags & RTL818X_RX_DESC_FLAG_OWN) - return; - - if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | - RTL818X_RX_DESC_FLAG_FOF | - RTL818X_RX_DESC_FLAG_RX_ERR))) - goto done; - else { - u32 flags2 = le32_to_cpu(entry->flags2); - struct ieee80211_rx_status rx_status = {0}; - struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); - - if (unlikely(!new_skb)) - goto done; - - pci_unmap_single(priv->pdev, - *((dma_addr_t *)skb->cb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - skb_put(skb, flags & 0xFFF); - - rx_status.antenna = (flags2 >> 15) & 1; - /* TODO: improve signal/rssi reporting */ - rx_status.qual = flags2 & 0xFF; - rx_status.signal = (flags2 >> 8) & 0x7F; - /* XXX: is this correct? */ - rx_status.rate_idx = (flags >> 20) & 0xF; - rx_status.freq = dev->conf.channel->center_freq; - rx_status.band = dev->conf.channel->band; - rx_status.mactime = le64_to_cpu(entry->tsft); - rx_status.flag |= RX_FLAG_TSFT; - if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - - ieee80211_rx_irqsafe(dev, skb, &rx_status); - - skb = new_skb; - priv->rx_buf[priv->rx_idx] = skb; - *((dma_addr_t *) skb->cb) = - pci_map_single(priv->pdev, skb_tail_pointer(skb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - } - - done: - entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); - entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | - MAX_RX_SIZE); - if (priv->rx_idx == 31) - entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); - priv->rx_idx = (priv->rx_idx + 1) % 32; - } -} - -static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - u32 flags = le32_to_cpu(entry->flags); - - if (flags & RTL818X_TX_DESC_FLAG_OWN) - return; - - ring->idx = (ring->idx + 1) % ring->entries; - skb = __skb_dequeue(&ring->queue); - pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), - skb->len, PCI_DMA_TODEVICE); - - info = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(info); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (flags & RTL818X_TX_DESC_FLAG_TX_OK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = (flags & 0xFF) + 1; - - ieee80211_tx_status_irqsafe(dev, skb); - if (ring->entries - skb_queue_len(&ring->queue) == 2) - ieee80211_wake_queue(dev, prio); - } -} - -static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) -{ - struct ieee80211_hw *dev = dev_id; - struct rtl8180_priv *priv = dev->priv; - u16 reg; - - spin_lock(&priv->lock); - reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); - if (unlikely(reg == 0xFFFF)) { - spin_unlock(&priv->lock); - return IRQ_HANDLED; - } - - rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); - - if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) - rtl8180_handle_tx(dev, 3); - - if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) - rtl8180_handle_tx(dev, 2); - - if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) - rtl8180_handle_tx(dev, 1); - - if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) - rtl8180_handle_tx(dev, 0); - - if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) - rtl8180_handle_rx(dev); - - spin_unlock(&priv->lock); - - return IRQ_HANDLED; -} - -static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring; - struct rtl8180_tx_desc *entry; - unsigned long flags; - unsigned int idx, prio; - dma_addr_t mapping; - u32 tx_flags; - u8 rc_flags; - u16 plcp_len = 0; - __le16 rts_duration = 0; - - prio = skb_get_queue_mapping(skb); - ring = &priv->tx_ring[prio]; - - mapping = pci_map_single(priv->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - - tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | - RTL818X_TX_DESC_FLAG_LS | - (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | - skb->len; - - if (priv->r8185) - tx_flags |= RTL818X_TX_DESC_FLAG_DMA | - RTL818X_TX_DESC_FLAG_NO_ENC; - - rc_flags = info->control.rates[0].flags; - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - tx_flags |= RTL818X_TX_DESC_FLAG_RTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - tx_flags |= RTL818X_TX_DESC_FLAG_CTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } - - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) - rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, - info); - - if (!priv->r8185) { - unsigned int remainder; - - plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); - remainder = (16 * (skb->len + 4)) % - ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); - if (remainder > 0 && remainder <= 6) - plcp_len |= 1 << 15; - } - - spin_lock_irqsave(&priv->lock, flags); - idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; - entry = &ring->desc[idx]; - - entry->rts_duration = rts_duration; - entry->plcp_len = cpu_to_le16(plcp_len); - entry->tx_buf = cpu_to_le32(mapping); - entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = info->control.rates[1].idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.rates[0].count; - entry->flags = cpu_to_le32(tx_flags); - __skb_queue_tail(&ring->queue, skb); - if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); - spin_unlock_irqrestore(&priv->lock, flags); - - rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); - - return 0; -} - -void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) -{ - u8 reg; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); -} - -static int rtl8180_init_hw(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg; - - rtl818x_iowrite8(priv, &priv->map->CMD, 0); - rtl818x_ioread8(priv, &priv->map->CMD); - msleep(10); - - /* reset */ - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - rtl818x_ioread8(priv, &priv->map->CMD); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= (1 << 1); - reg |= RTL818X_CMD_RESET; - rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); - rtl818x_ioread8(priv, &priv->map->CMD); - msleep(200); - - /* check success of reset */ - if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { - printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy)); - return -ETIMEDOUT; - } - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); - rtl818x_ioread8(priv, &priv->map->CMD); - msleep(200); - - if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { - /* For cardbus */ - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= 1 << 1; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - reg = rtl818x_ioread16(priv, &priv->map->FEMR); - reg |= (1 << 15) | (1 << 14) | (1 << 4); - rtl818x_iowrite16(priv, &priv->map->FEMR, reg); - } - - rtl818x_iowrite8(priv, &priv->map->MSR, 0); - - if (!priv->r8185) - rtl8180_set_anaparam(priv, priv->anaparam); - - rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); - rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); - rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); - rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); - rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); - - /* TODO: necessary? specs indicate not */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); - rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); - if (priv->r8185) { - reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); - rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); - } - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ - - /* TODO: turn off hw wep on rtl8180 */ - - rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); - - if (priv->r8185) { - rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); - - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - - /* TODO: set ClkRun enable? necessary? */ - reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - } else { - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); - rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); - - rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); - rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); - } - - priv->rf->init(dev); - if (priv->r8185) - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - return 0; -} - -static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_rx_desc *entry; - int i; - - priv->rx_ring = pci_alloc_consistent(priv->pdev, - sizeof(*priv->rx_ring) * 32, - &priv->rx_ring_dma); - - if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { - printk(KERN_ERR "%s: Cannot allocate RX ring\n", - wiphy_name(dev->wiphy)); - return -ENOMEM; - } - - memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32); - priv->rx_idx = 0; - - for (i = 0; i < 32; i++) { - struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); - dma_addr_t *mapping; - entry = &priv->rx_ring[i]; - if (!skb) - return 0; - - priv->rx_buf[i] = skb; - mapping = (dma_addr_t *)skb->cb; - *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - entry->rx_buf = cpu_to_le32(*mapping); - entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | - MAX_RX_SIZE); - } - entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); - return 0; -} - -static void rtl8180_free_rx_ring(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - for (i = 0; i < 32; i++) { - struct sk_buff *skb = priv->rx_buf[i]; - if (!skb) - continue; - - pci_unmap_single(priv->pdev, - *((dma_addr_t *)skb->cb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - kfree_skb(skb); - } - - pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32, - priv->rx_ring, priv->rx_ring_dma); - priv->rx_ring = NULL; -} - -static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, - unsigned int prio, unsigned int entries) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_desc *ring; - dma_addr_t dma; - int i; - - ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); - if (!ring || (unsigned long)ring & 0xFF) { - printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n", - wiphy_name(dev->wiphy), prio); - return -ENOMEM; - } - - memset(ring, 0, sizeof(*ring)*entries); - priv->tx_ring[prio].desc = ring; - priv->tx_ring[prio].dma = dma; - priv->tx_ring[prio].idx = 0; - priv->tx_ring[prio].entries = entries; - skb_queue_head_init(&priv->tx_ring[prio].queue); - - for (i = 0; i < entries; i++) - ring[i].next_tx_desc = - cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); - - return 0; -} - -static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb = __skb_dequeue(&ring->queue); - - pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), - skb->len, PCI_DMA_TODEVICE); - kfree_skb(skb); - ring->idx = (ring->idx + 1) % ring->entries; - } - - pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, - ring->desc, ring->dma); - ring->desc = NULL; -} - -static int rtl8180_start(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int ret, i; - u32 reg; - - ret = rtl8180_init_rx_ring(dev); - if (ret) - return ret; - - for (i = 0; i < 4; i++) - if ((ret = rtl8180_init_tx_ring(dev, i, 16))) - goto err_free_rings; - - ret = rtl8180_init_hw(dev); - if (ret) - goto err_free_rings; - - rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); - rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); - rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); - rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); - rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); - - ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, - IRQF_SHARED, KBUILD_MODNAME, dev); - if (ret) { - printk(KERN_ERR "%s: failed to register IRQ handler\n", - wiphy_name(dev->wiphy)); - goto err_free_rings; - } - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - - rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); - rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); - - reg = RTL818X_RX_CONF_ONLYERLPKT | - RTL818X_RX_CONF_RX_AUTORESETPHY | - RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_DATA | - (7 << 8 /* MAX RX DMA */) | - RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_NICMAC; - - if (priv->r8185) - reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; - else { - reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) - ? RTL818X_RX_CONF_CSDM1 : 0; - reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) - ? RTL818X_RX_CONF_CSDM2 : 0; - } - - priv->rx_conf = reg; - rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - - if (priv->r8185) { - reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); - reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; - reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; - rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); - - /* disable early TX */ - rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); - } - - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); - reg |= (6 << 21 /* MAX TX DMA */) | - RTL818X_TX_CONF_NO_ICV; - - if (priv->r8185) - reg &= ~RTL818X_TX_CONF_PROBE_DTS; - else - reg &= ~RTL818X_TX_CONF_HW_SEQNUM; - - /* different meaning, same value on both rtl8185 and rtl8180 */ - reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; - - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg |= RTL818X_CMD_RX_ENABLE; - reg |= RTL818X_CMD_TX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - priv->mode = NL80211_IFTYPE_MONITOR; - return 0; - - err_free_rings: - rtl8180_free_rx_ring(dev); - for (i = 0; i < 4; i++) - if (priv->tx_ring[i].desc) - rtl8180_free_tx_ring(dev, i); - - return ret; -} - -static void rtl8180_stop(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u8 reg; - int i; - - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= ~RTL818X_CMD_TX_ENABLE; - reg &= ~RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - priv->rf->stop(dev); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); - rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - free_irq(priv->pdev->irq, dev); - - rtl8180_free_rx_ring(dev); - for (i = 0; i < 4; i++) - rtl8180_free_tx_ring(dev, i); -} - -static int rtl8180_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - - if (priv->mode != NL80211_IFTYPE_MONITOR) - return -EOPNOTSUPP; - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - priv->mode = conf->type; - break; - default: - return -EOPNOTSUPP; - } - - priv->vif = conf->vif; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], - le32_to_cpu(*(__le32 *)conf->mac_addr)); - rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], - le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - return 0; -} - -static void rtl8180_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - priv->mode = NL80211_IFTYPE_MONITOR; - priv->vif = NULL; -} - -static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) -{ - struct rtl8180_priv *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - - priv->rf->set_chan(dev, conf); - - return 0; -} - -static int rtl8180_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); - else - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); - - return 0; -} - -static void rtl8180_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) -{ - struct rtl8180_priv *priv = dev->priv; - - if (changed_flags & FIF_FCSFAIL) - priv->rx_conf ^= RTL818X_RX_CONF_FCS; - if (changed_flags & FIF_CONTROL) - priv->rx_conf ^= RTL818X_RX_CONF_CTRL; - if (changed_flags & FIF_OTHER_BSS) - priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) - priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; - else - priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; - - *total_flags = 0; - - if (priv->rx_conf & RTL818X_RX_CONF_FCS) - *total_flags |= FIF_FCSFAIL; - if (priv->rx_conf & RTL818X_RX_CONF_CTRL) - *total_flags |= FIF_CONTROL; - if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) - *total_flags |= FIF_OTHER_BSS; - if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) - *total_flags |= FIF_ALLMULTI; - - rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); -} - -static const struct ieee80211_ops rtl8180_ops = { - .tx = rtl8180_tx, - .start = rtl8180_start, - .stop = rtl8180_stop, - .add_interface = rtl8180_add_interface, - .remove_interface = rtl8180_remove_interface, - .config = rtl8180_config, - .config_interface = rtl8180_config_interface, - .configure_filter = rtl8180_configure_filter, -}; - -static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8180_priv *priv = dev->priv; - u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - - eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; - eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; - eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; - eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; -} - -static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8180_priv *priv = dev->priv; - u8 reg = 2 << 6; - - if (eeprom->reg_data_in) - reg |= RTL818X_EEPROM_CMD_WRITE; - if (eeprom->reg_data_out) - reg |= RTL818X_EEPROM_CMD_READ; - if (eeprom->reg_data_clock) - reg |= RTL818X_EEPROM_CMD_CK; - if (eeprom->reg_chip_select) - reg |= RTL818X_EEPROM_CMD_CS; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); -} - -static int __devinit rtl8180_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct ieee80211_hw *dev; - struct rtl8180_priv *priv; - unsigned long mem_addr, mem_len; - unsigned int io_addr, io_len; - int err, i; - struct eeprom_93cx6 eeprom; - const char *chip_name, *rf_name = NULL; - u32 reg; - u16 eeprom_val; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n", - pci_name(pdev)); - return err; - } - - err = pci_request_regions(pdev, KBUILD_MODNAME); - if (err) { - printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\n", - pci_name(pdev)); - return err; - } - - io_addr = pci_resource_start(pdev, 0); - io_len = pci_resource_len(pdev, 0); - mem_addr = pci_resource_start(pdev, 1); - mem_len = pci_resource_len(pdev, 1); - - if (mem_len < sizeof(struct rtl818x_csr) || - io_len < sizeof(struct rtl818x_csr)) { - printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n", - pci_name(pdev)); - err = -ENOMEM; - goto err_free_reg; - } - - if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) || - (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) { - printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n", - pci_name(pdev)); - goto err_free_reg; - } - - pci_set_master(pdev); - - dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops); - if (!dev) { - printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n", - pci_name(pdev)); - err = -ENOMEM; - goto err_free_reg; - } - - priv = dev->priv; - priv->pdev = pdev; - - dev->max_rates = 2; - SET_IEEE80211_DEV(dev, &pdev->dev); - pci_set_drvdata(pdev, dev); - - priv->map = pci_iomap(pdev, 1, mem_len); - if (!priv->map) - priv->map = pci_iomap(pdev, 0, io_len); - - if (!priv->map) { - printk(KERN_ERR "%s (rtl8180): Cannot map device memory\n", - pci_name(pdev)); - goto err_free_dev; - } - - BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); - BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); - - memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); - memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); - - priv->band.band = IEEE80211_BAND_2GHZ; - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = 4; - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; - dev->queues = 1; - dev->max_signal = 65; - - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); - reg &= RTL818X_TX_CONF_HWVER_MASK; - switch (reg) { - case RTL818X_TX_CONF_R8180_ABCD: - chip_name = "RTL8180"; - break; - case RTL818X_TX_CONF_R8180_F: - chip_name = "RTL8180vF"; - break; - case RTL818X_TX_CONF_R8185_ABC: - chip_name = "RTL8185"; - break; - case RTL818X_TX_CONF_R8185_D: - chip_name = "RTL8185vD"; - break; - default: - printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", - pci_name(pdev), reg >> 25); - goto err_iounmap; - } - - priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; - if (priv->r8185) { - priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); - pci_try_set_mwi(pdev); - } - - eeprom.data = dev; - eeprom.register_read = rtl8180_eeprom_register_read; - eeprom.register_write = rtl8180_eeprom_register_write; - if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) - eeprom.width = PCI_EEPROM_WIDTH_93C66; - else - eeprom.width = PCI_EEPROM_WIDTH_93C46; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); - eeprom_val &= 0xFF; - switch (eeprom_val) { - case 1: rf_name = "Intersil"; - break; - case 2: rf_name = "RFMD"; - break; - case 3: priv->rf = &sa2400_rf_ops; - break; - case 4: priv->rf = &max2820_rf_ops; - break; - case 5: priv->rf = &grf5101_rf_ops; - break; - case 9: priv->rf = rtl8180_detect_rf(dev); - break; - case 10: - rf_name = "RTL8255"; - break; - default: - printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", - pci_name(pdev), eeprom_val); - goto err_iounmap; - } - - if (!priv->rf) { - printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", - pci_name(pdev), rf_name); - goto err_iounmap; - } - - eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); - priv->csthreshold = eeprom_val >> 8; - if (!priv->r8185) { - __le32 anaparam; - eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); - priv->anaparam = le32_to_cpu(anaparam); - eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); - } - - eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3); - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" - " randomly generated MAC addr\n", pci_name(pdev)); - random_ether_addr(dev->wiphy->perm_addr); - } - - /* CCK TX power */ - for (i = 0; i < 14; i += 2) { - u16 txpwr; - eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); - priv->channels[i].hw_value = txpwr & 0xFF; - priv->channels[i + 1].hw_value = txpwr >> 8; - } - - /* OFDM TX power */ - if (priv->r8185) { - for (i = 0; i < 14; i += 2) { - u16 txpwr; - eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); - priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; - priv->channels[i + 1].hw_value |= txpwr & 0xFF00; - } - } - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - spin_lock_init(&priv->lock); - - err = ieee80211_register_hw(dev); - if (err) { - printk(KERN_ERR "%s (rtl8180): Cannot register device\n", - pci_name(pdev)); - goto err_iounmap; - } - - printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", - wiphy_name(dev->wiphy), dev->wiphy->perm_addr, - chip_name, priv->rf->name); - - return 0; - - err_iounmap: - iounmap(priv->map); - - err_free_dev: - pci_set_drvdata(pdev, NULL); - ieee80211_free_hw(dev); - - err_free_reg: - pci_release_regions(pdev); - pci_disable_device(pdev); - return err; -} - -static void __devexit rtl8180_remove(struct pci_dev *pdev) -{ - struct ieee80211_hw *dev = pci_get_drvdata(pdev); - struct rtl8180_priv *priv; - - if (!dev) - return; - - ieee80211_unregister_hw(dev); - - priv = dev->priv; - - pci_iounmap(pdev, priv->map); - pci_release_regions(pdev); - pci_disable_device(pdev); - ieee80211_free_hw(dev); -} - -#ifdef CONFIG_PM -static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) -{ - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int rtl8180_resume(struct pci_dev *pdev) -{ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - return 0; -} - -#endif /* CONFIG_PM */ - -static struct pci_driver rtl8180_driver = { - .name = KBUILD_MODNAME, - .id_table = rtl8180_table, - .probe = rtl8180_probe, - .remove = __devexit_p(rtl8180_remove), -#ifdef CONFIG_PM - .suspend = rtl8180_suspend, - .resume = rtl8180_resume, -#endif /* CONFIG_PM */ -}; - -static int __init rtl8180_init(void) -{ - return pci_register_driver(&rtl8180_driver); -} - -static void __exit rtl8180_exit(void) -{ - pci_unregister_driver(&rtl8180_driver); -} - -module_init(rtl8180_init); -module_exit(rtl8180_exit); diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c deleted file mode 100644 index 947ee55..0000000 --- a/drivers/net/wireless/rtl8180_grf5101.c +++ /dev/null @@ -1,180 +0,0 @@ - -/* - * Radio tuning for GCT GRF5101 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_grf5101.h" - -static const int grf5101_encode[] = { - 0x0, 0x8, 0x4, 0xC, - 0x2, 0xA, 0x6, 0xE, - 0x1, 0x9, 0x5, 0xD, - 0x3, 0xB, 0x7, 0xF -}; - -static void write_grf5101(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - u32 phy_config; - - phy_config = grf5101_encode[(data >> 8) & 0xF]; - phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4; - phy_config |= grf5101_encode[data & 0xF] << 8; - phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12; - phy_config |= (addr & 1) << 16; - phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24; - - /* MAC will bang bits to the chip */ - phy_config |= 0x90000000; - - rtl818x_iowrite32(priv, - (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); - - msleep(3); -} - -static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan) -{ - struct rtl8180_priv *priv = dev->priv; - u8 ant = GRF5101_ANTENNA; - - if (priv->rfparam & RF_PARAM_ANTBDEFAULT) - ant |= BB_ANTENNA_B; - - if (chan == 14) - ant |= BB_ANTATTEN_CHAN14; - - rtl8180_write_phy(dev, 0x10, ant); -} - -static void grf5101_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; - u32 chan = channel - 1; - - /* set TX power */ - write_grf5101(dev, 0x15, 0x0); - write_grf5101(dev, 0x06, txpw); - write_grf5101(dev, 0x15, 0x10); - write_grf5101(dev, 0x15, 0x0); - - /* set frequency */ - write_grf5101(dev, 0x07, 0x0); - write_grf5101(dev, 0x0B, chan); - write_grf5101(dev, 0x07, 0x1000); - - grf5101_write_phy_antenna(dev, channel); -} - -static void grf5101_rf_stop(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u32 anaparam; - - anaparam = priv->anaparam; - anaparam &= 0x000fffff; - anaparam |= 0x3f900000; - rtl8180_set_anaparam(priv, anaparam); - - write_grf5101(dev, 0x07, 0x0); - write_grf5101(dev, 0x1f, 0x45); - write_grf5101(dev, 0x1f, 0x5); - write_grf5101(dev, 0x00, 0x8e4); -} - -static void grf5101_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - - rtl8180_set_anaparam(priv, priv->anaparam); - - write_grf5101(dev, 0x1f, 0x0); - write_grf5101(dev, 0x1f, 0x0); - write_grf5101(dev, 0x1f, 0x40); - write_grf5101(dev, 0x1f, 0x60); - write_grf5101(dev, 0x1f, 0x61); - write_grf5101(dev, 0x1f, 0x61); - write_grf5101(dev, 0x00, 0xae4); - write_grf5101(dev, 0x1f, 0x1); - write_grf5101(dev, 0x1f, 0x41); - write_grf5101(dev, 0x1f, 0x61); - - write_grf5101(dev, 0x01, 0x1a23); - write_grf5101(dev, 0x02, 0x4971); - write_grf5101(dev, 0x03, 0x41de); - write_grf5101(dev, 0x04, 0x2d80); - write_grf5101(dev, 0x05, 0x68ff); /* 0x61ff original value */ - write_grf5101(dev, 0x06, 0x0); - write_grf5101(dev, 0x07, 0x0); - write_grf5101(dev, 0x08, 0x7533); - write_grf5101(dev, 0x09, 0xc401); - write_grf5101(dev, 0x0a, 0x0); - write_grf5101(dev, 0x0c, 0x1c7); - write_grf5101(dev, 0x0d, 0x29d3); - write_grf5101(dev, 0x0e, 0x2e8); - write_grf5101(dev, 0x10, 0x192); - write_grf5101(dev, 0x11, 0x248); - write_grf5101(dev, 0x12, 0x0); - write_grf5101(dev, 0x13, 0x20c4); - write_grf5101(dev, 0x14, 0xf4fc); - write_grf5101(dev, 0x15, 0x0); - write_grf5101(dev, 0x16, 0x1500); - - write_grf5101(dev, 0x07, 0x1000); - - /* baseband configuration */ - rtl8180_write_phy(dev, 0, 0xa8); - rtl8180_write_phy(dev, 3, 0x0); - rtl8180_write_phy(dev, 4, 0xc0); - rtl8180_write_phy(dev, 5, 0x90); - rtl8180_write_phy(dev, 6, 0x1e); - rtl8180_write_phy(dev, 7, 0x64); - - grf5101_write_phy_antenna(dev, 1); - - rtl8180_write_phy(dev, 0x11, 0x88); - - if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & - RTL818X_CONFIG2_ANTENNA_DIV) - rtl8180_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */ - else - rtl8180_write_phy(dev, 0x12, 0x40); /* disable ant diversity */ - - rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); - - rtl8180_write_phy(dev, 0x19, 0x0); - rtl8180_write_phy(dev, 0x1a, 0xa0); - rtl8180_write_phy(dev, 0x1b, 0x44); -} - -const struct rtl818x_rf_ops grf5101_rf_ops = { - .name = "GCT", - .init = grf5101_rf_init, - .stop = grf5101_rf_stop, - .set_chan = grf5101_rf_set_channel -}; diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl8180_grf5101.h deleted file mode 100644 index 7664711..0000000 --- a/drivers/net/wireless/rtl8180_grf5101.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef RTL8180_GRF5101_H -#define RTL8180_GRF5101_H - -/* - * Radio tuning for GCT GRF5101 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define GRF5101_ANTENNA 0xA3 - -extern const struct rtl818x_rf_ops grf5101_rf_ops; - -#endif /* RTL8180_GRF5101_H */ diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c deleted file mode 100644 index 6c825fd..0000000 --- a/drivers/net/wireless/rtl8180_max2820.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Radio tuning for Maxim max2820 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_max2820.h" - -static const u32 max2820_chan[] = { - 12, /* CH 1 */ - 17, - 22, - 27, - 32, - 37, - 42, - 47, - 52, - 57, - 62, - 67, - 72, - 84, /* CH 14 */ -}; - -static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - u32 phy_config; - - phy_config = 0x90 + (data & 0xf); - phy_config <<= 16; - phy_config += addr; - phy_config <<= 8; - phy_config += (data >> 4) & 0xff; - - rtl818x_iowrite32(priv, - (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); - - msleep(1); -} - -static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) -{ - struct rtl8180_priv *priv = dev->priv; - u8 ant; - - ant = MAXIM_ANTENNA; - if (priv->rfparam & RF_PARAM_ANTBDEFAULT) - ant |= BB_ANTENNA_B; - if (chan == 14) - ant |= BB_ANTATTEN_CHAN14; - - rtl8180_write_phy(dev, 0x10, ant); -} - -static void max2820_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int channel = conf ? - ieee80211_frequency_to_channel(conf->channel->center_freq) : 1; - unsigned int chan_idx = channel - 1; - u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; - u32 chan = max2820_chan[chan_idx]; - - /* While philips SA2400 drive the PA bias from - * sa2400, for MAXIM we do this directly from BB */ - rtl8180_write_phy(dev, 3, txpw); - - max2820_write_phy_antenna(dev, channel); - write_max2820(dev, 3, chan); -} - -static void max2820_rf_stop(struct ieee80211_hw *dev) -{ - rtl8180_write_phy(dev, 3, 0x8); - write_max2820(dev, 1, 0); -} - - -static void max2820_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - - /* MAXIM from netbsd driver */ - write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ - write_max2820(dev, 1, 0x01e); /* enable register */ - write_max2820(dev, 2, 0x001); /* synt register */ - - max2820_rf_set_channel(dev, NULL); - - write_max2820(dev, 4, 0x313); /* rx register */ - - /* PA is driven directly by the BB, we keep the MAXIM bias - * at the highest value in case that setting it to lower - * values may introduce some further attenuation somewhere.. - */ - write_max2820(dev, 5, 0x00f); - - /* baseband configuration */ - rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ - rtl8180_write_phy(dev, 3, 0x08); /* txagc */ - rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ - rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ - rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ - rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ - - max2820_write_phy_antenna(dev, 1); - - rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ - - if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & - RTL818X_CONFIG2_ANTENNA_DIV) - rtl8180_write_phy(dev, 0x12, 0xc7); - else - rtl8180_write_phy(dev, 0x12, 0x47); - - rtl8180_write_phy(dev, 0x13, 0x9b); - - rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ - rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ - - max2820_rf_set_channel(dev, NULL); -} - -const struct rtl818x_rf_ops max2820_rf_ops = { - .name = "Maxim", - .init = max2820_rf_init, - .stop = max2820_rf_stop, - .set_chan = max2820_rf_set_channel -}; diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl8180_max2820.h deleted file mode 100644 index 61cf6d1..0000000 --- a/drivers/net/wireless/rtl8180_max2820.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef RTL8180_MAX2820_H -#define RTL8180_MAX2820_H - -/* - * Radio tuning for Maxim max2820 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define MAXIM_ANTENNA 0xb3 - -extern const struct rtl818x_rf_ops max2820_rf_ops; - -#endif /* RTL8180_MAX2820_H */ diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl8180_rtl8225.c deleted file mode 100644 index cd22781..0000000 --- a/drivers/net/wireless/rtl8180_rtl8225.c +++ /dev/null @@ -1,780 +0,0 @@ - -/* - * Radio tuning for RTL8225 on RTL8180 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8180 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_rtl8225.h" - -static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg80, reg84, reg82; - u32 bangdata; - int i; - - bangdata = (data << 4) | (addr & 0xf); - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); - - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - for (i = 15; i >= 0; i--) { - u16 reg = reg80 | !!(bangdata & (1 << i)); - - if (i & 1) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - - if (!(i & 1)) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); -} - -static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg80, reg82, reg84, out; - int i; - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400; - - reg80 &= ~0xF; - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(4); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(5); - - for (i = 4; i >= 0; i--) { - u16 reg = reg80 | ((addr >> i) & 1); - - if (!(i & 1)) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(1); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - if (i & 1) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(1); - } - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - out = 0; - for (i = 11; i >= 0; i--) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(1); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) - out |= 1 << i; - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); - - return out; -} - -static const u16 rtl8225bcd_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, - 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb -}; - -static const u8 rtl8225_agc[] = { - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, - 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, - 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, - 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, - 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, - 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, - 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, - 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 -}; - -static const u8 rtl8225_gain[] = { - 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ - 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ - 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ - 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ - 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ - 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ - 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ -}; - -static const u8 rtl8225_threshold[] = { - 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd -}; - -static const u8 rtl8225_tx_gain_cck_ofdm[] = { - 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e -}; - -static const u8 rtl8225_tx_power_cck[] = { - 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, - 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, - 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, - 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 -}; - -static const u8 rtl8225_tx_power_cck_ch14[] = { - 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225_tx_power_ofdm[] = { - 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 -}; - -static const u32 rtl8225_chan[] = { - 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, - 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 -}; - -static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8180_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - u32 reg; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xFF; - ofdm_power = priv->channels[channel - 1].hw_value >> 8; - - cck_power = min(cck_power, (u8)35); - ofdm_power = min(ofdm_power, (u8)35); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); - - if (channel == 14) - tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; - else - tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - msleep(1); /* FIXME: optional? */ - - /* anaparam2 on */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1); - - tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; - - rtl8225_write_phy_ofdm(dev, 5, *tmp); - rtl8225_write_phy_ofdm(dev, 7, *tmp); - - msleep(1); -} - -static void rtl8225_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); - - /* host_pci_init */ - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - msleep(200); /* FIXME: ehh?? */ - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); - - /* TODO: check if we need really to change BRSR to do RF config */ - rtl818x_ioread16(priv, &priv->map->BRSR); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); - rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl8225_write(dev, 0x0, 0x067); - rtl8225_write(dev, 0x1, 0xFE0); - rtl8225_write(dev, 0x2, 0x44D); - rtl8225_write(dev, 0x3, 0x441); - rtl8225_write(dev, 0x4, 0x8BE); - rtl8225_write(dev, 0x5, 0xBF0); /* TODO: minipci */ - rtl8225_write(dev, 0x6, 0xAE6); - rtl8225_write(dev, 0x7, rtl8225_chan[0]); - rtl8225_write(dev, 0x8, 0x01F); - rtl8225_write(dev, 0x9, 0x334); - rtl8225_write(dev, 0xA, 0xFD4); - rtl8225_write(dev, 0xB, 0x391); - rtl8225_write(dev, 0xC, 0x050); - rtl8225_write(dev, 0xD, 0x6DB); - rtl8225_write(dev, 0xE, 0x029); - rtl8225_write(dev, 0xF, 0x914); msleep(1); - - rtl8225_write(dev, 0x2, 0xC4D); msleep(100); - - rtl8225_write(dev, 0x0, 0x127); - - for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); - } - - rtl8225_write(dev, 0x0, 0x027); - rtl8225_write(dev, 0x0, 0x22F); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); - rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); - } - - msleep(1); - - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x03); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); - - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); - rtl8225_write_phy_cck(dev, 0x13, 0xd0); - rtl8225_write_phy_cck(dev, 0x19, 0x00); - rtl8225_write_phy_cck(dev, 0x1a, 0xa0); - rtl8225_write_phy_cck(dev, 0x1b, 0x08); - rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); - - rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1); - - rtl8225_rf_set_tx_power(dev, 1); - - /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - rtl8225_write(dev, 0x0c, 0x50); - /* set OFDM initial gain */ - rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]); - rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]); - rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]); - rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]); - /* set CCK threshold */ - rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]); -} - -static const u8 rtl8225z2_tx_power_cck_ch14[] = { - 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225z2_tx_power_cck_B[] = { - 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04 -}; - -static const u8 rtl8225z2_tx_power_cck_A[] = { - 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 -}; - -static const u8 rtl8225z2_tx_power_cck[] = { - 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 -}; - -static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8180_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xFF; - ofdm_power = priv->channels[channel - 1].hw_value >> 8; - - if (channel == 14) - tmp = rtl8225z2_tx_power_cck_ch14; - else if (cck_power == 12) - tmp = rtl8225z2_tx_power_cck_B; - else if (cck_power == 13) - tmp = rtl8225z2_tx_power_cck_A; - else - tmp = rtl8225z2_tx_power_cck; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - cck_power = min(cck_power, (u8)35); - if (cck_power == 13 || cck_power == 14) - cck_power = 12; - if (cck_power >= 15) - cck_power -= 2; - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power); - rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK); - msleep(1); - - ofdm_power = min(ofdm_power, (u8)35); - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power); - - rtl8225_write_phy_ofdm(dev, 2, 0x62); - rtl8225_write_phy_ofdm(dev, 5, 0x00); - rtl8225_write_phy_ofdm(dev, 6, 0x40); - rtl8225_write_phy_ofdm(dev, 7, 0x00); - rtl8225_write_phy_ofdm(dev, 8, 0x40); - - msleep(1); -} - -static const u16 rtl8225z2_rxgain[] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009, - 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141, - 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183, - 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244, - 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288, - 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345, - 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389, - 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393, - 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, - 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, - 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, - 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb -}; - -static void rtl8225z2_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); - - /* host_pci_init */ - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - msleep(200); /* FIXME: ehh?? */ - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008); - - /* TODO: check if we need really to change BRSR to do RF config */ - rtl818x_ioread16(priv, &priv->map->BRSR); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); - rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(100); - - if (!(rtl8225_read(dev, 6) & (1 << 7))) { - rtl8225_write(dev, 0x02, 0x0C4D); - msleep(200); - rtl8225_write(dev, 0x02, 0x044D); - msleep(100); - /* TODO: readd calibration failure message when the calibration - check works */ - } - - rtl8225_write(dev, 0x0, 0x1B7); - rtl8225_write(dev, 0x3, 0x002); - rtl8225_write(dev, 0x5, 0x004); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); - } - - rtl8225_write(dev, 0x0, 0x0B7); msleep(100); - rtl8225_write(dev, 0x2, 0xC4D); - - msleep(200); - rtl8225_write(dev, 0x2, 0x44D); - msleep(100); - - rtl8225_write(dev, 0x00, 0x2BF); - rtl8225_write(dev, 0xFF, 0xFFFF); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); - rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); - } - - msleep(1); - - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); /* FIXME: not needed? */ - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); - - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); - rtl8225_write_phy_cck(dev, 0x13, 0xd0); - rtl8225_write_phy_cck(dev, 0x19, 0x00); - rtl8225_write_phy_cck(dev, 0x1a, 0xa0); - rtl8225_write_phy_cck(dev, 0x1b, 0x08); - rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8a); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); - - rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 0x0D); msleep(1); - - rtl8225z2_rf_set_tx_power(dev, 1); - - /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); -} - -static void rtl8225_rf_stop(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u8 reg; - - rtl8225_write(dev, 0x4, 0x1f); msleep(1); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); -} - -static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); - - if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, chan); - else - rtl8225z2_rf_set_tx_power(dev, chan); - - rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); - msleep(10); - - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 81); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 81); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } -} - -static const struct rtl818x_rf_ops rtl8225_ops = { - .name = "rtl8225", - .init = rtl8225_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -static const struct rtl818x_rf_ops rtl8225z2_ops = { - .name = "rtl8225z2", - .init = rtl8225z2_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg8, reg9; - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - msleep(100); - - rtl8225_write(dev, 0, 0x1B7); - - reg8 = rtl8225_read(dev, 8); - reg9 = rtl8225_read(dev, 9); - - rtl8225_write(dev, 0, 0x0B7); - - if (reg8 != 0x588 || reg9 != 0x700) - return &rtl8225_ops; - - return &rtl8225z2_ops; -} diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl8180_rtl8225.h deleted file mode 100644 index 310013a..0000000 --- a/drivers/net/wireless/rtl8180_rtl8225.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef RTL8180_RTL8225_H -#define RTL8180_RTL8225_H - -#define RTL8225_ANAPARAM_ON 0xa0000b59 -#define RTL8225_ANAPARAM2_ON 0x860dec11 -#define RTL8225_ANAPARAM_OFF 0xa00beb59 -#define RTL8225_ANAPARAM2_OFF 0x840dec11 - -const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *); - -static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, - u8 addr, u8 data) -{ - rtl8180_write_phy(dev, addr, data); -} - -static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, - u8 addr, u8 data) -{ - rtl8180_write_phy(dev, addr, data | 0x10000); -} - -#endif /* RTL8180_RTL8225_H */ diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c deleted file mode 100644 index cea4e0c..0000000 --- a/drivers/net/wireless/rtl8180_sa2400.c +++ /dev/null @@ -1,202 +0,0 @@ - -/* - * Radio tuning for Philips SA2400 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_sa2400.h" - -static const u32 sa2400_chan[] = { - 0x00096c, /* ch1 */ - 0x080970, - 0x100974, - 0x180978, - 0x000980, - 0x080984, - 0x100988, - 0x18098c, - 0x000994, - 0x080998, - 0x10099c, - 0x1809a0, - 0x0009a8, - 0x0009b4, /* ch 14 */ -}; - -static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - u32 phy_config; - - /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ - phy_config = 0xb0000000; - - phy_config |= ((u32)(addr & 0xf)) << 24; - phy_config |= data & 0xffffff; - - rtl818x_iowrite32(priv, - (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); - - msleep(3); -} - -static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) -{ - struct rtl8180_priv *priv = dev->priv; - u8 ant = SA2400_ANTENNA; - - if (priv->rfparam & RF_PARAM_ANTBDEFAULT) - ant |= BB_ANTENNA_B; - - if (chan == 14) - ant |= BB_ANTATTEN_CHAN14; - - rtl8180_write_phy(dev, 0x10, ant); - -} - -static void sa2400_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; - u32 chan = sa2400_chan[channel - 1]; - - write_sa2400(dev, 7, txpw); - - sa2400_write_phy_antenna(dev, channel); - - write_sa2400(dev, 0, chan); - write_sa2400(dev, 1, 0xbb50); - write_sa2400(dev, 2, 0x80); - write_sa2400(dev, 3, 0); -} - -static void sa2400_rf_stop(struct ieee80211_hw *dev) -{ - write_sa2400(dev, 4, 0); -} - -static void sa2400_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u32 anaparam, txconf; - u8 firdac; - int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; - - anaparam = priv->anaparam; - anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); - anaparam &= ~ANAPARAM_PWR1_MASK; - anaparam &= ~ANAPARAM_PWR0_MASK; - - if (analogphy) { - anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; - firdac = 0; - } else { - anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); - anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); - firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; - } - - rtl8180_set_anaparam(priv, anaparam); - - write_sa2400(dev, 0, sa2400_chan[0]); - write_sa2400(dev, 1, 0xbb50); - write_sa2400(dev, 2, 0x80); - write_sa2400(dev, 3, 0); - write_sa2400(dev, 4, 0x19340 | firdac); - write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); - write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ - - if (!analogphy) - write_sa2400(dev, 4, 0x1938c); /*???*/ - - write_sa2400(dev, 4, 0x19340 | firdac); - - write_sa2400(dev, 0, sa2400_chan[0]); - write_sa2400(dev, 1, 0xbb50); - write_sa2400(dev, 2, 0x80); - write_sa2400(dev, 3, 0); - write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ - - /* new from rtl8180 embedded driver (rtl8181 project) */ - write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ - write_sa2400(dev, 8, 0); /* VCO */ - - if (analogphy) { - rtl8180_set_anaparam(priv, anaparam | - (1 << ANAPARAM_TXDACOFF_SHIFT)); - - txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - txconf | RTL818X_TX_CONF_LOOPBACK_CONT); - - write_sa2400(dev, 4, 0x19341); /* calibrates DC */ - - /* a 5us sleep is required here, - * we rely on the 3ms delay introduced in write_sa2400 */ - write_sa2400(dev, 4, 0x19345); - - /* a 20us sleep is required here, - * we rely on the 3ms delay introduced in write_sa2400 */ - - rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); - - rtl8180_set_anaparam(priv, anaparam); - } - /* end new code */ - - write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ - - /* baseband configuration */ - rtl8180_write_phy(dev, 0, 0x98); - rtl8180_write_phy(dev, 3, 0x38); - rtl8180_write_phy(dev, 4, 0xe0); - rtl8180_write_phy(dev, 5, 0x90); - rtl8180_write_phy(dev, 6, 0x1a); - rtl8180_write_phy(dev, 7, 0x64); - - sa2400_write_phy_antenna(dev, 1); - - rtl8180_write_phy(dev, 0x11, 0x80); - - if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & - RTL818X_CONFIG2_ANTENNA_DIV) - rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ - else - rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ - - rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); - - rtl8180_write_phy(dev, 0x19, 0x0); - rtl8180_write_phy(dev, 0x1a, 0xa0); -} - -const struct rtl818x_rf_ops sa2400_rf_ops = { - .name = "Philips", - .init = sa2400_rf_init, - .stop = sa2400_rf_stop, - .set_chan = sa2400_rf_set_channel -}; diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl8180_sa2400.h deleted file mode 100644 index a4aaa0d..0000000 --- a/drivers/net/wireless/rtl8180_sa2400.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef RTL8180_SA2400_H -#define RTL8180_SA2400_H - -/* - * Radio tuning for Philips SA2400 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define SA2400_ANTENNA 0x91 -#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 -#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 -#define SA2400_ANAPARAM_PWR0_ON 0x3 - -/* RX sensitivity in dbm */ -#define SA2400_MAX_SENS 85 - -#define SA2400_REG4_FIRDAC_SHIFT 7 - -extern const struct rtl818x_rf_ops sa2400_rf_ops; - -#endif /* RTL8180_SA2400_H */ diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h deleted file mode 100644 index 33725d0..0000000 --- a/drivers/net/wireless/rtl8187.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Definitions for RTL8187 hardware - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef RTL8187_H -#define RTL8187_H - -#include "rtl818x.h" - -#define RTL8187_EEPROM_TXPWR_BASE 0x05 -#define RTL8187_EEPROM_MAC_ADDR 0x07 -#define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */ -#define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */ -#define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */ - -#define RTL8187_REQT_READ 0xC0 -#define RTL8187_REQT_WRITE 0x40 -#define RTL8187_REQ_GET_REG 0x05 -#define RTL8187_REQ_SET_REG 0x05 - -#define RTL8187_MAX_RX 0x9C4 - -struct rtl8187_rx_info { - struct urb *urb; - struct ieee80211_hw *dev; -}; - -struct rtl8187_rx_hdr { - __le32 flags; - u8 noise; - u8 signal; - u8 agc; - u8 reserved; - __le64 mac_time; -} __attribute__((packed)); - -struct rtl8187b_rx_hdr { - __le32 flags; - __le64 mac_time; - u8 sq; - u8 rssi; - u8 agc; - u8 flags2; - __le16 snr_long2end; - s8 pwdb_g12; - u8 fot; -} __attribute__((packed)); - -/* {rtl8187,rtl8187b}_tx_info is in skb */ - -struct rtl8187_tx_hdr { - __le32 flags; - __le16 rts_duration; - __le16 len; - __le32 retry; -} __attribute__((packed)); - -struct rtl8187b_tx_hdr { - __le32 flags; - __le16 rts_duration; - __le16 len; - __le32 unused_1; - __le16 unused_2; - __le16 tx_duration; - __le32 unused_3; - __le32 retry; - __le32 unused_4[2]; -} __attribute__((packed)); - -enum { - DEVICE_RTL8187, - DEVICE_RTL8187B -}; - -struct rtl8187_priv { - /* common between rtl818x drivers */ - struct rtl818x_csr *map; - const struct rtl818x_rf_ops *rf; - struct ieee80211_vif *vif; - int mode; - /* The mutex protects the TX loopback state. - * Any attempt to set channels concurrently locks the device. - */ - struct mutex conf_mutex; - - /* rtl8187 specific */ - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; - struct ieee80211_supported_band band; - struct usb_device *udev; - u32 rx_conf; - u16 txpwr_base; - u8 asic_rev; - u8 is_rtl8187b; - enum { - RTL8187BvB, - RTL8187BvD, - RTL8187BvE - } hw_rev; - struct sk_buff_head rx_queue; - u8 signal; - u8 quality; - u8 noise; -}; - -void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); - -static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv, - u8 *addr, u8 idx) -{ - u8 val; - - usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), - RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); - - return val; -} - -static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) -{ - return rtl818x_ioread8_idx(priv, addr, 0); -} - -static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv, - __le16 *addr, u8 idx) -{ - __le16 val; - - usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), - RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); - - return le16_to_cpu(val); -} - -static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) -{ - return rtl818x_ioread16_idx(priv, addr, 0); -} - -static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv, - __le32 *addr, u8 idx) -{ - __le32 val; - - usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), - RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); - - return le32_to_cpu(val); -} - -static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) -{ - return rtl818x_ioread32_idx(priv, addr, 0); -} - -static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv, - u8 *addr, u8 val, u8 idx) -{ - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); -} - -static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val) -{ - rtl818x_iowrite8_idx(priv, addr, val, 0); -} - -static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv, - __le16 *addr, u16 val, u8 idx) -{ - __le16 buf = cpu_to_le16(val); - - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), - HZ / 2); -} - -static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr, - u16 val) -{ - rtl818x_iowrite16_idx(priv, addr, val, 0); -} - -static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv, - __le32 *addr, u32 val, u8 idx) -{ - __le32 buf = cpu_to_le32(val); - - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), - HZ / 2); -} - -static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr, - u32 val) -{ - rtl818x_iowrite32_idx(priv, addr, val, 0); -} - -#endif /* RTL8187_H */ diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c deleted file mode 100644 index e1399d0..0000000 --- a/drivers/net/wireless/rtl8187_dev.c +++ /dev/null @@ -1,1298 +0,0 @@ -/* - * Linux device driver for RTL8187 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * Magic delays and register offsets below are taken from the original - * r8187 driver sources. Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include "rtl8187.h" -#include "rtl8187_rtl8225.h" - -MODULE_AUTHOR("Michael Wu "); -MODULE_AUTHOR("Andrea Merello "); -MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); -MODULE_LICENSE("GPL"); - -static struct usb_device_id rtl8187_table[] __devinitdata = { - /* Asus */ - {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, - /* Belkin */ - {USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B}, - /* Realtek */ - {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, - {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, - {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B}, - /* Netgear */ - {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0846, 0x4260), .driver_info = DEVICE_RTL8187B}, - /* HP */ - {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187}, - /* Sitecom */ - {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B}, - /* Abocom */ - {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187}, - {} -}; - -MODULE_DEVICE_TABLE(usb, rtl8187_table); - -static const struct ieee80211_rate rtl818x_rates[] = { - { .bitrate = 10, .hw_value = 0, }, - { .bitrate = 20, .hw_value = 1, }, - { .bitrate = 55, .hw_value = 2, }, - { .bitrate = 110, .hw_value = 3, }, - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static const struct ieee80211_channel rtl818x_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - -static void rtl8187_iowrite_async_cb(struct urb *urb) -{ - kfree(urb->context); - usb_free_urb(urb); -} - -static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, - void *data, u16 len) -{ - struct usb_ctrlrequest *dr; - struct urb *urb; - struct rtl8187_async_write_data { - u8 data[4]; - struct usb_ctrlrequest dr; - } *buf; - int rc; - - buf = kmalloc(sizeof(*buf), GFP_ATOMIC); - if (!buf) - return; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(buf); - return; - } - - dr = &buf->dr; - - dr->bRequestType = RTL8187_REQT_WRITE; - dr->bRequest = RTL8187_REQ_SET_REG; - dr->wValue = addr; - dr->wIndex = 0; - dr->wLength = cpu_to_le16(len); - - memcpy(buf, data, len); - - usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), - (unsigned char *)dr, buf, len, - rtl8187_iowrite_async_cb, buf); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) { - kfree(buf); - usb_free_urb(urb); - } -} - -static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, - __le32 *addr, u32 val) -{ - __le32 buf = cpu_to_le32(val); - - rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), - &buf, sizeof(buf)); -} - -void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8187_priv *priv = dev->priv; - - data <<= 8; - data |= addr | 0x80; - - rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF); - rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); - rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); - rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); -} - -static void rtl8187_tx_cb(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *)urb->context; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->rate_driver_data[0]; - struct rtl8187_priv *priv = hw->priv; - - usb_free_urb(info->rate_driver_data[1]); - skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : - sizeof(struct rtl8187_tx_hdr)); - ieee80211_tx_info_clear_status(info); - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(hw, skb); -} - -static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct rtl8187_priv *priv = dev->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - unsigned int ep; - void *buf; - struct urb *urb; - __le16 rts_dur = 0; - u32 flags; - int rc; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree_skb(skb); - return 0; - } - - flags = skb->len; - flags |= RTL818X_TX_DESC_FLAG_NO_ENC; - - flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; - if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) - flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; - if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - flags |= RTL818X_TX_DESC_FLAG_RTS; - flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - rts_dur = ieee80211_rts_duration(dev, priv->vif, - skb->len, info); - } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - flags |= RTL818X_TX_DESC_FLAG_CTS; - flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } - - if (!priv->is_rtl8187b) { - struct rtl8187_tx_hdr *hdr = - (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); - hdr->flags = cpu_to_le32(flags); - hdr->len = 0; - hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); - buf = hdr; - - ep = 2; - } else { - /* fc needs to be calculated before skb_push() */ - unsigned int epmap[4] = { 6, 7, 5, 4 }; - struct ieee80211_hdr *tx_hdr = - (struct ieee80211_hdr *)(skb->data); - u16 fc = le16_to_cpu(tx_hdr->frame_control); - - struct rtl8187b_tx_hdr *hdr = - (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); - struct ieee80211_rate *txrate = - ieee80211_get_tx_rate(dev, info); - memset(hdr, 0, sizeof(*hdr)); - hdr->flags = cpu_to_le32(flags); - hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); - hdr->tx_duration = - ieee80211_generic_frame_duration(dev, priv->vif, - skb->len, txrate); - buf = hdr; - - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - ep = 12; - else - ep = epmap[skb_get_queue_mapping(skb)]; - } - - info->rate_driver_data[0] = dev; - info->rate_driver_data[1] = urb; - - usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), - buf, skb->len, rtl8187_tx_cb, skb); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) { - usb_free_urb(urb); - kfree_skb(skb); - } - - return 0; -} - -static void rtl8187_rx_cb(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *)urb->context; - struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; - struct ieee80211_hw *dev = info->dev; - struct rtl8187_priv *priv = dev->priv; - struct ieee80211_rx_status rx_status = { 0 }; - int rate, signal; - u32 flags; - u32 quality; - - spin_lock(&priv->rx_queue.lock); - if (skb->next) - __skb_unlink(skb, &priv->rx_queue); - else { - spin_unlock(&priv->rx_queue.lock); - return; - } - spin_unlock(&priv->rx_queue.lock); - - if (unlikely(urb->status)) { - usb_free_urb(urb); - dev_kfree_skb_irq(skb); - return; - } - - skb_put(skb, urb->actual_length); - if (!priv->is_rtl8187b) { - struct rtl8187_rx_hdr *hdr = - (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); - flags = le32_to_cpu(hdr->flags); - signal = hdr->signal & 0x7f; - rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.noise = hdr->noise; - rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->quality = signal; - rx_status.qual = priv->quality; - priv->noise = hdr->noise; - rate = (flags >> 20) & 0xF; - if (rate > 3) { /* OFDM rate */ - if (signal > 90) - signal = 90; - else if (signal < 25) - signal = 25; - signal = 90 - signal; - } else { /* CCK rate */ - if (signal > 95) - signal = 95; - else if (signal < 30) - signal = 30; - signal = 95 - signal; - } - rx_status.signal = signal; - priv->signal = signal; - } else { - struct rtl8187b_rx_hdr *hdr = - (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); - /* The Realtek datasheet for the RTL8187B shows that the RX - * header contains the following quantities: signal quality, - * RSSI, AGC, the received power in dB, and the measured SNR. - * In testing, none of these quantities show qualitative - * agreement with AP signal strength, except for the AGC, - * which is inversely proportional to the strength of the - * signal. In the following, the quality and signal strength - * are derived from the AGC. The arbitrary scaling constants - * are chosen to make the results close to the values obtained - * for a BCM4312 using b43 as the driver. The noise is ignored - * for now. - */ - flags = le32_to_cpu(hdr->flags); - quality = 170 - hdr->agc; - if (quality > 100) - quality = 100; - signal = 14 - hdr->agc / 2; - rx_status.qual = quality; - priv->quality = quality; - rx_status.signal = signal; - priv->signal = signal; - rx_status.antenna = (hdr->rssi >> 7) & 1; - rx_status.mactime = le64_to_cpu(hdr->mac_time); - rate = (flags >> 20) & 0xF; - } - - skb_trim(skb, flags & 0x0FFF); - rx_status.rate_idx = rate; - rx_status.freq = dev->conf.channel->center_freq; - rx_status.band = dev->conf.channel->band; - rx_status.flag |= RX_FLAG_TSFT; - if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - ieee80211_rx_irqsafe(dev, skb, &rx_status); - - skb = dev_alloc_skb(RTL8187_MAX_RX); - if (unlikely(!skb)) { - usb_free_urb(urb); - /* TODO check rx queue length and refill *somewhere* */ - return; - } - - info = (struct rtl8187_rx_info *)skb->cb; - info->urb = urb; - info->dev = dev; - urb->transfer_buffer = skb_tail_pointer(skb); - urb->context = skb; - skb_queue_tail(&priv->rx_queue, skb); - - usb_submit_urb(urb, GFP_ATOMIC); -} - -static int rtl8187_init_urbs(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - struct urb *entry; - struct sk_buff *skb; - struct rtl8187_rx_info *info; - - while (skb_queue_len(&priv->rx_queue) < 8) { - skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); - if (!skb) - break; - entry = usb_alloc_urb(0, GFP_KERNEL); - if (!entry) { - kfree_skb(skb); - break; - } - usb_fill_bulk_urb(entry, priv->udev, - usb_rcvbulkpipe(priv->udev, - priv->is_rtl8187b ? 3 : 1), - skb_tail_pointer(skb), - RTL8187_MAX_RX, rtl8187_rx_cb, skb); - info = (struct rtl8187_rx_info *)skb->cb; - info->urb = entry; - info->dev = dev; - skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); - } - - return 0; -} - -static int rtl8187_cmd_reset(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - u8 reg; - int i; - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= (1 << 1); - reg |= RTL818X_CMD_RESET; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - i = 10; - do { - msleep(2); - if (!(rtl818x_ioread8(priv, &priv->map->CMD) & - RTL818X_CMD_RESET)) - break; - } while (--i); - - if (!i) { - printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy)); - return -ETIMEDOUT; - } - - /* reload registers from eeprom */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); - - i = 10; - do { - msleep(4); - if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) & - RTL818X_EEPROM_CMD_CONFIG)) - break; - } while (--i); - - if (!i) { - printk(KERN_ERR "%s: eeprom reset timeout!\n", - wiphy_name(dev->wiphy)); - return -ETIMEDOUT; - } - - return 0; -} - -static int rtl8187_init_hw(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - u8 reg; - int res; - - /* reset */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | - RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & - ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - msleep(200); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); - msleep(200); - - res = rtl8187_cmd_reset(dev); - if (res) - return res; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - /* setup card */ - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); - - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 1); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - - rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); - reg &= 0x3F; - reg |= 0x80; - rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); - rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); - - // TODO: set RESP_RATE and BRSR properly - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - - /* host_usb_init */ - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); - reg = rtl818x_ioread8(priv, (u8 *)0xFE53); - rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80); - msleep(100); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); - rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); - msleep(100); - - priv->rf->init(dev); - - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); - rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); - rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); - rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); - - return 0; -} - -static const u8 rtl8187b_reg_table[][3] = { - {0xF0, 0x32, 0}, {0xF1, 0x32, 0}, {0xF2, 0x00, 0}, {0xF3, 0x00, 0}, - {0xF4, 0x32, 0}, {0xF5, 0x43, 0}, {0xF6, 0x00, 0}, {0xF7, 0x00, 0}, - {0xF8, 0x46, 0}, {0xF9, 0xA4, 0}, {0xFA, 0x00, 0}, {0xFB, 0x00, 0}, - {0xFC, 0x96, 0}, {0xFD, 0xA4, 0}, {0xFE, 0x00, 0}, {0xFF, 0x00, 0}, - - {0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1}, - {0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1}, - {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1}, - {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1}, - {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1}, - {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, - - {0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2}, - {0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2}, - {0x27, 0x8D, 2}, {0x4D, 0x08, 2}, {0x50, 0x05, 2}, {0x51, 0xF5, 2}, - {0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2}, - {0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2}, - {0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2}, - {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, - {0x73, 0x9A, 2}, - - {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, - {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, - {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, - {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, - {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, - - {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, - {0x8E, 0x08, 0}, {0x8F, 0x00, 0} -}; - -static int rtl8187b_init_hw(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int res, i; - u8 reg; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187B_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187B_RTL8225_ANAPARAM_ON); - rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, - RTL8187B_RTL8225_ANAPARAM3_ON); - - rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); - reg = rtl818x_ioread8(priv, (u8 *)0xFF62); - rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); - rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); - - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - res = rtl8187_cmd_reset(dev); - if (res) - return res; - - rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF); - reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); - reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; - rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT | - RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); - - rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); - reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK); - reg |= RTL818X_RATE_FALLBACK_ENABLE; - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg); - - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); - rtl818x_iowrite8(priv, &priv->map->CONFIG1, (reg & 0x3F) | 0x80); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - for (i = 0; i < ARRAY_SIZE(rtl8187b_reg_table); i++) { - rtl818x_iowrite8_idx(priv, - (u8 *)(uintptr_t) - (rtl8187b_reg_table[i][0] | 0xFF00), - rtl8187b_reg_table[i][1], - rtl8187b_reg_table[i][2]); - } - - rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50); - rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0); - - rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF0, 0, 1); - rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF4, 0, 1); - rtl818x_iowrite8_idx(priv, (u8 *)0xFFF8, 0, 1); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001); - - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - msleep(100); - - priv->rf->init(dev); - - reg = RTL818X_CMD_TX_ENABLE | RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - - rtl818x_iowrite8(priv, (u8 *)0xFE41, 0xF4); - rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x00); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); - rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x0F); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); - - reg = rtl818x_ioread8(priv, (u8 *)0xFFDB); - rtl818x_iowrite8(priv, (u8 *)0xFFDB, reg | (1 << 2)); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x59FA, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF74, 0x59D2, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF76, 0x59D2, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF78, 0x19FA, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7A, 0x19FA, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7C, 0x00D0, 3); - rtl818x_iowrite8(priv, (u8 *)0xFF61, 0); - rtl818x_iowrite8_idx(priv, (u8 *)0xFF80, 0x0F, 1); - rtl818x_iowrite8_idx(priv, (u8 *)0xFF83, 0x03, 1); - rtl818x_iowrite8(priv, (u8 *)0xFFDA, 0x10); - rtl818x_iowrite8_idx(priv, (u8 *)0xFF4D, 0x08, 2); - - rtl818x_iowrite32(priv, &priv->map->HSSI_PARA, 0x0600321B); - - rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); - - return 0; -} - -static int rtl8187_start(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - u32 reg; - int ret; - - ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : - rtl8187b_init_hw(dev); - if (ret) - return ret; - - mutex_lock(&priv->conf_mutex); - if (priv->is_rtl8187b) { - reg = RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_DATA | - RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_NICMAC | - RTL818X_RX_CONF_BSSID | - (7 << 13 /* RX FIFO threshold NONE */) | - (7 << 10 /* MAX RX DMA */) | - RTL818X_RX_CONF_RX_AUTORESETPHY | - RTL818X_RX_CONF_ONLYERLPKT | - RTL818X_RX_CONF_MULTICAST; - priv->rx_conf = reg; - rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - RTL818X_TX_CONF_HW_SEQNUM | - RTL818X_TX_CONF_DISREQQSIZE | - (7 << 8 /* short retry limit */) | - (7 << 0 /* long retry limit */) | - (7 << 21 /* MAX TX DMA */)); - rtl8187_init_urbs(dev); - mutex_unlock(&priv->conf_mutex); - return 0; - } - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - - rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); - rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); - - rtl8187_init_urbs(dev); - - reg = RTL818X_RX_CONF_ONLYERLPKT | - RTL818X_RX_CONF_RX_AUTORESETPHY | - RTL818X_RX_CONF_BSSID | - RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_DATA | - (7 << 13 /* RX FIFO threshold NONE */) | - (7 << 10 /* MAX RX DMA */) | - RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_NICMAC; - - priv->rx_conf = reg; - rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); - reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; - reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; - rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); - - reg = RTL818X_TX_CONF_CW_MIN | - (7 << 21 /* MAX TX DMA */) | - RTL818X_TX_CONF_NO_ICV; - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg |= RTL818X_CMD_TX_ENABLE; - reg |= RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - mutex_unlock(&priv->conf_mutex); - - return 0; -} - -static void rtl8187_stop(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - struct rtl8187_rx_info *info; - struct sk_buff *skb; - u32 reg; - - mutex_lock(&priv->conf_mutex); - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= ~RTL818X_CMD_TX_ENABLE; - reg &= ~RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - priv->rf->stop(dev); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); - rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct rtl8187_rx_info *)skb->cb; - usb_kill_urb(info->urb); - kfree_skb(skb); - } - mutex_unlock(&priv->conf_mutex); -} - -static int rtl8187_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - if (priv->mode != NL80211_IFTYPE_MONITOR) - return -EOPNOTSUPP; - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - priv->mode = conf->type; - break; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&priv->conf_mutex); - priv->vif = conf->vif; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->MAC[i], - ((u8 *)conf->mac_addr)[i]); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static void rtl8187_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - mutex_lock(&priv->conf_mutex); - priv->mode = NL80211_IFTYPE_MONITOR; - priv->vif = NULL; - mutex_unlock(&priv->conf_mutex); -} - -static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) -{ - struct rtl8187_priv *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - u32 reg; - - mutex_lock(&priv->conf_mutex); - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); - /* Enable TX loopback on MAC level to avoid TX during channel - * changes, as this has be seen to causes problems and the - * card will stop work until next reset - */ - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - reg | RTL818X_TX_CONF_LOOPBACK_MAC); - priv->rf->set_chan(dev, conf); - msleep(10); - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); - rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static int rtl8187_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - u8 reg; - - mutex_lock(&priv->conf_mutex); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) { - reg = RTL818X_MSR_INFRA; - if (priv->is_rtl8187b) - reg |= RTL818X_MSR_ENEDCA; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } else { - reg = RTL818X_MSR_NO_LINK; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } - - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, - bool use_short_preamble) -{ - if (priv->is_rtl8187b) { - u8 difs, eifs, slot_time; - u16 ack_timeout; - - if (use_short_slot) { - slot_time = 0x9; - difs = 0x1c; - eifs = 0x53; - } else { - slot_time = 0x14; - difs = 0x32; - eifs = 0x5b; - } - rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); - rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); - rtl818x_iowrite8(priv, &priv->map->DIFS, difs); - - /* - * BRSR+1 on 8187B is in fact EIFS register - * Value in units of 4 us - */ - rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); - - /* - * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout - * register. In units of 4 us like eifs register - * ack_timeout = ack duration + plcp + difs + preamble - */ - ack_timeout = 112 + 48 + difs; - if (use_short_preamble) - ack_timeout += 72; - else - ack_timeout += 144; - rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, - DIV_ROUND_UP(ack_timeout, 4)); - } else { - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - if (use_short_slot) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } - } -} - -static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct rtl8187_priv *priv = dev->priv; - - if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) - rtl8187_conf_erp(priv, info->use_short_slot, - info->use_short_preamble); -} - -static void rtl8187_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) -{ - struct rtl8187_priv *priv = dev->priv; - - if (changed_flags & FIF_FCSFAIL) - priv->rx_conf ^= RTL818X_RX_CONF_FCS; - if (changed_flags & FIF_CONTROL) - priv->rx_conf ^= RTL818X_RX_CONF_CTRL; - if (changed_flags & FIF_OTHER_BSS) - priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) - priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; - else - priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; - - *total_flags = 0; - - if (priv->rx_conf & RTL818X_RX_CONF_FCS) - *total_flags |= FIF_FCSFAIL; - if (priv->rx_conf & RTL818X_RX_CONF_CTRL) - *total_flags |= FIF_CONTROL; - if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) - *total_flags |= FIF_OTHER_BSS; - if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) - *total_flags |= FIF_ALLMULTI; - - rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); -} - -static const struct ieee80211_ops rtl8187_ops = { - .tx = rtl8187_tx, - .start = rtl8187_start, - .stop = rtl8187_stop, - .add_interface = rtl8187_add_interface, - .remove_interface = rtl8187_remove_interface, - .config = rtl8187_config, - .config_interface = rtl8187_config_interface, - .bss_info_changed = rtl8187_bss_info_changed, - .configure_filter = rtl8187_configure_filter, -}; - -static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8187_priv *priv = dev->priv; - u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - - eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; - eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; - eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; - eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; -} - -static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8187_priv *priv = dev->priv; - u8 reg = RTL818X_EEPROM_CMD_PROGRAM; - - if (eeprom->reg_data_in) - reg |= RTL818X_EEPROM_CMD_WRITE; - if (eeprom->reg_data_out) - reg |= RTL818X_EEPROM_CMD_READ; - if (eeprom->reg_data_clock) - reg |= RTL818X_EEPROM_CMD_CK; - if (eeprom->reg_chip_select) - reg |= RTL818X_EEPROM_CMD_CS; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); - udelay(10); -} - -static int __devinit rtl8187_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct ieee80211_hw *dev; - struct rtl8187_priv *priv; - struct eeprom_93cx6 eeprom; - struct ieee80211_channel *channel; - const char *chip_name; - u16 txpwr, reg; - int err, i; - - dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); - if (!dev) { - printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n"); - return -ENOMEM; - } - - priv = dev->priv; - priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B); - - SET_IEEE80211_DEV(dev, &intf->dev); - usb_set_intfdata(intf, dev); - priv->udev = udev; - - usb_get_dev(udev); - - skb_queue_head_init(&priv->rx_queue); - - BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); - BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); - - memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); - memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); - priv->map = (struct rtl818x_csr *)0xFF00; - - priv->band.band = IEEE80211_BAND_2GHZ; - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - - - priv->mode = NL80211_IFTYPE_MONITOR; - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; - - eeprom.data = dev; - eeprom.register_read = rtl8187_eeprom_register_read; - eeprom.register_write = rtl8187_eeprom_register_write; - if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) - eeprom.width = PCI_EEPROM_WIDTH_93C66; - else - eeprom.width = PCI_EEPROM_WIDTH_93C46; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - udelay(10); - - eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR, - (__le16 __force *)dev->wiphy->perm_addr, 3); - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly " - "generated MAC address\n"); - random_ether_addr(dev->wiphy->perm_addr); - } - - channel = priv->channels; - for (i = 0; i < 3; i++) { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - for (i = 0; i < 2; i++) { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, - &priv->txpwr_base); - - reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); - /* 0 means asic B-cut, we should use SW 3 wire - * bit-by-bit banging for radio. 1 means we can use - * USB specific request to write radio registers */ - priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3; - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - if (!priv->is_rtl8187b) { - u32 reg32; - reg32 = rtl818x_ioread32(priv, &priv->map->TX_CONF); - reg32 &= RTL818X_TX_CONF_HWVER_MASK; - switch (reg32) { - case RTL818X_TX_CONF_R8187vD_B: - /* Some RTL8187B devices have a USB ID of 0x8187 - * detect them here */ - chip_name = "RTL8187BvB(early)"; - priv->is_rtl8187b = 1; - priv->hw_rev = RTL8187BvB; - break; - case RTL818X_TX_CONF_R8187vD: - chip_name = "RTL8187vD"; - break; - default: - chip_name = "RTL8187vB (default)"; - } - } else { - /* - * Force USB request to write radio registers for 8187B, Realtek - * only uses it in their sources - */ - /*if (priv->asic_rev == 0) { - printk(KERN_WARNING "rtl8187: Forcing use of USB " - "requests to write to radio registers\n"); - priv->asic_rev = 1; - }*/ - switch (rtl818x_ioread8(priv, (u8 *)0xFFE1)) { - case RTL818X_R8187B_B: - chip_name = "RTL8187BvB"; - priv->hw_rev = RTL8187BvB; - break; - case RTL818X_R8187B_D: - chip_name = "RTL8187BvD"; - priv->hw_rev = RTL8187BvD; - break; - case RTL818X_R8187B_E: - chip_name = "RTL8187BvE"; - priv->hw_rev = RTL8187BvE; - break; - default: - chip_name = "RTL8187BvB (default)"; - priv->hw_rev = RTL8187BvB; - } - } - - if (!priv->is_rtl8187b) { - for (i = 0; i < 2; i++) { - eeprom_93cx6_read(&eeprom, - RTL8187_EEPROM_TXPWR_CHAN_6 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - } else { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - - eeprom_93cx6_read(&eeprom, 0x0A, &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - - eeprom_93cx6_read(&eeprom, 0x1C, &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - - if (priv->is_rtl8187b) { - printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " - "is EXPERIMENTAL, and could damage your\n" - " hardware, use at your own risk\n"); - dev->flags |= IEEE80211_HW_SIGNAL_DBM; - } else { - dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; - dev->max_signal = 65; - } - - /* - * XXX: Once this driver supports anything that requires - * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. - */ - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - - if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) - printk(KERN_INFO "rtl8187: inconsistency between id with OEM" - " info!\n"); - - priv->rf = rtl8187_detect_rf(dev); - dev->extra_tx_headroom = (!priv->is_rtl8187b) ? - sizeof(struct rtl8187_tx_hdr) : - sizeof(struct rtl8187b_tx_hdr); - if (!priv->is_rtl8187b) - dev->queues = 1; - else - dev->queues = 4; - - err = ieee80211_register_hw(dev); - if (err) { - printk(KERN_ERR "rtl8187: Cannot register device\n"); - goto err_free_dev; - } - mutex_init(&priv->conf_mutex); - - printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", - wiphy_name(dev->wiphy), dev->wiphy->perm_addr, - chip_name, priv->asic_rev, priv->rf->name); - - return 0; - - err_free_dev: - ieee80211_free_hw(dev); - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - return err; -} - -static void __devexit rtl8187_disconnect(struct usb_interface *intf) -{ - struct ieee80211_hw *dev = usb_get_intfdata(intf); - struct rtl8187_priv *priv; - - if (!dev) - return; - - ieee80211_unregister_hw(dev); - - priv = dev->priv; - usb_put_dev(interface_to_usbdev(intf)); - ieee80211_free_hw(dev); -} - -static struct usb_driver rtl8187_driver = { - .name = KBUILD_MODNAME, - .id_table = rtl8187_table, - .probe = rtl8187_probe, - .disconnect = __devexit_p(rtl8187_disconnect), -}; - -static int __init rtl8187_init(void) -{ - return usb_register(&rtl8187_driver); -} - -static void __exit rtl8187_exit(void) -{ - usb_deregister(&rtl8187_driver); -} - -module_init(rtl8187_init); -module_exit(rtl8187_exit); diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c deleted file mode 100644 index 69030be..0000000 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Radio tuning for RTL8225 on RTL8187 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * Magic delays, register offsets, and phy value tables below are - * taken from the original r8187 driver sources. Thanks to Realtek - * for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include "rtl8187.h" -#include "rtl8187_rtl8225.h" - -static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) -{ - struct rtl8187_priv *priv = dev->priv; - u16 reg80, reg84, reg82; - u32 bangdata; - int i; - - bangdata = (data << 4) | (addr & 0xf); - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); - - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - udelay(10); - - for (i = 15; i >= 0; i--) { - u16 reg = reg80 | (bangdata & (1 << i)) >> i; - - if (i & 1) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - - if (!(i & 1)) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); -} - -static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) -{ - struct rtl8187_priv *priv = dev->priv; - u16 reg80, reg82, reg84; - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - - reg80 &= ~(0x3 << 2); - reg84 &= ~0xF; - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - udelay(10); - - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - addr, 0x8225, &data, sizeof(data), HZ / 2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); -} - -static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) -{ - struct rtl8187_priv *priv = dev->priv; - - if (priv->asic_rev) - rtl8225_write_8051(dev, addr, cpu_to_le16(data)); - else - rtl8225_write_bitbang(dev, addr, data); -} - -static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) -{ - struct rtl8187_priv *priv = dev->priv; - u16 reg80, reg82, reg84, out; - int i; - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - - reg80 &= ~0xF; - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(4); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - udelay(5); - - for (i = 4; i >= 0; i--) { - u16 reg = reg80 | ((addr >> i) & 1); - - if (!(i & 1)) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - udelay(1); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - udelay(2); - - if (i & 1) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - udelay(1); - } - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(2); - - out = 0; - for (i = 11; i >= 0; i--) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(1); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - - if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) - out |= 1 << i; - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(2); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 2)); - udelay(2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); - - return out; -} - -static const u16 rtl8225bcd_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, - 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb -}; - -static const u8 rtl8225_agc[] = { - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, - 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, - 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, - 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, - 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, - 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, - 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, - 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 -}; - -static const u8 rtl8225_gain[] = { - 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */ - 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */ - 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */ - 0x33, 0x80, 0x79, 0xc5, /* -78dBm */ - 0x43, 0x78, 0x76, 0xc5, /* -74dBm */ - 0x53, 0x60, 0x73, 0xc5, /* -70dBm */ - 0x63, 0x58, 0x70, 0xc5, /* -66dBm */ -}; - -static const u8 rtl8225_threshold[] = { - 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd -}; - -static const u8 rtl8225_tx_gain_cck_ofdm[] = { - 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e -}; - -static const u8 rtl8225_tx_power_cck[] = { - 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, - 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, - 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, - 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 -}; - -static const u8 rtl8225_tx_power_cck_ch14[] = { - 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225_tx_power_ofdm[] = { - 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 -}; - -static const u32 rtl8225_chan[] = { - 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, - 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 -}; - -static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8187_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - u32 reg; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xF; - ofdm_power = priv->channels[channel - 1].hw_value >> 4; - - cck_power = min(cck_power, (u8)11); - ofdm_power = min(ofdm_power, (u8)35); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); - - if (channel == 14) - tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; - else - tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - msleep(1); // FIXME: optional? - - /* anaparam2 on */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl8225_write_phy_ofdm(dev, 2, 0x42); - rtl8225_write_phy_ofdm(dev, 6, 0x00); - rtl8225_write_phy_ofdm(dev, 8, 0x00); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1); - - tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; - - rtl8225_write_phy_ofdm(dev, 5, *tmp); - rtl8225_write_phy_ofdm(dev, 7, *tmp); - - msleep(1); -} - -static void rtl8225_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - rtl8225_write(dev, 0x0, 0x067); - rtl8225_write(dev, 0x1, 0xFE0); - rtl8225_write(dev, 0x2, 0x44D); - rtl8225_write(dev, 0x3, 0x441); - rtl8225_write(dev, 0x4, 0x486); - rtl8225_write(dev, 0x5, 0xBC0); - rtl8225_write(dev, 0x6, 0xAE6); - rtl8225_write(dev, 0x7, 0x82A); - rtl8225_write(dev, 0x8, 0x01F); - rtl8225_write(dev, 0x9, 0x334); - rtl8225_write(dev, 0xA, 0xFD4); - rtl8225_write(dev, 0xB, 0x391); - rtl8225_write(dev, 0xC, 0x050); - rtl8225_write(dev, 0xD, 0x6DB); - rtl8225_write(dev, 0xE, 0x029); - rtl8225_write(dev, 0xF, 0x914); msleep(100); - - rtl8225_write(dev, 0x2, 0xC4D); msleep(200); - rtl8225_write(dev, 0x2, 0x44D); msleep(200); - - if (!(rtl8225_read(dev, 6) & (1 << 7))) { - rtl8225_write(dev, 0x02, 0x0c4d); - msleep(200); - rtl8225_write(dev, 0x02, 0x044d); - msleep(100); - if (!(rtl8225_read(dev, 6) & (1 << 7))) - printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", - wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); - } - - rtl8225_write(dev, 0x0, 0x127); - - for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); - } - - rtl8225_write(dev, 0x0, 0x027); - rtl8225_write(dev, 0x0, 0x22F); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - } - - msleep(1); - - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); - rtl8225_write_phy_ofdm(dev, 0x11, 0x06); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); - rtl8225_write_phy_ofdm(dev, 0x21, 0x27); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); - rtl8225_write_phy_ofdm(dev, 0x25, 0x20); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); - - rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); - rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); - rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); - rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); - - rtl8225_write_phy_cck(dev, 0x00, 0x98); - rtl8225_write_phy_cck(dev, 0x03, 0x20); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); - rtl8225_write_phy_cck(dev, 0x05, 0x12); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); - rtl8225_write_phy_cck(dev, 0x07, 0x78); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); - rtl8225_write_phy_cck(dev, 0x11, 0x88); - rtl8225_write_phy_cck(dev, 0x12, 0x47); - rtl8225_write_phy_cck(dev, 0x13, 0xd0); - rtl8225_write_phy_cck(dev, 0x19, 0x00); - rtl8225_write_phy_cck(dev, 0x1a, 0xa0); - rtl8225_write_phy_cck(dev, 0x1b, 0x08); - rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); - rtl8225_write_phy_cck(dev, 0x42, 0x15); - rtl8225_write_phy_cck(dev, 0x43, 0x18); - rtl8225_write_phy_cck(dev, 0x44, 0x1f); - rtl8225_write_phy_cck(dev, 0x45, 0x1e); - rtl8225_write_phy_cck(dev, 0x46, 0x1a); - rtl8225_write_phy_cck(dev, 0x47, 0x15); - rtl8225_write_phy_cck(dev, 0x48, 0x10); - rtl8225_write_phy_cck(dev, 0x49, 0x0a); - rtl8225_write_phy_cck(dev, 0x4a, 0x05); - rtl8225_write_phy_cck(dev, 0x4b, 0x02); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); - - rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); - - rtl8225_rf_set_tx_power(dev, 1); - - /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); - - /* set sensitivity */ - rtl8225_write(dev, 0x0c, 0x50); - rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); - rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); - rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); - rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); - rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]); -} - -static const u8 rtl8225z2_agc[] = { - 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f, - 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37, - 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f, - 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07, - 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, - 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 -}; -static const u8 rtl8225z2_ofdm[] = { - 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, - 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, - 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f, - 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, - 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, - 0x6d, 0x3c, 0xfb, 0x07 -}; - -static const u8 rtl8225z2_tx_power_cck_ch14[] = { - 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225z2_tx_power_cck[] = { - 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, - 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 -}; - -static const u8 rtl8225z2_tx_power_ofdm[] = { - 0x42, 0x00, 0x40, 0x00, 0x40 -}; - -static const u8 rtl8225z2_tx_gain_cck_ofdm[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23 -}; - -static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8187_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - u32 reg; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xF; - ofdm_power = priv->channels[channel - 1].hw_value >> 4; - - cck_power = min(cck_power, (u8)15); - cck_power += priv->txpwr_base & 0xF; - cck_power = min(cck_power, (u8)35); - - ofdm_power = min(ofdm_power, (u8)15); - ofdm_power += priv->txpwr_base >> 4; - ofdm_power = min(ofdm_power, (u8)35); - - if (channel == 14) - tmp = rtl8225z2_tx_power_cck_ch14; - else - tmp = rtl8225z2_tx_power_cck; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power]); - msleep(1); - - /* anaparam2 on */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl8225_write_phy_ofdm(dev, 2, 0x42); - rtl8225_write_phy_ofdm(dev, 5, 0x00); - rtl8225_write_phy_ofdm(dev, 6, 0x40); - rtl8225_write_phy_ofdm(dev, 7, 0x00); - rtl8225_write_phy_ofdm(dev, 8, 0x40); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225z2_tx_gain_cck_ofdm[ofdm_power]); - msleep(1); -} - -static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8187_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xF; - ofdm_power = priv->channels[channel - 1].hw_value >> 4; - - if (cck_power > 15) - cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22; - else - cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7; - cck_power += priv->txpwr_base & 0xF; - cck_power = min(cck_power, (u8)35); - - if (ofdm_power > 15) - ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25; - else - ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10; - ofdm_power += (priv->txpwr_base >> 4) & 0xF; - ofdm_power = min(ofdm_power, (u8)35); - - if (channel == 14) - tmp = rtl8225z2_tx_power_cck_ch14; - else - tmp = rtl8225z2_tx_power_cck; - - if (priv->hw_rev == RTL8187BvB) { - if (cck_power <= 6) - ; /* do nothing */ - else if (cck_power <= 11) - tmp += 8; - else - tmp += 16; - } else { - if (cck_power <= 5) - ; /* do nothing */ - else if (cck_power <= 11) - tmp += 8; - else if (cck_power <= 17) - tmp += 16; - else - tmp += 24; - } - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); - msleep(1); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1); - if (priv->hw_rev == RTL8187BvB) { - if (ofdm_power <= 11) { - rtl8225_write_phy_ofdm(dev, 0x87, 0x60); - rtl8225_write_phy_ofdm(dev, 0x89, 0x60); - } else { - rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); - rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); - } - } else { - if (ofdm_power <= 11) { - rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); - rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); - } else if (ofdm_power <= 17) { - rtl8225_write_phy_ofdm(dev, 0x87, 0x54); - rtl8225_write_phy_ofdm(dev, 0x89, 0x54); - } else { - rtl8225_write_phy_ofdm(dev, 0x87, 0x50); - rtl8225_write_phy_ofdm(dev, 0x89, 0x50); - } - } - msleep(1); -} - -static const u16 rtl8225z2_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, - 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb -}; - -static const u8 rtl8225z2_gain_bg[] = { - 0x23, 0x15, 0xa5, /* -82-1dBm */ - 0x23, 0x15, 0xb5, /* -82-2dBm */ - 0x23, 0x15, 0xc5, /* -82-3dBm */ - 0x33, 0x15, 0xc5, /* -78dBm */ - 0x43, 0x15, 0xc5, /* -74dBm */ - 0x53, 0x15, 0xc5, /* -70dBm */ - 0x63, 0x15, 0xc5 /* -66dBm */ -}; - -static void rtl8225z2_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - rtl8225_write(dev, 0x0, 0x2BF); - rtl8225_write(dev, 0x1, 0xEE0); - rtl8225_write(dev, 0x2, 0x44D); - rtl8225_write(dev, 0x3, 0x441); - rtl8225_write(dev, 0x4, 0x8C3); - rtl8225_write(dev, 0x5, 0xC72); - rtl8225_write(dev, 0x6, 0x0E6); - rtl8225_write(dev, 0x7, 0x82A); - rtl8225_write(dev, 0x8, 0x03F); - rtl8225_write(dev, 0x9, 0x335); - rtl8225_write(dev, 0xa, 0x9D4); - rtl8225_write(dev, 0xb, 0x7BB); - rtl8225_write(dev, 0xc, 0x850); - rtl8225_write(dev, 0xd, 0xCDF); - rtl8225_write(dev, 0xe, 0x02B); - rtl8225_write(dev, 0xf, 0x114); - msleep(100); - - rtl8225_write(dev, 0x0, 0x1B7); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); - } - - rtl8225_write(dev, 0x3, 0x080); - rtl8225_write(dev, 0x5, 0x004); - rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x2, 0xc4D); - - msleep(200); - rtl8225_write(dev, 0x2, 0x44D); - msleep(100); - - if (!(rtl8225_read(dev, 6) & (1 << 7))) { - rtl8225_write(dev, 0x02, 0x0C4D); - msleep(200); - rtl8225_write(dev, 0x02, 0x044D); - msleep(100); - if (!(rtl8225_read(dev, 6) & (1 << 7))) - printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", - wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); - } - - msleep(200); - - rtl8225_write(dev, 0x0, 0x2BF); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - } - - msleep(1); - - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); - rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); - rtl8225_write_phy_ofdm(dev, 0x11, 0x07); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); - rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); - rtl8225_write_phy_ofdm(dev, 0x21, 0x17); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); - rtl8225_write_phy_ofdm(dev, 0x23, 0x80); - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); - rtl8225_write_phy_ofdm(dev, 0x25, 0x00); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); - - rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]); - rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]); - rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]); - rtl8225_write_phy_ofdm(dev, 0x21, 0x37); - - rtl8225_write_phy_cck(dev, 0x00, 0x98); - rtl8225_write_phy_cck(dev, 0x03, 0x20); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); - rtl8225_write_phy_cck(dev, 0x05, 0x12); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); - rtl8225_write_phy_cck(dev, 0x07, 0x78); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); - rtl8225_write_phy_cck(dev, 0x11, 0x88); - rtl8225_write_phy_cck(dev, 0x12, 0x47); - rtl8225_write_phy_cck(dev, 0x13, 0xd0); - rtl8225_write_phy_cck(dev, 0x19, 0x00); - rtl8225_write_phy_cck(dev, 0x1a, 0xa0); - rtl8225_write_phy_cck(dev, 0x1b, 0x08); - rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); - rtl8225_write_phy_cck(dev, 0x42, 0x15); - rtl8225_write_phy_cck(dev, 0x43, 0x18); - rtl8225_write_phy_cck(dev, 0x44, 0x36); - rtl8225_write_phy_cck(dev, 0x45, 0x35); - rtl8225_write_phy_cck(dev, 0x46, 0x2e); - rtl8225_write_phy_cck(dev, 0x47, 0x25); - rtl8225_write_phy_cck(dev, 0x48, 0x1c); - rtl8225_write_phy_cck(dev, 0x49, 0x12); - rtl8225_write_phy_cck(dev, 0x4a, 0x09); - rtl8225_write_phy_cck(dev, 0x4b, 0x04); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); - - rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1); - - rtl8225z2_rf_set_tx_power(dev, 1); - - /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); -} - -static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x1, 0xEE0); - rtl8225_write(dev, 0x2, 0x44D); - rtl8225_write(dev, 0x3, 0x441); - rtl8225_write(dev, 0x4, 0x8C3); - rtl8225_write(dev, 0x5, 0xC72); - rtl8225_write(dev, 0x6, 0x0E6); - rtl8225_write(dev, 0x7, 0x82A); - rtl8225_write(dev, 0x8, 0x03F); - rtl8225_write(dev, 0x9, 0x335); - rtl8225_write(dev, 0xa, 0x9D4); - rtl8225_write(dev, 0xb, 0x7BB); - rtl8225_write(dev, 0xc, 0x850); - rtl8225_write(dev, 0xd, 0xCDF); - rtl8225_write(dev, 0xe, 0x02B); - rtl8225_write(dev, 0xf, 0x114); - - rtl8225_write(dev, 0x0, 0x1B7); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); - } - - rtl8225_write(dev, 0x3, 0x080); - rtl8225_write(dev, 0x5, 0x004); - rtl8225_write(dev, 0x0, 0x0B7); - - rtl8225_write(dev, 0x2, 0xC4D); - - rtl8225_write(dev, 0x2, 0x44D); - rtl8225_write(dev, 0x0, 0x2BF); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03); - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07); - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); - - rtl8225_write_phy_ofdm(dev, 0x80, 0x12); - for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]); - rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i); - rtl8225_write_phy_ofdm(dev, 0xE, 0); - } - rtl8225_write_phy_ofdm(dev, 0x80, 0x10); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) - rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); - - rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); - - rtl8225_write_phy_ofdm(dev, 0x97, 0x46); - rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); - rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); - rtl8225_write_phy_cck(dev, 0xc1, 0x88); -} - -static void rtl8225_rf_stop(struct ieee80211_hw *dev) -{ - u8 reg; - struct rtl8187_priv *priv = dev->priv; - - rtl8225_write(dev, 0x4, 0x1f); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - if (!priv->is_rtl8187b) { - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_OFF); - } else { - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187B_RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187B_RTL8225_ANAPARAM_OFF); - rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, - RTL8187B_RTL8225_ANAPARAM3_OFF); - } - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); -} - -static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); - - if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, chan); - else if (priv->rf->init == rtl8225z2_rf_init) - rtl8225z2_rf_set_tx_power(dev, chan); - else - rtl8225z2_b_rf_set_tx_power(dev, chan); - - rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); - msleep(10); -} - -static const struct rtl818x_rf_ops rtl8225_ops = { - .name = "rtl8225", - .init = rtl8225_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -static const struct rtl818x_rf_ops rtl8225z2_ops = { - .name = "rtl8225z2", - .init = rtl8225z2_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -static const struct rtl818x_rf_ops rtl8225z2_b_ops = { - .name = "rtl8225z2", - .init = rtl8225z2_b_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev) -{ - u16 reg8, reg9; - struct rtl8187_priv *priv = dev->priv; - - if (!priv->is_rtl8187b) { - rtl8225_write(dev, 0, 0x1B7); - - reg8 = rtl8225_read(dev, 8); - reg9 = rtl8225_read(dev, 9); - - rtl8225_write(dev, 0, 0x0B7); - - if (reg8 != 0x588 || reg9 != 0x700) - return &rtl8225_ops; - - return &rtl8225z2_ops; - } else - return &rtl8225z2_b_ops; -} diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h deleted file mode 100644 index 20c5b6e..0000000 --- a/drivers/net/wireless/rtl8187_rtl8225.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Radio tuning definitions for RTL8225 on RTL8187 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef RTL8187_RTL8225_H -#define RTL8187_RTL8225_H - -#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59 -#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312 -#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59 -#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11 - -#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658 -#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52 -#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00 -#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658 -#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50 -#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00 - -const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *); - -static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, - u8 addr, u32 data) -{ - rtl8187_write_phy(dev, addr, data); -} - -static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, - u8 addr, u32 data) -{ - rtl8187_write_phy(dev, addr, data | 0x10000); -} - -#endif /* RTL8187_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h deleted file mode 100644 index 3538b15..0000000 --- a/drivers/net/wireless/rtl818x.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Definitions for RTL818x hardware - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef RTL818X_H -#define RTL818X_H - -struct rtl818x_csr { - u8 MAC[6]; - u8 reserved_0[2]; - __le32 MAR[2]; - u8 RX_FIFO_COUNT; - u8 reserved_1; - u8 TX_FIFO_COUNT; - u8 BQREQ; - u8 reserved_2[4]; - __le32 TSFT[2]; - __le32 TLPDA; - __le32 TNPDA; - __le32 THPDA; - __le16 BRSR; - u8 BSSID[6]; - u8 RESP_RATE; - u8 EIFS; - u8 reserved_3[1]; - u8 CMD; -#define RTL818X_CMD_TX_ENABLE (1 << 2) -#define RTL818X_CMD_RX_ENABLE (1 << 3) -#define RTL818X_CMD_RESET (1 << 4) - u8 reserved_4[4]; - __le16 INT_MASK; - __le16 INT_STATUS; -#define RTL818X_INT_RX_OK (1 << 0) -#define RTL818X_INT_RX_ERR (1 << 1) -#define RTL818X_INT_TXL_OK (1 << 2) -#define RTL818X_INT_TXL_ERR (1 << 3) -#define RTL818X_INT_RX_DU (1 << 4) -#define RTL818X_INT_RX_FO (1 << 5) -#define RTL818X_INT_TXN_OK (1 << 6) -#define RTL818X_INT_TXN_ERR (1 << 7) -#define RTL818X_INT_TXH_OK (1 << 8) -#define RTL818X_INT_TXH_ERR (1 << 9) -#define RTL818X_INT_TXB_OK (1 << 10) -#define RTL818X_INT_TXB_ERR (1 << 11) -#define RTL818X_INT_ATIM (1 << 12) -#define RTL818X_INT_BEACON (1 << 13) -#define RTL818X_INT_TIME_OUT (1 << 14) -#define RTL818X_INT_TX_FO (1 << 15) - __le32 TX_CONF; -#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17) -#define RTL818X_TX_CONF_LOOPBACK_CONT (3 << 17) -#define RTL818X_TX_CONF_NO_ICV (1 << 19) -#define RTL818X_TX_CONF_DISCW (1 << 20) -#define RTL818X_TX_CONF_SAT_HWPLCP (1 << 24) -#define RTL818X_TX_CONF_R8180_ABCD (2 << 25) -#define RTL818X_TX_CONF_R8180_F (3 << 25) -#define RTL818X_TX_CONF_R8185_ABC (4 << 25) -#define RTL818X_TX_CONF_R8185_D (5 << 25) -#define RTL818X_TX_CONF_R8187vD (5 << 25) -#define RTL818X_TX_CONF_R8187vD_B (6 << 25) -#define RTL818X_TX_CONF_HWVER_MASK (7 << 25) -#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28) -#define RTL818X_TX_CONF_PROBE_DTS (1 << 29) -#define RTL818X_TX_CONF_HW_SEQNUM (1 << 30) -#define RTL818X_TX_CONF_CW_MIN (1 << 31) - __le32 RX_CONF; -#define RTL818X_RX_CONF_MONITOR (1 << 0) -#define RTL818X_RX_CONF_NICMAC (1 << 1) -#define RTL818X_RX_CONF_MULTICAST (1 << 2) -#define RTL818X_RX_CONF_BROADCAST (1 << 3) -#define RTL818X_RX_CONF_FCS (1 << 5) -#define RTL818X_RX_CONF_DATA (1 << 18) -#define RTL818X_RX_CONF_CTRL (1 << 19) -#define RTL818X_RX_CONF_MGMT (1 << 20) -#define RTL818X_RX_CONF_ADDR3 (1 << 21) -#define RTL818X_RX_CONF_PM (1 << 22) -#define RTL818X_RX_CONF_BSSID (1 << 23) -#define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28) -#define RTL818X_RX_CONF_CSDM1 (1 << 29) -#define RTL818X_RX_CONF_CSDM2 (1 << 30) -#define RTL818X_RX_CONF_ONLYERLPKT (1 << 31) - __le32 INT_TIMEOUT; - __le32 TBDA; - u8 EEPROM_CMD; -#define RTL818X_EEPROM_CMD_READ (1 << 0) -#define RTL818X_EEPROM_CMD_WRITE (1 << 1) -#define RTL818X_EEPROM_CMD_CK (1 << 2) -#define RTL818X_EEPROM_CMD_CS (1 << 3) -#define RTL818X_EEPROM_CMD_NORMAL (0 << 6) -#define RTL818X_EEPROM_CMD_LOAD (1 << 6) -#define RTL818X_EEPROM_CMD_PROGRAM (2 << 6) -#define RTL818X_EEPROM_CMD_CONFIG (3 << 6) - u8 CONFIG0; - u8 CONFIG1; - u8 CONFIG2; -#define RTL818X_CONFIG2_ANTENNA_DIV (1 << 6) - __le32 ANAPARAM; - u8 MSR; -#define RTL818X_MSR_NO_LINK (0 << 2) -#define RTL818X_MSR_ADHOC (1 << 2) -#define RTL818X_MSR_INFRA (2 << 2) -#define RTL818X_MSR_MASTER (3 << 2) -#define RTL818X_MSR_ENEDCA (4 << 2) - u8 CONFIG3; -#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6) -#define RTL818X_CONFIG3_GNT_SELECT (1 << 7) - u8 CONFIG4; -#define RTL818X_CONFIG4_POWEROFF (1 << 6) -#define RTL818X_CONFIG4_VCOOFF (1 << 7) - u8 TESTR; - u8 reserved_9[2]; - u8 PGSELECT; - u8 SECURITY; - __le32 ANAPARAM2; - u8 reserved_10[12]; - __le16 BEACON_INTERVAL; - __le16 ATIM_WND; - __le16 BEACON_INTERVAL_TIME; - __le16 ATIMTR_INTERVAL; - u8 PHY_DELAY; - u8 CARRIER_SENSE_COUNTER; - u8 reserved_11[2]; - u8 PHY[4]; - __le16 RFPinsOutput; - __le16 RFPinsEnable; - __le16 RFPinsSelect; - __le16 RFPinsInput; - __le32 RF_PARA; - __le32 RF_TIMING; - u8 GP_ENABLE; - u8 GPIO; - u8 reserved_12[2]; - __le32 HSSI_PARA; - u8 reserved_13[4]; - u8 TX_AGC_CTL; -#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0) -#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1) -#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2) - u8 TX_GAIN_CCK; - u8 TX_GAIN_OFDM; - u8 TX_ANTENNA; - u8 reserved_14[16]; - u8 WPA_CONF; - u8 reserved_15[3]; - u8 SIFS; - u8 DIFS; - u8 SLOT; - u8 reserved_16[5]; - u8 CW_CONF; -#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0) -#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1) - u8 CW_VAL; - u8 RATE_FALLBACK; -#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7) - u8 ACM_CONTROL; - u8 reserved_17[24]; - u8 CONFIG5; - u8 TX_DMA_POLLING; - u8 reserved_18[2]; - __le16 CWR; - u8 RETRY_CTR; - u8 reserved_19[3]; - __le16 INT_MIG; -/* RTL818X_R8187B_*: magic numbers from ioregisters */ -#define RTL818X_R8187B_B 0 -#define RTL818X_R8187B_D 1 -#define RTL818X_R8187B_E 2 - __le32 RDSAR; - __le16 TID_AC_MAP; - u8 reserved_20[4]; - u8 ANAPARAM3; - u8 reserved_21[5]; - __le16 FEMR; - u8 reserved_22[4]; - __le16 TALLY_CNT; - u8 TALLY_SEL; -} __attribute__((packed)); - -struct rtl818x_rf_ops { - char *name; - void (*init)(struct ieee80211_hw *); - void (*stop)(struct ieee80211_hw *); - void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); -}; - -/* Tx/Rx flags are common between RTL818X chips */ - -enum rtl818x_tx_desc_flags { - RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), - RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), - RTL818X_TX_DESC_FLAG_SPLCP = (1 << 16), - RTL818X_TX_DESC_FLAG_RX_UNDER = (1 << 16), - RTL818X_TX_DESC_FLAG_MOREFRAG = (1 << 17), - RTL818X_TX_DESC_FLAG_CTS = (1 << 18), - RTL818X_TX_DESC_FLAG_RTS = (1 << 23), - RTL818X_TX_DESC_FLAG_LS = (1 << 28), - RTL818X_TX_DESC_FLAG_FS = (1 << 29), - RTL818X_TX_DESC_FLAG_DMA = (1 << 30), - RTL818X_TX_DESC_FLAG_OWN = (1 << 31) -}; - -enum rtl818x_rx_desc_flags { - RTL818X_RX_DESC_FLAG_ICV_ERR = (1 << 12), - RTL818X_RX_DESC_FLAG_CRC32_ERR = (1 << 13), - RTL818X_RX_DESC_FLAG_PM = (1 << 14), - RTL818X_RX_DESC_FLAG_RX_ERR = (1 << 15), - RTL818X_RX_DESC_FLAG_BCAST = (1 << 16), - RTL818X_RX_DESC_FLAG_PAM = (1 << 17), - RTL818X_RX_DESC_FLAG_MCAST = (1 << 18), - RTL818X_RX_DESC_FLAG_QOS = (1 << 19), /* RTL8187(B) only */ - RTL818X_RX_DESC_FLAG_TRSW = (1 << 24), /* RTL8187(B) only */ - RTL818X_RX_DESC_FLAG_SPLCP = (1 << 25), - RTL818X_RX_DESC_FLAG_FOF = (1 << 26), - RTL818X_RX_DESC_FLAG_DMA_FAIL = (1 << 27), - RTL818X_RX_DESC_FLAG_LS = (1 << 28), - RTL818X_RX_DESC_FLAG_FS = (1 << 29), - RTL818X_RX_DESC_FLAG_EOR = (1 << 30), - RTL818X_RX_DESC_FLAG_OWN = (1 << 31) -}; - -#endif /* RTL818X_H */ diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile new file mode 100644 index 0000000..c113b3e --- /dev/null +++ b/drivers/net/wireless/rtl818x/Makefile @@ -0,0 +1,7 @@ +rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o + +obj-$(CONFIG_RTL8180) += rtl8180.o +obj-$(CONFIG_RTL8187) += rtl8187.o + + diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h new file mode 100644 index 0000000..8721282 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180.h @@ -0,0 +1,120 @@ +#ifndef RTL8180_H +#define RTL8180_H + +#include "rtl818x.h" + +#define MAX_RX_SIZE IEEE80211_MAX_RTS_THRESHOLD + +#define RF_PARAM_ANALOGPHY (1 << 0) +#define RF_PARAM_ANTBDEFAULT (1 << 1) +#define RF_PARAM_CARRIERSENSE1 (1 << 2) +#define RF_PARAM_CARRIERSENSE2 (1 << 3) + +#define BB_ANTATTEN_CHAN14 0x0C +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1 << 30) +#define BB_HOST_BANG_EN (1 << 2) +#define BB_HOST_BANG_CLK (1 << 1) +#define BB_HOST_BANG_DATA 1 + +#define ANAPARAM_TXDACOFF_SHIFT 27 +#define ANAPARAM_PWR0_SHIFT 28 +#define ANAPARAM_PWR0_MASK (0x07 << ANAPARAM_PWR0_SHIFT) +#define ANAPARAM_PWR1_SHIFT 20 +#define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) + +struct rtl8180_tx_desc { + __le32 flags; + __le16 rts_duration; + __le16 plcp_len; + __le32 tx_buf; + __le32 frame_len; + __le32 next_tx_desc; + u8 cw; + u8 retry_limit; + u8 agc; + u8 flags2; + u32 reserved[2]; +} __attribute__ ((packed)); + +struct rtl8180_rx_desc { + __le32 flags; + __le32 flags2; + union { + __le32 rx_buf; + __le64 tsft; + }; +} __attribute__ ((packed)); + +struct rtl8180_tx_ring { + struct rtl8180_tx_desc *desc; + dma_addr_t dma; + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; +}; + +struct rtl8180_priv { + /* common between rtl818x drivers */ + struct rtl818x_csr __iomem *map; + const struct rtl818x_rf_ops *rf; + struct ieee80211_vif *vif; + int mode; + + /* rtl8180 driver specific */ + spinlock_t lock; + struct rtl8180_rx_desc *rx_ring; + dma_addr_t rx_ring_dma; + unsigned int rx_idx; + struct sk_buff *rx_buf[32]; + struct rtl8180_tx_ring tx_ring[4]; + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct pci_dev *pdev; + u32 rx_conf; + + int r8185; + u32 anaparam; + u16 rfparam; + u8 csthreshold; +}; + +void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); +void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam); + +static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr) +{ + return ioread8(addr); +} + +static inline u16 rtl818x_ioread16(struct rtl8180_priv *priv, __le16 __iomem *addr) +{ + return ioread16(addr); +} + +static inline u32 rtl818x_ioread32(struct rtl8180_priv *priv, __le32 __iomem *addr) +{ + return ioread32(addr); +} + +static inline void rtl818x_iowrite8(struct rtl8180_priv *priv, + u8 __iomem *addr, u8 val) +{ + iowrite8(val, addr); +} + +static inline void rtl818x_iowrite16(struct rtl8180_priv *priv, + __le16 __iomem *addr, u16 val) +{ + iowrite16(val, addr); +} + +static inline void rtl818x_iowrite32(struct rtl8180_priv *priv, + __le32 __iomem *addr, u32 val) +{ + iowrite32(val, addr); +} + +#endif /* RTL8180_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c new file mode 100644 index 0000000..6c226c0 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -0,0 +1,1081 @@ + +/* + * Linux device driver for RTL8180 / RTL8185 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_rtl8225.h" +#include "rtl8180_sa2400.h" +#include "rtl8180_max2820.h" +#include "rtl8180_grf5101.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_AUTHOR("Andrea Merello "); +MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); +MODULE_LICENSE("GPL"); + +static struct pci_device_id rtl8180_table[] __devinitdata = { + /* rtl8185 */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, + { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) }, + { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) }, + + /* rtl8180 */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) }, + { PCI_DEVICE(0x1799, 0x6001) }, + { PCI_DEVICE(0x1799, 0x6020) }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, rtl8180_table); + +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + + + + +void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + int i = 10; + u32 buf; + + buf = (data << 8) | addr; + + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80); + while (i--) { + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf); + if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF)) + return; + } +} + +static void rtl8180_handle_rx(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + unsigned int count = 32; + + while (count--) { + struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; + struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; + u32 flags = le32_to_cpu(entry->flags); + + if (flags & RTL818X_RX_DESC_FLAG_OWN) + return; + + if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | + RTL818X_RX_DESC_FLAG_FOF | + RTL818X_RX_DESC_FLAG_RX_ERR))) + goto done; + else { + u32 flags2 = le32_to_cpu(entry->flags2); + struct ieee80211_rx_status rx_status = {0}; + struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); + + if (unlikely(!new_skb)) + goto done; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + skb_put(skb, flags & 0xFFF); + + rx_status.antenna = (flags2 >> 15) & 1; + /* TODO: improve signal/rssi reporting */ + rx_status.qual = flags2 & 0xFF; + rx_status.signal = (flags2 >> 8) & 0x7F; + /* XXX: is this correct? */ + rx_status.rate_idx = (flags >> 20) & 0xF; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; + rx_status.mactime = le64_to_cpu(entry->tsft); + rx_status.flag |= RX_FLAG_TSFT; + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + + ieee80211_rx_irqsafe(dev, skb, &rx_status); + + skb = new_skb; + priv->rx_buf[priv->rx_idx] = skb; + *((dma_addr_t *) skb->cb) = + pci_map_single(priv->pdev, skb_tail_pointer(skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + } + + done: + entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | + MAX_RX_SIZE); + if (priv->rx_idx == 31) + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); + priv->rx_idx = (priv->rx_idx + 1) % 32; + } +} + +static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + u32 flags = le32_to_cpu(entry->flags); + + if (flags & RTL818X_TX_DESC_FLAG_OWN) + return; + + ring->idx = (ring->idx + 1) % ring->entries; + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; + + ieee80211_tx_status_irqsafe(dev, skb); + if (ring->entries - skb_queue_len(&ring->queue) == 2) + ieee80211_wake_queue(dev, prio); + } +} + +static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *dev = dev_id; + struct rtl8180_priv *priv = dev->priv; + u16 reg; + + spin_lock(&priv->lock); + reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); + if (unlikely(reg == 0xFFFF)) { + spin_unlock(&priv->lock); + return IRQ_HANDLED; + } + + rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); + + if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) + rtl8180_handle_tx(dev, 3); + + if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) + rtl8180_handle_tx(dev, 2); + + if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) + rtl8180_handle_tx(dev, 1); + + if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) + rtl8180_handle_tx(dev, 0); + + if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) + rtl8180_handle_rx(dev); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; +} + +static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring; + struct rtl8180_tx_desc *entry; + unsigned long flags; + unsigned int idx, prio; + dma_addr_t mapping; + u32 tx_flags; + u8 rc_flags; + u16 plcp_len = 0; + __le16 rts_duration = 0; + + prio = skb_get_queue_mapping(skb); + ring = &priv->tx_ring[prio]; + + mapping = pci_map_single(priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + + tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | + RTL818X_TX_DESC_FLAG_LS | + (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | + skb->len; + + if (priv->r8185) + tx_flags |= RTL818X_TX_DESC_FLAG_DMA | + RTL818X_TX_DESC_FLAG_NO_ENC; + + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + tx_flags |= RTL818X_TX_DESC_FLAG_RTS; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + tx_flags |= RTL818X_TX_DESC_FLAG_CTS; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } + + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) + rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, + info); + + if (!priv->r8185) { + unsigned int remainder; + + plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), + (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); + remainder = (16 * (skb->len + 4)) % + ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); + if (remainder > 0 && remainder <= 6) + plcp_len |= 1 << 15; + } + + spin_lock_irqsave(&priv->lock, flags); + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + entry = &ring->desc[idx]; + + entry->rts_duration = rts_duration; + entry->plcp_len = cpu_to_le16(plcp_len); + entry->tx_buf = cpu_to_le32(mapping); + entry->frame_len = cpu_to_le32(skb->len); + entry->flags2 = info->control.rates[1].idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; + entry->retry_limit = info->control.rates[0].count; + entry->flags = cpu_to_le32(tx_flags); + __skb_queue_tail(&ring->queue, skb); + if (ring->entries - skb_queue_len(&ring->queue) < 2) + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); + spin_unlock_irqrestore(&priv->lock, flags); + + rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); + + return 0; +} + +void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) +{ + u8 reg; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static int rtl8180_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg; + + rtl818x_iowrite8(priv, &priv->map->CMD, 0); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(10); + + /* reset */ + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + rtl818x_ioread8(priv, &priv->map->CMD); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= (1 << 1); + reg |= RTL818X_CMD_RESET; + rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(200); + + /* check success of reset */ + if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { + printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(200); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { + /* For cardbus */ + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= 1 << 1; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + reg = rtl818x_ioread16(priv, &priv->map->FEMR); + reg |= (1 << 15) | (1 << 14) | (1 << 4); + rtl818x_iowrite16(priv, &priv->map->FEMR, reg); + } + + rtl818x_iowrite8(priv, &priv->map->MSR, 0); + + if (!priv->r8185) + rtl8180_set_anaparam(priv, priv->anaparam); + + rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); + rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); + rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); + rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); + rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); + + /* TODO: necessary? specs indicate not */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); + rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); + if (priv->r8185) { + reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); + rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); + } + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ + + /* TODO: turn off hw wep on rtl8180 */ + + rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); + + if (priv->r8185) { + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); + + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* TODO: set ClkRun enable? necessary? */ + reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + } else { + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); + rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); + + rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); + } + + priv->rf->init(dev); + if (priv->r8185) + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + return 0; +} + +static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_rx_desc *entry; + int i; + + priv->rx_ring = pci_alloc_consistent(priv->pdev, + sizeof(*priv->rx_ring) * 32, + &priv->rx_ring_dma); + + if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { + printk(KERN_ERR "%s: Cannot allocate RX ring\n", + wiphy_name(dev->wiphy)); + return -ENOMEM; + } + + memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32); + priv->rx_idx = 0; + + for (i = 0; i < 32; i++) { + struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); + dma_addr_t *mapping; + entry = &priv->rx_ring[i]; + if (!skb) + return 0; + + priv->rx_buf[i] = skb; + mapping = (dma_addr_t *)skb->cb; + *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + entry->rx_buf = cpu_to_le32(*mapping); + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | + MAX_RX_SIZE); + } + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); + return 0; +} + +static void rtl8180_free_rx_ring(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + for (i = 0; i < 32; i++) { + struct sk_buff *skb = priv->rx_buf[i]; + if (!skb) + continue; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(skb); + } + + pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32, + priv->rx_ring, priv->rx_ring_dma); + priv->rx_ring = NULL; +} + +static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, + unsigned int prio, unsigned int entries) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_desc *ring; + dma_addr_t dma; + int i; + + ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); + if (!ring || (unsigned long)ring & 0xFF) { + printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n", + wiphy_name(dev->wiphy), prio); + return -ENOMEM; + } + + memset(ring, 0, sizeof(*ring)*entries); + priv->tx_ring[prio].desc = ring; + priv->tx_ring[prio].dma = dma; + priv->tx_ring[prio].idx = 0; + priv->tx_ring[prio].entries = entries; + skb_queue_head_init(&priv->tx_ring[prio].queue); + + for (i = 0; i < entries; i++) + ring[i].next_tx_desc = + cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); + + return 0; +} + +static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; +} + +static int rtl8180_start(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int ret, i; + u32 reg; + + ret = rtl8180_init_rx_ring(dev); + if (ret) + return ret; + + for (i = 0; i < 4; i++) + if ((ret = rtl8180_init_tx_ring(dev, i, 16))) + goto err_free_rings; + + ret = rtl8180_init_hw(dev); + if (ret) + goto err_free_rings; + + rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); + rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); + rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); + rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); + rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); + + ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + goto err_free_rings; + } + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); + rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); + + reg = RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + (7 << 8 /* MAX RX DMA */) | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC; + + if (priv->r8185) + reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; + else { + reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) + ? RTL818X_RX_CONF_CSDM1 : 0; + reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) + ? RTL818X_RX_CONF_CSDM2 : 0; + } + + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + if (priv->r8185) { + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + /* disable early TX */ + rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); + } + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg |= (6 << 21 /* MAX TX DMA */) | + RTL818X_TX_CONF_NO_ICV; + + if (priv->r8185) + reg &= ~RTL818X_TX_CONF_PROBE_DTS; + else + reg &= ~RTL818X_TX_CONF_HW_SEQNUM; + + /* different meaning, same value on both rtl8185 and rtl8180 */ + reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg |= RTL818X_CMD_RX_ENABLE; + reg |= RTL818X_CMD_TX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->mode = NL80211_IFTYPE_MONITOR; + return 0; + + err_free_rings: + rtl8180_free_rx_ring(dev); + for (i = 0; i < 4; i++) + if (priv->tx_ring[i].desc) + rtl8180_free_tx_ring(dev, i); + + return ret; +} + +static void rtl8180_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u8 reg; + int i; + + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= ~RTL818X_CMD_TX_ENABLE; + reg &= ~RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->rf->stop(dev); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); + rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + free_irq(priv->pdev->irq, dev); + + rtl8180_free_rx_ring(dev); + for (i = 0; i < 4; i++) + rtl8180_free_tx_ring(dev, i); +} + +static int rtl8180_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + + if (priv->mode != NL80211_IFTYPE_MONITOR) + return -EOPNOTSUPP; + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->vif = conf->vif; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], + le32_to_cpu(*(__le32 *)conf->mac_addr)); + rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], + le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + return 0; +} + +static void rtl8180_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + priv->mode = NL80211_IFTYPE_MONITOR; + priv->vif = NULL; +} + +static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) +{ + struct rtl8180_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; + + priv->rf->set_chan(dev, conf); + + return 0; +} + +static int rtl8180_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); + + if (is_valid_ether_addr(conf->bssid)) + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); + else + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); + + return 0; +} + +static void rtl8180_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mclist) +{ + struct rtl8180_priv *priv = dev->priv; + + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + if (*total_flags & FIF_ALLMULTI || mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + else + priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; + + *total_flags = 0; + + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + + rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); +} + +static const struct ieee80211_ops rtl8180_ops = { + .tx = rtl8180_tx, + .start = rtl8180_start, + .stop = rtl8180_stop, + .add_interface = rtl8180_add_interface, + .remove_interface = rtl8180_remove_interface, + .config = rtl8180_config, + .config_interface = rtl8180_config_interface, + .configure_filter = rtl8180_configure_filter, +}; + +static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8180_priv *priv = dev->priv; + u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + + eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; + eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; + eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; + eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; +} + +static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8180_priv *priv = dev->priv; + u8 reg = 2 << 6; + + if (eeprom->reg_data_in) + reg |= RTL818X_EEPROM_CMD_WRITE; + if (eeprom->reg_data_out) + reg |= RTL818X_EEPROM_CMD_READ; + if (eeprom->reg_data_clock) + reg |= RTL818X_EEPROM_CMD_CK; + if (eeprom->reg_chip_select) + reg |= RTL818X_EEPROM_CMD_CS; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); +} + +static int __devinit rtl8180_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ieee80211_hw *dev; + struct rtl8180_priv *priv; + unsigned long mem_addr, mem_len; + unsigned int io_addr, io_len; + int err, i; + struct eeprom_93cx6 eeprom; + const char *chip_name, *rf_name = NULL; + u32 reg; + u16 eeprom_val; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\n", + pci_name(pdev)); + return err; + } + + io_addr = pci_resource_start(pdev, 0); + io_len = pci_resource_len(pdev, 0); + mem_addr = pci_resource_start(pdev, 1); + mem_len = pci_resource_len(pdev, 1); + + if (mem_len < sizeof(struct rtl818x_csr) || + io_len < sizeof(struct rtl818x_csr)) { + printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) || + (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) { + printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + + dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops); + if (!dev) { + printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + priv = dev->priv; + priv->pdev = pdev; + + dev->max_rates = 2; + SET_IEEE80211_DEV(dev, &pdev->dev); + pci_set_drvdata(pdev, dev); + + priv->map = pci_iomap(pdev, 1, mem_len); + if (!priv->map) + priv->map = pci_iomap(pdev, 0, io_len); + + if (!priv->map) { + printk(KERN_ERR "%s (rtl8180): Cannot map device memory\n", + pci_name(pdev)); + goto err_free_dev; + } + + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); + memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = 4; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; + dev->queues = 1; + dev->max_signal = 65; + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg &= RTL818X_TX_CONF_HWVER_MASK; + switch (reg) { + case RTL818X_TX_CONF_R8180_ABCD: + chip_name = "RTL8180"; + break; + case RTL818X_TX_CONF_R8180_F: + chip_name = "RTL8180vF"; + break; + case RTL818X_TX_CONF_R8185_ABC: + chip_name = "RTL8185"; + break; + case RTL818X_TX_CONF_R8185_D: + chip_name = "RTL8185vD"; + break; + default: + printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", + pci_name(pdev), reg >> 25); + goto err_iounmap; + } + + priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; + if (priv->r8185) { + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); + pci_try_set_mwi(pdev); + } + + eeprom.data = dev; + eeprom.register_read = rtl8180_eeprom_register_read; + eeprom.register_write = rtl8180_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); + eeprom_val &= 0xFF; + switch (eeprom_val) { + case 1: rf_name = "Intersil"; + break; + case 2: rf_name = "RFMD"; + break; + case 3: priv->rf = &sa2400_rf_ops; + break; + case 4: priv->rf = &max2820_rf_ops; + break; + case 5: priv->rf = &grf5101_rf_ops; + break; + case 9: priv->rf = rtl8180_detect_rf(dev); + break; + case 10: + rf_name = "RTL8255"; + break; + default: + printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", + pci_name(pdev), eeprom_val); + goto err_iounmap; + } + + if (!priv->rf) { + printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", + pci_name(pdev), rf_name); + goto err_iounmap; + } + + eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); + priv->csthreshold = eeprom_val >> 8; + if (!priv->r8185) { + __le32 anaparam; + eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); + priv->anaparam = le32_to_cpu(anaparam); + eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); + } + + eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3); + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" + " randomly generated MAC addr\n", pci_name(pdev)); + random_ether_addr(dev->wiphy->perm_addr); + } + + /* CCK TX power */ + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); + priv->channels[i].hw_value = txpwr & 0xFF; + priv->channels[i + 1].hw_value = txpwr >> 8; + } + + /* OFDM TX power */ + if (priv->r8185) { + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); + priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; + priv->channels[i + 1].hw_value |= txpwr & 0xFF00; + } + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + spin_lock_init(&priv->lock); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot register device\n", + pci_name(pdev)); + goto err_iounmap; + } + + printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, + chip_name, priv->rf->name); + + return 0; + + err_iounmap: + iounmap(priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + pci_disable_device(pdev); + return err; +} + +static void __devexit rtl8180_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct rtl8180_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + + pci_iounmap(pdev, priv->map); + pci_release_regions(pdev); + pci_disable_device(pdev); + ieee80211_free_hw(dev); +} + +#ifdef CONFIG_PM +static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int rtl8180_resume(struct pci_dev *pdev) +{ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + return 0; +} + +#endif /* CONFIG_PM */ + +static struct pci_driver rtl8180_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8180_table, + .probe = rtl8180_probe, + .remove = __devexit_p(rtl8180_remove), +#ifdef CONFIG_PM + .suspend = rtl8180_suspend, + .resume = rtl8180_resume, +#endif /* CONFIG_PM */ +}; + +static int __init rtl8180_init(void) +{ + return pci_register_driver(&rtl8180_driver); +} + +static void __exit rtl8180_exit(void) +{ + pci_unregister_driver(&rtl8180_driver); +} + +module_init(rtl8180_init); +module_exit(rtl8180_exit); diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c new file mode 100644 index 0000000..947ee55 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c @@ -0,0 +1,180 @@ + +/* + * Radio tuning for GCT GRF5101 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_grf5101.h" + +static const int grf5101_encode[] = { + 0x0, 0x8, 0x4, 0xC, + 0x2, 0xA, 0x6, 0xE, + 0x1, 0x9, 0x5, 0xD, + 0x3, 0xB, 0x7, 0xF +}; + +static void write_grf5101(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + phy_config = grf5101_encode[(data >> 8) & 0xF]; + phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4; + phy_config |= grf5101_encode[data & 0xF] << 8; + phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12; + phy_config |= (addr & 1) << 16; + phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24; + + /* MAC will bang bits to the chip */ + phy_config |= 0x90000000; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(3); +} + +static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant = GRF5101_ANTENNA; + + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); +} + +static void grf5101_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = channel - 1; + + /* set TX power */ + write_grf5101(dev, 0x15, 0x0); + write_grf5101(dev, 0x06, txpw); + write_grf5101(dev, 0x15, 0x10); + write_grf5101(dev, 0x15, 0x0); + + /* set frequency */ + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x0B, chan); + write_grf5101(dev, 0x07, 0x1000); + + grf5101_write_phy_antenna(dev, channel); +} + +static void grf5101_rf_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u32 anaparam; + + anaparam = priv->anaparam; + anaparam &= 0x000fffff; + anaparam |= 0x3f900000; + rtl8180_set_anaparam(priv, anaparam); + + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x1f, 0x45); + write_grf5101(dev, 0x1f, 0x5); + write_grf5101(dev, 0x00, 0x8e4); +} + +static void grf5101_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + rtl8180_set_anaparam(priv, priv->anaparam); + + write_grf5101(dev, 0x1f, 0x0); + write_grf5101(dev, 0x1f, 0x0); + write_grf5101(dev, 0x1f, 0x40); + write_grf5101(dev, 0x1f, 0x60); + write_grf5101(dev, 0x1f, 0x61); + write_grf5101(dev, 0x1f, 0x61); + write_grf5101(dev, 0x00, 0xae4); + write_grf5101(dev, 0x1f, 0x1); + write_grf5101(dev, 0x1f, 0x41); + write_grf5101(dev, 0x1f, 0x61); + + write_grf5101(dev, 0x01, 0x1a23); + write_grf5101(dev, 0x02, 0x4971); + write_grf5101(dev, 0x03, 0x41de); + write_grf5101(dev, 0x04, 0x2d80); + write_grf5101(dev, 0x05, 0x68ff); /* 0x61ff original value */ + write_grf5101(dev, 0x06, 0x0); + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x08, 0x7533); + write_grf5101(dev, 0x09, 0xc401); + write_grf5101(dev, 0x0a, 0x0); + write_grf5101(dev, 0x0c, 0x1c7); + write_grf5101(dev, 0x0d, 0x29d3); + write_grf5101(dev, 0x0e, 0x2e8); + write_grf5101(dev, 0x10, 0x192); + write_grf5101(dev, 0x11, 0x248); + write_grf5101(dev, 0x12, 0x0); + write_grf5101(dev, 0x13, 0x20c4); + write_grf5101(dev, 0x14, 0xf4fc); + write_grf5101(dev, 0x15, 0x0); + write_grf5101(dev, 0x16, 0x1500); + + write_grf5101(dev, 0x07, 0x1000); + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0xa8); + rtl8180_write_phy(dev, 3, 0x0); + rtl8180_write_phy(dev, 4, 0xc0); + rtl8180_write_phy(dev, 5, 0x90); + rtl8180_write_phy(dev, 6, 0x1e); + rtl8180_write_phy(dev, 7, 0x64); + + grf5101_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x88); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */ + else + rtl8180_write_phy(dev, 0x12, 0x40); /* disable ant diversity */ + + rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); + + rtl8180_write_phy(dev, 0x19, 0x0); + rtl8180_write_phy(dev, 0x1a, 0xa0); + rtl8180_write_phy(dev, 0x1b, 0x44); +} + +const struct rtl818x_rf_ops grf5101_rf_ops = { + .name = "GCT", + .init = grf5101_rf_init, + .stop = grf5101_rf_stop, + .set_chan = grf5101_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h new file mode 100644 index 0000000..7664711 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h @@ -0,0 +1,28 @@ +#ifndef RTL8180_GRF5101_H +#define RTL8180_GRF5101_H + +/* + * Radio tuning for GCT GRF5101 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define GRF5101_ANTENNA 0xA3 + +extern const struct rtl818x_rf_ops grf5101_rf_ops; + +#endif /* RTL8180_GRF5101_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c new file mode 100644 index 0000000..6c825fd --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c @@ -0,0 +1,152 @@ +/* + * Radio tuning for Maxim max2820 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_max2820.h" + +static const u32 max2820_chan[] = { + 12, /* CH 1 */ + 17, + 22, + 27, + 32, + 37, + 42, + 47, + 52, + 57, + 62, + 67, + 72, + 84, /* CH 14 */ +}; + +static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + phy_config = 0x90 + (data & 0xf); + phy_config <<= 16; + phy_config += addr; + phy_config <<= 8; + phy_config += (data >> 4) & 0xff; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(1); +} + +static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant; + + ant = MAXIM_ANTENNA; + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); +} + +static void max2820_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int channel = conf ? + ieee80211_frequency_to_channel(conf->channel->center_freq) : 1; + unsigned int chan_idx = channel - 1; + u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; + u32 chan = max2820_chan[chan_idx]; + + /* While philips SA2400 drive the PA bias from + * sa2400, for MAXIM we do this directly from BB */ + rtl8180_write_phy(dev, 3, txpw); + + max2820_write_phy_antenna(dev, channel); + write_max2820(dev, 3, chan); +} + +static void max2820_rf_stop(struct ieee80211_hw *dev) +{ + rtl8180_write_phy(dev, 3, 0x8); + write_max2820(dev, 1, 0); +} + + +static void max2820_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + /* MAXIM from netbsd driver */ + write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ + write_max2820(dev, 1, 0x01e); /* enable register */ + write_max2820(dev, 2, 0x001); /* synt register */ + + max2820_rf_set_channel(dev, NULL); + + write_max2820(dev, 4, 0x313); /* rx register */ + + /* PA is driven directly by the BB, we keep the MAXIM bias + * at the highest value in case that setting it to lower + * values may introduce some further attenuation somewhere.. + */ + write_max2820(dev, 5, 0x00f); + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ + rtl8180_write_phy(dev, 3, 0x08); /* txagc */ + rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ + rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ + rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ + rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ + + max2820_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc7); + else + rtl8180_write_phy(dev, 0x12, 0x47); + + rtl8180_write_phy(dev, 0x13, 0x9b); + + rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ + rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ + + max2820_rf_set_channel(dev, NULL); +} + +const struct rtl818x_rf_ops max2820_rf_ops = { + .name = "Maxim", + .init = max2820_rf_init, + .stop = max2820_rf_stop, + .set_chan = max2820_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h new file mode 100644 index 0000000..61cf6d1 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.h @@ -0,0 +1,28 @@ +#ifndef RTL8180_MAX2820_H +#define RTL8180_MAX2820_H + +/* + * Radio tuning for Maxim max2820 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define MAXIM_ANTENNA 0xb3 + +extern const struct rtl818x_rf_ops max2820_rf_ops; + +#endif /* RTL8180_MAX2820_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c new file mode 100644 index 0000000..cd22781 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c @@ -0,0 +1,780 @@ + +/* + * Radio tuning for RTL8225 on RTL8180 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8180 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_rtl8225.h" + +static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg80, reg84, reg82; + u32 bangdata; + int i; + + bangdata = (data << 4) | (addr & 0xf); + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); + + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + for (i = 15; i >= 0; i--) { + u16 reg = reg80 | !!(bangdata & (1 << i)); + + if (i & 1) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + + if (!(i & 1)) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); +} + +static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg80, reg82, reg84, out; + int i; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400; + + reg80 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(4); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(5); + + for (i = 4; i >= 0; i--) { + u16 reg = reg80 | ((addr >> i) & 1); + + if (!(i & 1)) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + if (i & 1) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + } + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + out = 0; + for (i = 11; i >= 0; i--) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) + out |= 1 << i; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); + + return out; +} + +static const u16 rtl8225bcd_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb +}; + +static const u8 rtl8225_agc[] = { + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, + 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +static const u8 rtl8225_gain[] = { + 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ + 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ + 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ + 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ + 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ + 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ + 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ +}; + +static const u8 rtl8225_threshold[] = { + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd +}; + +static const u8 rtl8225_tx_gain_cck_ofdm[] = { + 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e +}; + +static const u8 rtl8225_tx_power_cck[] = { + 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, + 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, + 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, + 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 +}; + +static const u8 rtl8225_tx_power_cck_ch14[] = { + 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225_tx_power_ofdm[] = { + 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 +}; + +static const u32 rtl8225_chan[] = { + 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, + 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 +}; + +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; + + cck_power = min(cck_power, (u8)35); + ofdm_power = min(ofdm_power, (u8)35); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); + + if (channel == 14) + tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; + else + tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + msleep(1); /* FIXME: optional? */ + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1); + + tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; + + rtl8225_write_phy_ofdm(dev, 5, *tmp); + rtl8225_write_phy_ofdm(dev, 7, *tmp); + + msleep(1); +} + +static void rtl8225_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); + + /* host_pci_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(200); /* FIXME: ehh?? */ + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); + + /* TODO: check if we need really to change BRSR to do RF config */ + rtl818x_ioread16(priv, &priv->map->BRSR); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8BE); + rtl8225_write(dev, 0x5, 0xBF0); /* TODO: minipci */ + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, rtl8225_chan[0]); + rtl8225_write(dev, 0x8, 0x01F); + rtl8225_write(dev, 0x9, 0x334); + rtl8225_write(dev, 0xA, 0xFD4); + rtl8225_write(dev, 0xB, 0x391); + rtl8225_write(dev, 0xC, 0x050); + rtl8225_write(dev, 0xD, 0x6DB); + rtl8225_write(dev, 0xE, 0x029); + rtl8225_write(dev, 0xF, 0x914); msleep(1); + + rtl8225_write(dev, 0x2, 0xC4D); msleep(100); + + rtl8225_write(dev, 0x0, 0x127); + + for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x027); + rtl8225_write(dev, 0x0, 0x22F); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + msleep(1); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + msleep(1); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x06, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x11, 0x03); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); + rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); + rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1); + rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); + rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); + rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); + rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1); + + rtl8225_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + rtl8225_write(dev, 0x0c, 0x50); + /* set OFDM initial gain */ + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]); + /* set CCK threshold */ + rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]); +} + +static const u8 rtl8225z2_tx_power_cck_ch14[] = { + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225z2_tx_power_cck_B[] = { + 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04 +}; + +static const u8 rtl8225z2_tx_power_cck_A[] = { + 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 +}; + +static const u8 rtl8225z2_tx_power_cck[] = { + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 +}; + +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else if (cck_power == 12) + tmp = rtl8225z2_tx_power_cck_B; + else if (cck_power == 13) + tmp = rtl8225z2_tx_power_cck_A; + else + tmp = rtl8225z2_tx_power_cck; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + cck_power = min(cck_power, (u8)35); + if (cck_power == 13 || cck_power == 14) + cck_power = 12; + if (cck_power >= 15) + cck_power -= 2; + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power); + rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK); + msleep(1); + + ofdm_power = min(ofdm_power, (u8)35); + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power); + + rtl8225_write_phy_ofdm(dev, 2, 0x62); + rtl8225_write_phy_ofdm(dev, 5, 0x00); + rtl8225_write_phy_ofdm(dev, 6, 0x40); + rtl8225_write_phy_ofdm(dev, 7, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x40); + + msleep(1); +} + +static const u16 rtl8225z2_rxgain[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009, + 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141, + 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183, + 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244, + 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288, + 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389, + 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393, + 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb +}; + +static void rtl8225z2_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); + + /* host_pci_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(200); /* FIXME: ehh?? */ + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008); + + /* TODO: check if we need really to change BRSR to do RF config */ + rtl818x_ioread16(priv, &priv->map->BRSR); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + rtl8225_write(dev, 0x0, 0x0B7); msleep(1); + rtl8225_write(dev, 0x1, 0xEE0); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); msleep(1); + rtl8225_write(dev, 0x3, 0x441); msleep(1); + rtl8225_write(dev, 0x4, 0x8C3); msleep(1); + rtl8225_write(dev, 0x5, 0xC72); msleep(1); + rtl8225_write(dev, 0x6, 0x0E6); msleep(1); + rtl8225_write(dev, 0x7, 0x82A); msleep(1); + rtl8225_write(dev, 0x8, 0x03F); msleep(1); + rtl8225_write(dev, 0x9, 0x335); msleep(1); + rtl8225_write(dev, 0xa, 0x9D4); msleep(1); + rtl8225_write(dev, 0xb, 0x7BB); msleep(1); + rtl8225_write(dev, 0xc, 0x850); msleep(1); + rtl8225_write(dev, 0xd, 0xCDF); msleep(1); + rtl8225_write(dev, 0xe, 0x02B); msleep(1); + rtl8225_write(dev, 0xf, 0x114); msleep(100); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0C4D); + msleep(200); + rtl8225_write(dev, 0x02, 0x044D); + msleep(100); + /* TODO: readd calibration failure message when the calibration + check works */ + } + + rtl8225_write(dev, 0x0, 0x1B7); + rtl8225_write(dev, 0x3, 0x002); + rtl8225_write(dev, 0x5, 0x004); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x0B7); msleep(100); + rtl8225_write(dev, 0x2, 0xC4D); + + msleep(200); + rtl8225_write(dev, 0x2, 0x44D); + msleep(100); + + rtl8225_write(dev, 0x00, 0x2BF); + rtl8225_write(dev, 0xFF, 0xFFFF); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + msleep(1); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + msleep(1); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); /* FIXME: not needed? */ + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); + rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); + rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1); + rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); + rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8a); msleep(1); + rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); + rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); + rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); + rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + + rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 0x0D); msleep(1); + + rtl8225z2_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); +} + +static void rtl8225_rf_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u8 reg; + + rtl8225_write(dev, 0x4, 0x1f); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); + + if (priv->rf->init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, chan); + else + rtl8225z2_rf_set_tx_power(dev, chan); + + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); + msleep(10); + + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 81); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 81); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } +} + +static const struct rtl818x_rf_ops rtl8225_ops = { + .name = "rtl8225", + .init = rtl8225_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg8, reg9; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(100); + + rtl8225_write(dev, 0, 0x1B7); + + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); + + rtl8225_write(dev, 0, 0x0B7); + + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; + + return &rtl8225z2_ops; +} diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h new file mode 100644 index 0000000..310013a --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h @@ -0,0 +1,23 @@ +#ifndef RTL8180_RTL8225_H +#define RTL8180_RTL8225_H + +#define RTL8225_ANAPARAM_ON 0xa0000b59 +#define RTL8225_ANAPARAM2_ON 0x860dec11 +#define RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8225_ANAPARAM2_OFF 0x840dec11 + +const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *); + +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, + u8 addr, u8 data) +{ + rtl8180_write_phy(dev, addr, data); +} + +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, + u8 addr, u8 data) +{ + rtl8180_write_phy(dev, addr, data | 0x10000); +} + +#endif /* RTL8180_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c new file mode 100644 index 0000000..cea4e0c --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c @@ -0,0 +1,202 @@ + +/* + * Radio tuning for Philips SA2400 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_sa2400.h" + +static const u32 sa2400_chan[] = { + 0x00096c, /* ch1 */ + 0x080970, + 0x100974, + 0x180978, + 0x000980, + 0x080984, + 0x100988, + 0x18098c, + 0x000994, + 0x080998, + 0x10099c, + 0x1809a0, + 0x0009a8, + 0x0009b4, /* ch 14 */ +}; + +static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ + phy_config = 0xb0000000; + + phy_config |= ((u32)(addr & 0xf)) << 24; + phy_config |= data & 0xffffff; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(3); +} + +static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant = SA2400_ANTENNA; + + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); + +} + +static void sa2400_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = sa2400_chan[channel - 1]; + + write_sa2400(dev, 7, txpw); + + sa2400_write_phy_antenna(dev, channel); + + write_sa2400(dev, 0, chan); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); +} + +static void sa2400_rf_stop(struct ieee80211_hw *dev) +{ + write_sa2400(dev, 4, 0); +} + +static void sa2400_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u32 anaparam, txconf; + u8 firdac; + int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; + + anaparam = priv->anaparam; + anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); + anaparam &= ~ANAPARAM_PWR1_MASK; + anaparam &= ~ANAPARAM_PWR0_MASK; + + if (analogphy) { + anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; + firdac = 0; + } else { + anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); + anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); + firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; + } + + rtl8180_set_anaparam(priv, anaparam); + + write_sa2400(dev, 0, sa2400_chan[0]); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); + write_sa2400(dev, 4, 0x19340 | firdac); + write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); + write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ + + if (!analogphy) + write_sa2400(dev, 4, 0x1938c); /*???*/ + + write_sa2400(dev, 4, 0x19340 | firdac); + + write_sa2400(dev, 0, sa2400_chan[0]); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); + write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ + + /* new from rtl8180 embedded driver (rtl8181 project) */ + write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ + write_sa2400(dev, 8, 0); /* VCO */ + + if (analogphy) { + rtl8180_set_anaparam(priv, anaparam | + (1 << ANAPARAM_TXDACOFF_SHIFT)); + + txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + txconf | RTL818X_TX_CONF_LOOPBACK_CONT); + + write_sa2400(dev, 4, 0x19341); /* calibrates DC */ + + /* a 5us sleep is required here, + * we rely on the 3ms delay introduced in write_sa2400 */ + write_sa2400(dev, 4, 0x19345); + + /* a 20us sleep is required here, + * we rely on the 3ms delay introduced in write_sa2400 */ + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); + + rtl8180_set_anaparam(priv, anaparam); + } + /* end new code */ + + write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0x98); + rtl8180_write_phy(dev, 3, 0x38); + rtl8180_write_phy(dev, 4, 0xe0); + rtl8180_write_phy(dev, 5, 0x90); + rtl8180_write_phy(dev, 6, 0x1a); + rtl8180_write_phy(dev, 7, 0x64); + + sa2400_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x80); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ + else + rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ + + rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); + + rtl8180_write_phy(dev, 0x19, 0x0); + rtl8180_write_phy(dev, 0x1a, 0xa0); +} + +const struct rtl818x_rf_ops sa2400_rf_ops = { + .name = "Philips", + .init = sa2400_rf_init, + .stop = sa2400_rf_stop, + .set_chan = sa2400_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h new file mode 100644 index 0000000..a4aaa0d --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h @@ -0,0 +1,36 @@ +#ifndef RTL8180_SA2400_H +#define RTL8180_SA2400_H + +/* + * Radio tuning for Philips SA2400 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define SA2400_ANTENNA 0x91 +#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 +#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 +#define SA2400_ANAPARAM_PWR0_ON 0x3 + +/* RX sensitivity in dbm */ +#define SA2400_MAX_SENS 85 + +#define SA2400_REG4_FIRDAC_SHIFT 7 + +extern const struct rtl818x_rf_ops sa2400_rf_ops; + +#endif /* RTL8180_SA2400_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h new file mode 100644 index 0000000..33725d0 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -0,0 +1,220 @@ +/* + * Definitions for RTL8187 hardware + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL8187_H +#define RTL8187_H + +#include "rtl818x.h" + +#define RTL8187_EEPROM_TXPWR_BASE 0x05 +#define RTL8187_EEPROM_MAC_ADDR 0x07 +#define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */ +#define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */ +#define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */ + +#define RTL8187_REQT_READ 0xC0 +#define RTL8187_REQT_WRITE 0x40 +#define RTL8187_REQ_GET_REG 0x05 +#define RTL8187_REQ_SET_REG 0x05 + +#define RTL8187_MAX_RX 0x9C4 + +struct rtl8187_rx_info { + struct urb *urb; + struct ieee80211_hw *dev; +}; + +struct rtl8187_rx_hdr { + __le32 flags; + u8 noise; + u8 signal; + u8 agc; + u8 reserved; + __le64 mac_time; +} __attribute__((packed)); + +struct rtl8187b_rx_hdr { + __le32 flags; + __le64 mac_time; + u8 sq; + u8 rssi; + u8 agc; + u8 flags2; + __le16 snr_long2end; + s8 pwdb_g12; + u8 fot; +} __attribute__((packed)); + +/* {rtl8187,rtl8187b}_tx_info is in skb */ + +struct rtl8187_tx_hdr { + __le32 flags; + __le16 rts_duration; + __le16 len; + __le32 retry; +} __attribute__((packed)); + +struct rtl8187b_tx_hdr { + __le32 flags; + __le16 rts_duration; + __le16 len; + __le32 unused_1; + __le16 unused_2; + __le16 tx_duration; + __le32 unused_3; + __le32 retry; + __le32 unused_4[2]; +} __attribute__((packed)); + +enum { + DEVICE_RTL8187, + DEVICE_RTL8187B +}; + +struct rtl8187_priv { + /* common between rtl818x drivers */ + struct rtl818x_csr *map; + const struct rtl818x_rf_ops *rf; + struct ieee80211_vif *vif; + int mode; + /* The mutex protects the TX loopback state. + * Any attempt to set channels concurrently locks the device. + */ + struct mutex conf_mutex; + + /* rtl8187 specific */ + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct usb_device *udev; + u32 rx_conf; + u16 txpwr_base; + u8 asic_rev; + u8 is_rtl8187b; + enum { + RTL8187BvB, + RTL8187BvD, + RTL8187BvE + } hw_rev; + struct sk_buff_head rx_queue; + u8 signal; + u8 quality; + u8 noise; +}; + +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); + +static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv, + u8 *addr, u8 idx) +{ + u8 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); + + return val; +} + +static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) +{ + return rtl818x_ioread8_idx(priv, addr, 0); +} + +static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv, + __le16 *addr, u8 idx) +{ + __le16 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); + + return le16_to_cpu(val); +} + +static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) +{ + return rtl818x_ioread16_idx(priv, addr, 0); +} + +static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv, + __le32 *addr, u8 idx) +{ + __le32 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); + + return le32_to_cpu(val); +} + +static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) +{ + return rtl818x_ioread32_idx(priv, addr, 0); +} + +static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv, + u8 *addr, u8 val, u8 idx) +{ + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); +} + +static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val) +{ + rtl818x_iowrite8_idx(priv, addr, val, 0); +} + +static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv, + __le16 *addr, u16 val, u8 idx) +{ + __le16 buf = cpu_to_le16(val); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), + HZ / 2); +} + +static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr, + u16 val) +{ + rtl818x_iowrite16_idx(priv, addr, val, 0); +} + +static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv, + __le32 *addr, u32 val, u8 idx) +{ + __le32 buf = cpu_to_le32(val); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), + HZ / 2); +} + +static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr, + u32 val) +{ + rtl818x_iowrite32_idx(priv, addr, val, 0); +} + +#endif /* RTL8187_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c new file mode 100644 index 0000000..e1399d0 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -0,0 +1,1298 @@ +/* + * Linux device driver for RTL8187 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * Magic delays and register offsets below are taken from the original + * r8187 driver sources. Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "rtl8187.h" +#include "rtl8187_rtl8225.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_AUTHOR("Andrea Merello "); +MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); +MODULE_LICENSE("GPL"); + +static struct usb_device_id rtl8187_table[] __devinitdata = { + /* Asus */ + {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, + /* Belkin */ + {USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B}, + /* Realtek */ + {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B}, + /* Netgear */ + {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0846, 0x4260), .driver_info = DEVICE_RTL8187B}, + /* HP */ + {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187}, + /* Sitecom */ + {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B}, + /* Abocom */ + {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187}, + {} +}; + +MODULE_DEVICE_TABLE(usb, rtl8187_table); + +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + +static void rtl8187_iowrite_async_cb(struct urb *urb) +{ + kfree(urb->context); + usb_free_urb(urb); +} + +static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, + void *data, u16 len) +{ + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl8187_async_write_data { + u8 data[4]; + struct usb_ctrlrequest dr; + } *buf; + int rc; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(buf); + return; + } + + dr = &buf->dr; + + dr->bRequestType = RTL8187_REQT_WRITE; + dr->bRequest = RTL8187_REQ_SET_REG; + dr->wValue = addr; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(len); + + memcpy(buf, data, len); + + usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), + (unsigned char *)dr, buf, len, + rtl8187_iowrite_async_cb, buf); + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc < 0) { + kfree(buf); + usb_free_urb(urb); + } +} + +static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, + __le32 *addr, u32 val) +{ + __le32 buf = cpu_to_le32(val); + + rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), + &buf, sizeof(buf)); +} + +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8187_priv *priv = dev->priv; + + data <<= 8; + data |= addr | 0x80; + + rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); +} + +static void rtl8187_tx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->rate_driver_data[0]; + struct rtl8187_priv *priv = hw->priv; + + usb_free_urb(info->rate_driver_data[1]); + skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : + sizeof(struct rtl8187_tx_hdr)); + ieee80211_tx_info_clear_status(info); + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); +} + +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct rtl8187_priv *priv = dev->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned int ep; + void *buf; + struct urb *urb; + __le16 rts_dur = 0; + u32 flags; + int rc; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree_skb(skb); + return 0; + } + + flags = skb->len; + flags |= RTL818X_TX_DESC_FLAG_NO_ENC; + + flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; + if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) + flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + flags |= RTL818X_TX_DESC_FLAG_RTS; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + rts_dur = ieee80211_rts_duration(dev, priv->vif, + skb->len, info); + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + flags |= RTL818X_TX_DESC_FLAG_CTS; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } + + if (!priv->is_rtl8187b) { + struct rtl8187_tx_hdr *hdr = + (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le32(flags); + hdr->len = 0; + hdr->rts_duration = rts_dur; + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); + buf = hdr; + + ep = 2; + } else { + /* fc needs to be calculated before skb_push() */ + unsigned int epmap[4] = { 6, 7, 5, 4 }; + struct ieee80211_hdr *tx_hdr = + (struct ieee80211_hdr *)(skb->data); + u16 fc = le16_to_cpu(tx_hdr->frame_control); + + struct rtl8187b_tx_hdr *hdr = + (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct ieee80211_rate *txrate = + ieee80211_get_tx_rate(dev, info); + memset(hdr, 0, sizeof(*hdr)); + hdr->flags = cpu_to_le32(flags); + hdr->rts_duration = rts_dur; + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); + hdr->tx_duration = + ieee80211_generic_frame_duration(dev, priv->vif, + skb->len, txrate); + buf = hdr; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + ep = 12; + else + ep = epmap[skb_get_queue_mapping(skb)]; + } + + info->rate_driver_data[0] = dev; + info->rate_driver_data[1] = urb; + + usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), + buf, skb->len, rtl8187_tx_cb, skb); + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc < 0) { + usb_free_urb(urb); + kfree_skb(skb); + } + + return 0; +} + +static void rtl8187_rx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; + struct ieee80211_hw *dev = info->dev; + struct rtl8187_priv *priv = dev->priv; + struct ieee80211_rx_status rx_status = { 0 }; + int rate, signal; + u32 flags; + u32 quality; + + spin_lock(&priv->rx_queue.lock); + if (skb->next) + __skb_unlink(skb, &priv->rx_queue); + else { + spin_unlock(&priv->rx_queue.lock); + return; + } + spin_unlock(&priv->rx_queue.lock); + + if (unlikely(urb->status)) { + usb_free_urb(urb); + dev_kfree_skb_irq(skb); + return; + } + + skb_put(skb, urb->actual_length); + if (!priv->is_rtl8187b) { + struct rtl8187_rx_hdr *hdr = + (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + flags = le32_to_cpu(hdr->flags); + signal = hdr->signal & 0x7f; + rx_status.antenna = (hdr->signal >> 7) & 1; + rx_status.noise = hdr->noise; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + priv->quality = signal; + rx_status.qual = priv->quality; + priv->noise = hdr->noise; + rate = (flags >> 20) & 0xF; + if (rate > 3) { /* OFDM rate */ + if (signal > 90) + signal = 90; + else if (signal < 25) + signal = 25; + signal = 90 - signal; + } else { /* CCK rate */ + if (signal > 95) + signal = 95; + else if (signal < 30) + signal = 30; + signal = 95 - signal; + } + rx_status.signal = signal; + priv->signal = signal; + } else { + struct rtl8187b_rx_hdr *hdr = + (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + /* The Realtek datasheet for the RTL8187B shows that the RX + * header contains the following quantities: signal quality, + * RSSI, AGC, the received power in dB, and the measured SNR. + * In testing, none of these quantities show qualitative + * agreement with AP signal strength, except for the AGC, + * which is inversely proportional to the strength of the + * signal. In the following, the quality and signal strength + * are derived from the AGC. The arbitrary scaling constants + * are chosen to make the results close to the values obtained + * for a BCM4312 using b43 as the driver. The noise is ignored + * for now. + */ + flags = le32_to_cpu(hdr->flags); + quality = 170 - hdr->agc; + if (quality > 100) + quality = 100; + signal = 14 - hdr->agc / 2; + rx_status.qual = quality; + priv->quality = quality; + rx_status.signal = signal; + priv->signal = signal; + rx_status.antenna = (hdr->rssi >> 7) & 1; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + rate = (flags >> 20) & 0xF; + } + + skb_trim(skb, flags & 0x0FFF); + rx_status.rate_idx = rate; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; + rx_status.flag |= RX_FLAG_TSFT; + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + ieee80211_rx_irqsafe(dev, skb, &rx_status); + + skb = dev_alloc_skb(RTL8187_MAX_RX); + if (unlikely(!skb)) { + usb_free_urb(urb); + /* TODO check rx queue length and refill *somewhere* */ + return; + } + + info = (struct rtl8187_rx_info *)skb->cb; + info->urb = urb; + info->dev = dev; + urb->transfer_buffer = skb_tail_pointer(skb); + urb->context = skb; + skb_queue_tail(&priv->rx_queue, skb); + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int rtl8187_init_urbs(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct urb *entry; + struct sk_buff *skb; + struct rtl8187_rx_info *info; + + while (skb_queue_len(&priv->rx_queue) < 8) { + skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); + if (!skb) + break; + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) { + kfree_skb(skb); + break; + } + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, + priv->is_rtl8187b ? 3 : 1), + skb_tail_pointer(skb), + RTL8187_MAX_RX, rtl8187_rx_cb, skb); + info = (struct rtl8187_rx_info *)skb->cb; + info->urb = entry; + info->dev = dev; + skb_queue_tail(&priv->rx_queue, skb); + usb_submit_urb(entry, GFP_KERNEL); + } + + return 0; +} + +static int rtl8187_cmd_reset(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u8 reg; + int i; + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= (1 << 1); + reg |= RTL818X_CMD_RESET; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + i = 10; + do { + msleep(2); + if (!(rtl818x_ioread8(priv, &priv->map->CMD) & + RTL818X_CMD_RESET)) + break; + } while (--i); + + if (!i) { + printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + /* reload registers from eeprom */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); + + i = 10; + do { + msleep(4); + if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) & + RTL818X_EEPROM_CMD_CONFIG)) + break; + } while (--i); + + if (!i) { + printk(KERN_ERR "%s: eeprom reset timeout!\n", + wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8187_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u8 reg; + int res; + + /* reset */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | + RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & + ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + msleep(200); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); + msleep(200); + + res = rtl8187_cmd_reset(dev); + if (res) + return res; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + /* setup card */ + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); + rtl818x_iowrite8(priv, &priv->map->GPIO, 1); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + + rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); + reg &= 0x3F; + reg |= 0x80; + rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + + // TODO: set RESP_RATE and BRSR properly + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* host_usb_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + reg = rtl818x_ioread8(priv, (u8 *)0xFE53); + rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80); + msleep(100); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); + msleep(100); + + priv->rf->init(dev); + + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); + rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); + rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); + rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + + return 0; +} + +static const u8 rtl8187b_reg_table[][3] = { + {0xF0, 0x32, 0}, {0xF1, 0x32, 0}, {0xF2, 0x00, 0}, {0xF3, 0x00, 0}, + {0xF4, 0x32, 0}, {0xF5, 0x43, 0}, {0xF6, 0x00, 0}, {0xF7, 0x00, 0}, + {0xF8, 0x46, 0}, {0xF9, 0xA4, 0}, {0xFA, 0x00, 0}, {0xFB, 0x00, 0}, + {0xFC, 0x96, 0}, {0xFD, 0xA4, 0}, {0xFE, 0x00, 0}, {0xFF, 0x00, 0}, + + {0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1}, + {0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1}, + {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1}, + {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1}, + {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1}, + {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, + + {0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2}, + {0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2}, + {0x27, 0x8D, 2}, {0x4D, 0x08, 2}, {0x50, 0x05, 2}, {0x51, 0xF5, 2}, + {0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2}, + {0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2}, + {0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2}, + {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, + {0x73, 0x9A, 2}, + + {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, + {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, + {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, + {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, + {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, + + {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, + {0x8E, 0x08, 0}, {0x8F, 0x00, 0} +}; + +static int rtl8187b_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int res, i; + u8 reg; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187B_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187B_RTL8225_ANAPARAM_ON); + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, + RTL8187B_RTL8225_ANAPARAM3_ON); + + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); + reg = rtl818x_ioread8(priv, (u8 *)0xFF62); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); + + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + res = rtl8187_cmd_reset(dev); + if (res) + return res; + + rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF); + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT | + RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); + reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK); + reg |= RTL818X_RATE_FALLBACK_ENABLE; + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg); + + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); + rtl818x_iowrite8(priv, &priv->map->CONFIG1, (reg & 0x3F) | 0x80); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + for (i = 0; i < ARRAY_SIZE(rtl8187b_reg_table); i++) { + rtl818x_iowrite8_idx(priv, + (u8 *)(uintptr_t) + (rtl8187b_reg_table[i][0] | 0xFF00), + rtl8187b_reg_table[i][1], + rtl8187b_reg_table[i][2]); + } + + rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50); + rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0); + + rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF0, 0, 1); + rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF4, 0, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFFF8, 0, 1); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + msleep(100); + + priv->rf->init(dev); + + reg = RTL818X_CMD_TX_ENABLE | RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite8(priv, (u8 *)0xFE41, 0xF4); + rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); + rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x0F); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); + + reg = rtl818x_ioread8(priv, (u8 *)0xFFDB); + rtl818x_iowrite8(priv, (u8 *)0xFFDB, reg | (1 << 2)); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x59FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF74, 0x59D2, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF76, 0x59D2, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF78, 0x19FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7A, 0x19FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7C, 0x00D0, 3); + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF80, 0x0F, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF83, 0x03, 1); + rtl818x_iowrite8(priv, (u8 *)0xFFDA, 0x10); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF4D, 0x08, 2); + + rtl818x_iowrite32(priv, &priv->map->HSSI_PARA, 0x0600321B); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); + + return 0; +} + +static int rtl8187_start(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u32 reg; + int ret; + + ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : + rtl8187b_init_hw(dev); + if (ret) + return ret; + + mutex_lock(&priv->conf_mutex); + if (priv->is_rtl8187b) { + reg = RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC | + RTL818X_RX_CONF_BSSID | + (7 << 13 /* RX FIFO threshold NONE */) | + (7 << 10 /* MAX RX DMA */) | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_MULTICAST; + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + RTL818X_TX_CONF_HW_SEQNUM | + RTL818X_TX_CONF_DISREQQSIZE | + (7 << 8 /* short retry limit */) | + (7 << 0 /* long retry limit */) | + (7 << 21 /* MAX TX DMA */)); + rtl8187_init_urbs(dev); + mutex_unlock(&priv->conf_mutex); + return 0; + } + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); + rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); + + rtl8187_init_urbs(dev); + + reg = RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_BSSID | + RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + (7 << 13 /* RX FIFO threshold NONE */) | + (7 << 10 /* MAX RX DMA */) | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC; + + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + reg = RTL818X_TX_CONF_CW_MIN | + (7 << 21 /* MAX TX DMA */) | + RTL818X_TX_CONF_NO_ICV; + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg |= RTL818X_CMD_TX_ENABLE; + reg |= RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + mutex_unlock(&priv->conf_mutex); + + return 0; +} + +static void rtl8187_stop(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct rtl8187_rx_info *info; + struct sk_buff *skb; + u32 reg; + + mutex_lock(&priv->conf_mutex); + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= ~RTL818X_CMD_TX_ENABLE; + reg &= ~RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->rf->stop(dev); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); + rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + while ((skb = skb_dequeue(&priv->rx_queue))) { + info = (struct rtl8187_rx_info *)skb->cb; + usb_kill_urb(info->urb); + kfree_skb(skb); + } + mutex_unlock(&priv->conf_mutex); +} + +static int rtl8187_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + if (priv->mode != NL80211_IFTYPE_MONITOR) + return -EOPNOTSUPP; + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + mutex_lock(&priv->conf_mutex); + priv->vif = conf->vif; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->MAC[i], + ((u8 *)conf->mac_addr)[i]); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static void rtl8187_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_MONITOR; + priv->vif = NULL; + mutex_unlock(&priv->conf_mutex); +} + +static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; + u32 reg; + + mutex_lock(&priv->conf_mutex); + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + /* Enable TX loopback on MAC level to avoid TX during channel + * changes, as this has be seen to causes problems and the + * card will stop work until next reset + */ + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + reg | RTL818X_TX_CONF_LOOPBACK_MAC); + priv->rf->set_chan(dev, conf); + msleep(10); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); + rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static int rtl8187_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + u8 reg; + + mutex_lock(&priv->conf_mutex); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); + + if (is_valid_ether_addr(conf->bssid)) { + reg = RTL818X_MSR_INFRA; + if (priv->is_rtl8187b) + reg |= RTL818X_MSR_ENEDCA; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } else { + reg = RTL818X_MSR_NO_LINK; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } + + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, + bool use_short_preamble) +{ + if (priv->is_rtl8187b) { + u8 difs, eifs, slot_time; + u16 ack_timeout; + + if (use_short_slot) { + slot_time = 0x9; + difs = 0x1c; + eifs = 0x53; + } else { + slot_time = 0x14; + difs = 0x32; + eifs = 0x5b; + } + rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); + rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); + rtl818x_iowrite8(priv, &priv->map->DIFS, difs); + + /* + * BRSR+1 on 8187B is in fact EIFS register + * Value in units of 4 us + */ + rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); + + /* + * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout + * register. In units of 4 us like eifs register + * ack_timeout = ack duration + plcp + difs + preamble + */ + ack_timeout = 112 + 48 + difs; + if (use_short_preamble) + ack_timeout += 72; + else + ack_timeout += 144; + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, + DIV_ROUND_UP(ack_timeout, 4)); + } else { + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + if (use_short_slot) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } + } +} + +static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) + rtl8187_conf_erp(priv, info->use_short_slot, + info->use_short_preamble); +} + +static void rtl8187_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mclist) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + if (*total_flags & FIF_ALLMULTI || mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + else + priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; + + *total_flags = 0; + + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + + rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); +} + +static const struct ieee80211_ops rtl8187_ops = { + .tx = rtl8187_tx, + .start = rtl8187_start, + .stop = rtl8187_stop, + .add_interface = rtl8187_add_interface, + .remove_interface = rtl8187_remove_interface, + .config = rtl8187_config, + .config_interface = rtl8187_config_interface, + .bss_info_changed = rtl8187_bss_info_changed, + .configure_filter = rtl8187_configure_filter, +}; + +static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8187_priv *priv = dev->priv; + u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + + eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; + eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; + eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; + eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; +} + +static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8187_priv *priv = dev->priv; + u8 reg = RTL818X_EEPROM_CMD_PROGRAM; + + if (eeprom->reg_data_in) + reg |= RTL818X_EEPROM_CMD_WRITE; + if (eeprom->reg_data_out) + reg |= RTL818X_EEPROM_CMD_READ; + if (eeprom->reg_data_clock) + reg |= RTL818X_EEPROM_CMD_CK; + if (eeprom->reg_chip_select) + reg |= RTL818X_EEPROM_CMD_CS; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); + udelay(10); +} + +static int __devinit rtl8187_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ieee80211_hw *dev; + struct rtl8187_priv *priv; + struct eeprom_93cx6 eeprom; + struct ieee80211_channel *channel; + const char *chip_name; + u16 txpwr, reg; + int err, i; + + dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); + if (!dev) { + printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n"); + return -ENOMEM; + } + + priv = dev->priv; + priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B); + + SET_IEEE80211_DEV(dev, &intf->dev); + usb_set_intfdata(intf, dev); + priv->udev = udev; + + usb_get_dev(udev); + + skb_queue_head_init(&priv->rx_queue); + + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); + memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); + priv->map = (struct rtl818x_csr *)0xFF00; + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + + priv->mode = NL80211_IFTYPE_MONITOR; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_RX_INCLUDES_FCS; + + eeprom.data = dev; + eeprom.register_read = rtl8187_eeprom_register_read; + eeprom.register_write = rtl8187_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + udelay(10); + + eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR, + (__le16 __force *)dev->wiphy->perm_addr, 3); + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly " + "generated MAC address\n"); + random_ether_addr(dev->wiphy->perm_addr); + } + + channel = priv->channels; + for (i = 0; i < 3; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, + &priv->txpwr_base); + + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); + /* 0 means asic B-cut, we should use SW 3 wire + * bit-by-bit banging for radio. 1 means we can use + * USB specific request to write radio registers */ + priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + if (!priv->is_rtl8187b) { + u32 reg32; + reg32 = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg32 &= RTL818X_TX_CONF_HWVER_MASK; + switch (reg32) { + case RTL818X_TX_CONF_R8187vD_B: + /* Some RTL8187B devices have a USB ID of 0x8187 + * detect them here */ + chip_name = "RTL8187BvB(early)"; + priv->is_rtl8187b = 1; + priv->hw_rev = RTL8187BvB; + break; + case RTL818X_TX_CONF_R8187vD: + chip_name = "RTL8187vD"; + break; + default: + chip_name = "RTL8187vB (default)"; + } + } else { + /* + * Force USB request to write radio registers for 8187B, Realtek + * only uses it in their sources + */ + /*if (priv->asic_rev == 0) { + printk(KERN_WARNING "rtl8187: Forcing use of USB " + "requests to write to radio registers\n"); + priv->asic_rev = 1; + }*/ + switch (rtl818x_ioread8(priv, (u8 *)0xFFE1)) { + case RTL818X_R8187B_B: + chip_name = "RTL8187BvB"; + priv->hw_rev = RTL8187BvB; + break; + case RTL818X_R8187B_D: + chip_name = "RTL8187BvD"; + priv->hw_rev = RTL8187BvD; + break; + case RTL818X_R8187B_E: + chip_name = "RTL8187BvE"; + priv->hw_rev = RTL8187BvE; + break; + default: + chip_name = "RTL8187BvB (default)"; + priv->hw_rev = RTL8187BvB; + } + } + + if (!priv->is_rtl8187b) { + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, + RTL8187_EEPROM_TXPWR_CHAN_6 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + } else { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + + eeprom_93cx6_read(&eeprom, 0x0A, &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + + eeprom_93cx6_read(&eeprom, 0x1C, &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + + if (priv->is_rtl8187b) { + printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " + "is EXPERIMENTAL, and could damage your\n" + " hardware, use at your own risk\n"); + dev->flags |= IEEE80211_HW_SIGNAL_DBM; + } else { + dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; + dev->max_signal = 65; + } + + /* + * XXX: Once this driver supports anything that requires + * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) + printk(KERN_INFO "rtl8187: inconsistency between id with OEM" + " info!\n"); + + priv->rf = rtl8187_detect_rf(dev); + dev->extra_tx_headroom = (!priv->is_rtl8187b) ? + sizeof(struct rtl8187_tx_hdr) : + sizeof(struct rtl8187b_tx_hdr); + if (!priv->is_rtl8187b) + dev->queues = 1; + else + dev->queues = 4; + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "rtl8187: Cannot register device\n"); + goto err_free_dev; + } + mutex_init(&priv->conf_mutex); + + printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, + chip_name, priv->asic_rev, priv->rf->name); + + return 0; + + err_free_dev: + ieee80211_free_hw(dev); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + return err; +} + +static void __devexit rtl8187_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct rtl8187_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + usb_put_dev(interface_to_usbdev(intf)); + ieee80211_free_hw(dev); +} + +static struct usb_driver rtl8187_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8187_table, + .probe = rtl8187_probe, + .disconnect = __devexit_p(rtl8187_disconnect), +}; + +static int __init rtl8187_init(void) +{ + return usb_register(&rtl8187_driver); +} + +static void __exit rtl8187_exit(void) +{ + usb_deregister(&rtl8187_driver); +} + +module_init(rtl8187_init); +module_exit(rtl8187_exit); diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c new file mode 100644 index 0000000..69030be --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -0,0 +1,977 @@ +/* + * Radio tuning for RTL8225 on RTL8187 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * Magic delays, register offsets, and phy value tables below are + * taken from the original r8187 driver sources. Thanks to Realtek + * for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "rtl8187.h" +#include "rtl8187_rtl8225.h" + +static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg84, reg82; + u32 bangdata; + int i; + + bangdata = (data << 4) | (addr & 0xf); + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); + + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(10); + + for (i = 15; i >= 0; i--) { + u16 reg = reg80 | (bangdata & (1 << i)) >> i; + + if (i & 1) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + + if (!(i & 1)) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); +} + +static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg82, reg84; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + + reg80 &= ~(0x3 << 2); + reg84 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(10); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + addr, 0x8225, &data, sizeof(data), HZ / 2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); +} + +static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8187_priv *priv = dev->priv; + + if (priv->asic_rev) + rtl8225_write_8051(dev, addr, cpu_to_le16(data)); + else + rtl8225_write_bitbang(dev, addr, data); +} + +static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg82, reg84, out; + int i; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + + reg80 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(4); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(5); + + for (i = 4; i >= 0; i--) { + u16 reg = reg80 | ((addr >> i) & 1); + + if (!(i & 1)) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + udelay(1); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + udelay(2); + + if (i & 1) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + udelay(1); + } + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + + out = 0; + for (i = 11; i >= 0; i--) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(1); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + + if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) + out |= 1 << i; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 2)); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); + + return out; +} + +static const u16 rtl8225bcd_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb +}; + +static const u8 rtl8225_agc[] = { + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, + 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +static const u8 rtl8225_gain[] = { + 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */ + 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */ + 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */ + 0x33, 0x80, 0x79, 0xc5, /* -78dBm */ + 0x43, 0x78, 0x76, 0xc5, /* -74dBm */ + 0x53, 0x60, 0x73, 0xc5, /* -70dBm */ + 0x63, 0x58, 0x70, 0xc5, /* -66dBm */ +}; + +static const u8 rtl8225_threshold[] = { + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd +}; + +static const u8 rtl8225_tx_gain_cck_ofdm[] = { + 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e +}; + +static const u8 rtl8225_tx_power_cck[] = { + 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, + 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, + 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, + 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 +}; + +static const u8 rtl8225_tx_power_cck_ch14[] = { + 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225_tx_power_ofdm[] = { + 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 +}; + +static const u32 rtl8225_chan[] = { + 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, + 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 +}; + +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + cck_power = min(cck_power, (u8)11); + ofdm_power = min(ofdm_power, (u8)35); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); + + if (channel == 14) + tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; + else + tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + msleep(1); // FIXME: optional? + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write_phy_ofdm(dev, 2, 0x42); + rtl8225_write_phy_ofdm(dev, 6, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x00); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1); + + tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; + + rtl8225_write_phy_ofdm(dev, 5, *tmp); + rtl8225_write_phy_ofdm(dev, 7, *tmp); + + msleep(1); +} + +static void rtl8225_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x486); + rtl8225_write(dev, 0x5, 0xBC0); + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x01F); + rtl8225_write(dev, 0x9, 0x334); + rtl8225_write(dev, 0xA, 0xFD4); + rtl8225_write(dev, 0xB, 0x391); + rtl8225_write(dev, 0xC, 0x050); + rtl8225_write(dev, 0xD, 0x6DB); + rtl8225_write(dev, 0xE, 0x029); + rtl8225_write(dev, 0xF, 0x914); msleep(100); + + rtl8225_write(dev, 0x2, 0xC4D); msleep(200); + rtl8225_write(dev, 0x2, 0x44D); msleep(200); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0c4d); + msleep(200); + rtl8225_write(dev, 0x02, 0x044d); + msleep(100); + if (!(rtl8225_read(dev, 6) & (1 << 7))) + printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", + wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); + } + + rtl8225_write(dev, 0x0, 0x127); + + for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x027); + rtl8225_write(dev, 0x0, 0x22F); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); + + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); + rtl8225_write_phy_cck(dev, 0x47, 0x15); + rtl8225_write_phy_cck(dev, 0x48, 0x10); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); + + rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); + + rtl8225_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); + + /* set sensitivity */ + rtl8225_write(dev, 0x0c, 0x50); + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); + rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]); +} + +static const u8 rtl8225z2_agc[] = { + 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f, + 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37, + 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f, + 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07, + 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, + 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 +}; +static const u8 rtl8225z2_ofdm[] = { + 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, + 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, + 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f, + 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, + 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, + 0x6d, 0x3c, 0xfb, 0x07 +}; + +static const u8 rtl8225z2_tx_power_cck_ch14[] = { + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225z2_tx_power_cck[] = { + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, + 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 +}; + +static const u8 rtl8225z2_tx_power_ofdm[] = { + 0x42, 0x00, 0x40, 0x00, 0x40 +}; + +static const u8 rtl8225z2_tx_gain_cck_ofdm[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23 +}; + +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + cck_power = min(cck_power, (u8)15); + cck_power += priv->txpwr_base & 0xF; + cck_power = min(cck_power, (u8)35); + + ofdm_power = min(ofdm_power, (u8)15); + ofdm_power += priv->txpwr_base >> 4; + ofdm_power = min(ofdm_power, (u8)35); + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else + tmp = rtl8225z2_tx_power_cck; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225z2_tx_gain_cck_ofdm[cck_power]); + msleep(1); + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write_phy_ofdm(dev, 2, 0x42); + rtl8225_write_phy_ofdm(dev, 5, 0x00); + rtl8225_write_phy_ofdm(dev, 6, 0x40); + rtl8225_write_phy_ofdm(dev, 7, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x40); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225z2_tx_gain_cck_ofdm[ofdm_power]); + msleep(1); +} + +static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + if (cck_power > 15) + cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22; + else + cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7; + cck_power += priv->txpwr_base & 0xF; + cck_power = min(cck_power, (u8)35); + + if (ofdm_power > 15) + ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25; + else + ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10; + ofdm_power += (priv->txpwr_base >> 4) & 0xF; + ofdm_power = min(ofdm_power, (u8)35); + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else + tmp = rtl8225z2_tx_power_cck; + + if (priv->hw_rev == RTL8187BvB) { + if (cck_power <= 6) + ; /* do nothing */ + else if (cck_power <= 11) + tmp += 8; + else + tmp += 16; + } else { + if (cck_power <= 5) + ; /* do nothing */ + else if (cck_power <= 11) + tmp += 8; + else if (cck_power <= 17) + tmp += 16; + else + tmp += 24; + } + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); + msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1); + if (priv->hw_rev == RTL8187BvB) { + if (ofdm_power <= 11) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x60); + rtl8225_write_phy_ofdm(dev, 0x89, 0x60); + } else { + rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); + rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); + } + } else { + if (ofdm_power <= 11) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); + rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); + } else if (ofdm_power <= 17) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x54); + rtl8225_write_phy_ofdm(dev, 0x89, 0x54); + } else { + rtl8225_write_phy_ofdm(dev, 0x87, 0x50); + rtl8225_write_phy_ofdm(dev, 0x89, 0x50); + } + } + msleep(1); +} + +static const u16 rtl8225z2_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb +}; + +static const u8 rtl8225z2_gain_bg[] = { + 0x23, 0x15, 0xa5, /* -82-1dBm */ + 0x23, 0x15, 0xb5, /* -82-2dBm */ + 0x23, 0x15, 0xc5, /* -82-3dBm */ + 0x33, 0x15, 0xc5, /* -78dBm */ + 0x43, 0x15, 0xc5, /* -74dBm */ + 0x53, 0x15, 0xc5, /* -70dBm */ + 0x63, 0x15, 0xc5 /* -66dBm */ +}; + +static void rtl8225z2_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + rtl8225_write(dev, 0x0, 0x2BF); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + msleep(100); + + rtl8225_write(dev, 0x0, 0x1B7); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x2, 0xc4D); + + msleep(200); + rtl8225_write(dev, 0x2, 0x44D); + msleep(100); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0C4D); + msleep(200); + rtl8225_write(dev, 0x02, 0x044D); + msleep(100); + if (!(rtl8225_read(dev, 6) & (1 << 7))) + printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", + wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); + } + + msleep(200); + + rtl8225_write(dev, 0x0, 0x2BF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); + rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x07); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x17); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x00); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); + + rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]); + rtl8225_write_phy_ofdm(dev, 0x21, 0x37); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x36); + rtl8225_write_phy_cck(dev, 0x45, 0x35); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); + rtl8225_write_phy_cck(dev, 0x47, 0x25); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); + rtl8225_write_phy_cck(dev, 0x49, 0x12); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); + + rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1); + + rtl8225z2_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); +} + +static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + + rtl8225_write(dev, 0x0, 0x1B7); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); + + rtl8225_write(dev, 0x2, 0xC4D); + + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x0, 0x2BF); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03); + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07); + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); + + rtl8225_write_phy_ofdm(dev, 0x80, 0x12); + for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i); + rtl8225_write_phy_ofdm(dev, 0xE, 0); + } + rtl8225_write_phy_ofdm(dev, 0x80, 0x10); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) + rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); + + rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); + + rtl8225_write_phy_ofdm(dev, 0x97, 0x46); + rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); + rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); + rtl8225_write_phy_cck(dev, 0xc1, 0x88); +} + +static void rtl8225_rf_stop(struct ieee80211_hw *dev) +{ + u8 reg; + struct rtl8187_priv *priv = dev->priv; + + rtl8225_write(dev, 0x4, 0x1f); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + if (!priv->is_rtl8187b) { + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_OFF); + } else { + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187B_RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187B_RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, + RTL8187B_RTL8225_ANAPARAM3_OFF); + } + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); + + if (priv->rf->init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, chan); + else if (priv->rf->init == rtl8225z2_rf_init) + rtl8225z2_rf_set_tx_power(dev, chan); + else + rtl8225z2_b_rf_set_tx_power(dev, chan); + + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); + msleep(10); +} + +static const struct rtl818x_rf_ops rtl8225_ops = { + .name = "rtl8225", + .init = rtl8225_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_b_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_b_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev) +{ + u16 reg8, reg9; + struct rtl8187_priv *priv = dev->priv; + + if (!priv->is_rtl8187b) { + rtl8225_write(dev, 0, 0x1B7); + + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); + + rtl8225_write(dev, 0, 0x0B7); + + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; + + return &rtl8225z2_ops; + } else + return &rtl8225z2_b_ops; +} diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h new file mode 100644 index 0000000..20c5b6e --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h @@ -0,0 +1,44 @@ +/* + * Radio tuning definitions for RTL8225 on RTL8187 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL8187_RTL8225_H +#define RTL8187_RTL8225_H + +#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59 +#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312 +#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11 + +#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658 +#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52 +#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00 +#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658 +#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50 +#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00 + +const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *); + +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, + u8 addr, u32 data) +{ + rtl8187_write_phy(dev, addr, data); +} + +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, + u8 addr, u32 data) +{ + rtl8187_write_phy(dev, addr, data | 0x10000); +} + +#endif /* RTL8187_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h new file mode 100644 index 0000000..3538b15 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -0,0 +1,231 @@ +/* + * Definitions for RTL818x hardware + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL818X_H +#define RTL818X_H + +struct rtl818x_csr { + u8 MAC[6]; + u8 reserved_0[2]; + __le32 MAR[2]; + u8 RX_FIFO_COUNT; + u8 reserved_1; + u8 TX_FIFO_COUNT; + u8 BQREQ; + u8 reserved_2[4]; + __le32 TSFT[2]; + __le32 TLPDA; + __le32 TNPDA; + __le32 THPDA; + __le16 BRSR; + u8 BSSID[6]; + u8 RESP_RATE; + u8 EIFS; + u8 reserved_3[1]; + u8 CMD; +#define RTL818X_CMD_TX_ENABLE (1 << 2) +#define RTL818X_CMD_RX_ENABLE (1 << 3) +#define RTL818X_CMD_RESET (1 << 4) + u8 reserved_4[4]; + __le16 INT_MASK; + __le16 INT_STATUS; +#define RTL818X_INT_RX_OK (1 << 0) +#define RTL818X_INT_RX_ERR (1 << 1) +#define RTL818X_INT_TXL_OK (1 << 2) +#define RTL818X_INT_TXL_ERR (1 << 3) +#define RTL818X_INT_RX_DU (1 << 4) +#define RTL818X_INT_RX_FO (1 << 5) +#define RTL818X_INT_TXN_OK (1 << 6) +#define RTL818X_INT_TXN_ERR (1 << 7) +#define RTL818X_INT_TXH_OK (1 << 8) +#define RTL818X_INT_TXH_ERR (1 << 9) +#define RTL818X_INT_TXB_OK (1 << 10) +#define RTL818X_INT_TXB_ERR (1 << 11) +#define RTL818X_INT_ATIM (1 << 12) +#define RTL818X_INT_BEACON (1 << 13) +#define RTL818X_INT_TIME_OUT (1 << 14) +#define RTL818X_INT_TX_FO (1 << 15) + __le32 TX_CONF; +#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17) +#define RTL818X_TX_CONF_LOOPBACK_CONT (3 << 17) +#define RTL818X_TX_CONF_NO_ICV (1 << 19) +#define RTL818X_TX_CONF_DISCW (1 << 20) +#define RTL818X_TX_CONF_SAT_HWPLCP (1 << 24) +#define RTL818X_TX_CONF_R8180_ABCD (2 << 25) +#define RTL818X_TX_CONF_R8180_F (3 << 25) +#define RTL818X_TX_CONF_R8185_ABC (4 << 25) +#define RTL818X_TX_CONF_R8185_D (5 << 25) +#define RTL818X_TX_CONF_R8187vD (5 << 25) +#define RTL818X_TX_CONF_R8187vD_B (6 << 25) +#define RTL818X_TX_CONF_HWVER_MASK (7 << 25) +#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28) +#define RTL818X_TX_CONF_PROBE_DTS (1 << 29) +#define RTL818X_TX_CONF_HW_SEQNUM (1 << 30) +#define RTL818X_TX_CONF_CW_MIN (1 << 31) + __le32 RX_CONF; +#define RTL818X_RX_CONF_MONITOR (1 << 0) +#define RTL818X_RX_CONF_NICMAC (1 << 1) +#define RTL818X_RX_CONF_MULTICAST (1 << 2) +#define RTL818X_RX_CONF_BROADCAST (1 << 3) +#define RTL818X_RX_CONF_FCS (1 << 5) +#define RTL818X_RX_CONF_DATA (1 << 18) +#define RTL818X_RX_CONF_CTRL (1 << 19) +#define RTL818X_RX_CONF_MGMT (1 << 20) +#define RTL818X_RX_CONF_ADDR3 (1 << 21) +#define RTL818X_RX_CONF_PM (1 << 22) +#define RTL818X_RX_CONF_BSSID (1 << 23) +#define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28) +#define RTL818X_RX_CONF_CSDM1 (1 << 29) +#define RTL818X_RX_CONF_CSDM2 (1 << 30) +#define RTL818X_RX_CONF_ONLYERLPKT (1 << 31) + __le32 INT_TIMEOUT; + __le32 TBDA; + u8 EEPROM_CMD; +#define RTL818X_EEPROM_CMD_READ (1 << 0) +#define RTL818X_EEPROM_CMD_WRITE (1 << 1) +#define RTL818X_EEPROM_CMD_CK (1 << 2) +#define RTL818X_EEPROM_CMD_CS (1 << 3) +#define RTL818X_EEPROM_CMD_NORMAL (0 << 6) +#define RTL818X_EEPROM_CMD_LOAD (1 << 6) +#define RTL818X_EEPROM_CMD_PROGRAM (2 << 6) +#define RTL818X_EEPROM_CMD_CONFIG (3 << 6) + u8 CONFIG0; + u8 CONFIG1; + u8 CONFIG2; +#define RTL818X_CONFIG2_ANTENNA_DIV (1 << 6) + __le32 ANAPARAM; + u8 MSR; +#define RTL818X_MSR_NO_LINK (0 << 2) +#define RTL818X_MSR_ADHOC (1 << 2) +#define RTL818X_MSR_INFRA (2 << 2) +#define RTL818X_MSR_MASTER (3 << 2) +#define RTL818X_MSR_ENEDCA (4 << 2) + u8 CONFIG3; +#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6) +#define RTL818X_CONFIG3_GNT_SELECT (1 << 7) + u8 CONFIG4; +#define RTL818X_CONFIG4_POWEROFF (1 << 6) +#define RTL818X_CONFIG4_VCOOFF (1 << 7) + u8 TESTR; + u8 reserved_9[2]; + u8 PGSELECT; + u8 SECURITY; + __le32 ANAPARAM2; + u8 reserved_10[12]; + __le16 BEACON_INTERVAL; + __le16 ATIM_WND; + __le16 BEACON_INTERVAL_TIME; + __le16 ATIMTR_INTERVAL; + u8 PHY_DELAY; + u8 CARRIER_SENSE_COUNTER; + u8 reserved_11[2]; + u8 PHY[4]; + __le16 RFPinsOutput; + __le16 RFPinsEnable; + __le16 RFPinsSelect; + __le16 RFPinsInput; + __le32 RF_PARA; + __le32 RF_TIMING; + u8 GP_ENABLE; + u8 GPIO; + u8 reserved_12[2]; + __le32 HSSI_PARA; + u8 reserved_13[4]; + u8 TX_AGC_CTL; +#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0) +#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1) +#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2) + u8 TX_GAIN_CCK; + u8 TX_GAIN_OFDM; + u8 TX_ANTENNA; + u8 reserved_14[16]; + u8 WPA_CONF; + u8 reserved_15[3]; + u8 SIFS; + u8 DIFS; + u8 SLOT; + u8 reserved_16[5]; + u8 CW_CONF; +#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0) +#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1) + u8 CW_VAL; + u8 RATE_FALLBACK; +#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7) + u8 ACM_CONTROL; + u8 reserved_17[24]; + u8 CONFIG5; + u8 TX_DMA_POLLING; + u8 reserved_18[2]; + __le16 CWR; + u8 RETRY_CTR; + u8 reserved_19[3]; + __le16 INT_MIG; +/* RTL818X_R8187B_*: magic numbers from ioregisters */ +#define RTL818X_R8187B_B 0 +#define RTL818X_R8187B_D 1 +#define RTL818X_R8187B_E 2 + __le32 RDSAR; + __le16 TID_AC_MAP; + u8 reserved_20[4]; + u8 ANAPARAM3; + u8 reserved_21[5]; + __le16 FEMR; + u8 reserved_22[4]; + __le16 TALLY_CNT; + u8 TALLY_SEL; +} __attribute__((packed)); + +struct rtl818x_rf_ops { + char *name; + void (*init)(struct ieee80211_hw *); + void (*stop)(struct ieee80211_hw *); + void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); +}; + +/* Tx/Rx flags are common between RTL818X chips */ + +enum rtl818x_tx_desc_flags { + RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), + RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), + RTL818X_TX_DESC_FLAG_SPLCP = (1 << 16), + RTL818X_TX_DESC_FLAG_RX_UNDER = (1 << 16), + RTL818X_TX_DESC_FLAG_MOREFRAG = (1 << 17), + RTL818X_TX_DESC_FLAG_CTS = (1 << 18), + RTL818X_TX_DESC_FLAG_RTS = (1 << 23), + RTL818X_TX_DESC_FLAG_LS = (1 << 28), + RTL818X_TX_DESC_FLAG_FS = (1 << 29), + RTL818X_TX_DESC_FLAG_DMA = (1 << 30), + RTL818X_TX_DESC_FLAG_OWN = (1 << 31) +}; + +enum rtl818x_rx_desc_flags { + RTL818X_RX_DESC_FLAG_ICV_ERR = (1 << 12), + RTL818X_RX_DESC_FLAG_CRC32_ERR = (1 << 13), + RTL818X_RX_DESC_FLAG_PM = (1 << 14), + RTL818X_RX_DESC_FLAG_RX_ERR = (1 << 15), + RTL818X_RX_DESC_FLAG_BCAST = (1 << 16), + RTL818X_RX_DESC_FLAG_PAM = (1 << 17), + RTL818X_RX_DESC_FLAG_MCAST = (1 << 18), + RTL818X_RX_DESC_FLAG_QOS = (1 << 19), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_TRSW = (1 << 24), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_SPLCP = (1 << 25), + RTL818X_RX_DESC_FLAG_FOF = (1 << 26), + RTL818X_RX_DESC_FLAG_DMA_FAIL = (1 << 27), + RTL818X_RX_DESC_FLAG_LS = (1 << 28), + RTL818X_RX_DESC_FLAG_FS = (1 << 29), + RTL818X_RX_DESC_FLAG_EOR = (1 << 30), + RTL818X_RX_DESC_FLAG_OWN = (1 << 31) +}; + +#endif /* RTL818X_H */ -- cgit v1.1 From 3d8606a680529d41ad8985f36ecf83a7b393ecaf Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 2 Nov 2008 00:36:40 +0100 Subject: rt2x00: Remove RATE_BASIC flag mac80211 is in charge of determining the basic rates, so we are not using the RATE_BASIC flag anymore. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 14 +++++++------- drivers/net/wireless/rt2x00/rt2x00lib.h | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 477a944..a8fee68 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -717,31 +717,31 @@ EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); */ const struct rt2x00_rate rt2x00_supported_rates[12] = { { - .flags = DEV_RATE_CCK | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK, .bitrate = 10, .ratemask = BIT(0), .plcp = 0x00, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 20, .ratemask = BIT(1), .plcp = 0x01, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 55, .ratemask = BIT(2), .plcp = 0x02, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 110, .ratemask = BIT(3), .plcp = 0x03, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 60, .ratemask = BIT(4), .plcp = 0x0b, @@ -753,7 +753,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .plcp = 0x0f, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 120, .ratemask = BIT(6), .plcp = 0x0a, @@ -765,7 +765,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .plcp = 0x0e, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 240, .ratemask = BIT(8), .plcp = 0x09, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 9f214f8..c52ee21 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -43,7 +43,6 @@ struct rt2x00_rate { #define DEV_RATE_CCK 0x0001 #define DEV_RATE_OFDM 0x0002 #define DEV_RATE_SHORT_PREAMBLE 0x0004 -#define DEV_RATE_BASIC 0x0008 unsigned short bitrate; /* In 100kbit/s */ unsigned short ratemask; -- cgit v1.1 From 9a95dba32735534bda59def40c747bf606fedf05 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 2 Nov 2008 00:37:09 +0100 Subject: rt2x00: Fix LED state handling For every global LED state change (register/unregister, suspend/resume) we should force the LEDS to turn off. This makes sure that the LEDS will always be in a sane state after the state switch. Note that when unregister is called but the LED class wasn't resumed yet, we shouldn't change the LED state since we might not have access to the device (device was unplugged while suspended). Also remove the checks in the activity, assoc and radio LEDS which blocked calls to brightness_set() when the state hasn't changed. Some of those LEDS could be enabled by themselves when something happens in the hardware (e.g. firmware is loaded). We already did called rt2x00leds to switch the LED off, but those calls were blocked. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00leds.c | 94 +++++++++++++++++++------------- 1 file changed, 56 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index b362a1c..66c61b1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -72,49 +72,33 @@ void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi) } } -void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) +static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_qual; - unsigned int brightness; + unsigned int brightness = enabled ? LED_FULL : LED_OFF; - if ((led->type != LED_TYPE_ACTIVITY) || !(led->flags & LED_REGISTERED)) + if (!(led->flags & LED_REGISTERED)) return; - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } + led->led_dev.brightness_set(&led->led_dev, brightness); + led->led_dev.brightness = brightness; } -void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_assoc; - unsigned int brightness; - - if ((led->type != LED_TYPE_ASSOC) || !(led->flags & LED_REGISTERED)) - return; + if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY) + rt2x00led_led_simple(&rt2x00dev->led_qual, enabled); +} - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } +void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +{ + if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC) + rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled); } void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_radio; - unsigned int brightness; - - if ((led->type != LED_TYPE_RADIO) || !(led->flags & LED_REGISTERED)) - return; - - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } + if (rt2x00dev->led_radio.type == LED_TYPE_ASSOC) + rt2x00led_led_simple(&rt2x00dev->led_radio, enabled); } static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, @@ -125,6 +109,13 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, int retval; led->led_dev.name = name; + led->led_dev.brightness = LED_OFF; + + /* + * Ensure the LED is off, it might have been enabled + * by the hardware when the device was powered on. + */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); retval = led_classdev_register(device, &led->led_dev); if (retval) { @@ -199,7 +190,16 @@ exit_fail: static void rt2x00leds_unregister_led(struct rt2x00_led *led) { led_classdev_unregister(&led->led_dev); - led->led_dev.brightness_set(&led->led_dev, LED_OFF); + + /* + * This might look weird, but when we are unregistering while + * suspended the led is already off, and since we haven't + * fully resumed yet, access to the device might not be + * possible yet. + */ + if (!(led->led_dev.flags & LED_SUSPENDED)) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->flags &= ~LED_REGISTERED; } @@ -213,22 +213,40 @@ void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) rt2x00leds_unregister_led(&rt2x00dev->led_radio); } +static inline void rt2x00leds_suspend_led(struct rt2x00_led *led) +{ + led_classdev_suspend(&led->led_dev); + + /* This shouldn't be needed, but just to be safe */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->led_dev.brightness = LED_OFF; +} + void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->led_qual.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_qual.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_qual); if (rt2x00dev->led_assoc.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_assoc.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_assoc); if (rt2x00dev->led_radio.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_radio.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_radio); +} + +static inline void rt2x00leds_resume_led(struct rt2x00_led *led) +{ + led_classdev_resume(&led->led_dev); + + /* Device might have enabled the LEDS during resume */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->led_dev.brightness = LED_OFF; } void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->led_radio.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_radio.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_radio); if (rt2x00dev->led_assoc.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_assoc.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_assoc); if (rt2x00dev->led_qual.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_qual.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_qual); } -- cgit v1.1 From 8058409c4fb8e38632207d572ed29943d2585520 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 2 Nov 2008 00:37:25 +0100 Subject: rt2x00: Block set_key() during suspend/shutdown mac80211 will call set_key() when the device is shutting down. When the device is unplugged the keys will be lost automatically due to the power loss. When the device is not plugged but the module is only unloaded the keys can remain in the device hardware, when the module is loaded the keys will be cleaned up during initialization. This should prevent the problem reported by Johannes Berg, where unplugging the device while suspended resulted in a NULL pointer error during set_key() which was caused because of the CSR base address being freed. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 8fc2315..188f891 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -486,7 +486,9 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key); struct rt2x00lib_crypto crypto; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) return -EOPNOTSUPP; else if (key->keylen > 32) return -ENOSPC; -- cgit v1.1 From 6d64360ac56cda95243f15738a06f2a123c663e5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 2 Nov 2008 00:38:10 +0100 Subject: rt2x00: Fix BUG_ON() with antenna handling With the new configuration handling, and more specifically splitting the configuration of the antenna from the normal configuration steps allowed a BUG_ON() to be triggered in the driver because the SW_DIVERSITY was send to the driver. This fixes that by catching the value early in rt2x00config.c and replacing it with a sensible value. This also fixes a problem where the antenna is not being initialized at all when the radio is enabled. Since it no longer is part of the mac80211 configuration the only place where rt2x00 configured it was the SW diversity handler. Obviously this is broken for all non-diversity hardware and breaks SW diversity due to a broken initialization. When the radio is enabled the antenna will be configured once as soon as the config() callback function is called. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 3 +-- drivers/net/wireless/rt2x00/rt2x00config.c | 35 ++++++++++++++++++++++-------- drivers/net/wireless/rt2x00/rt2x00dev.c | 22 ++++++++++--------- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 13 +++++++++-- 5 files changed, 51 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index f85eedb..8fa971c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -723,8 +723,7 @@ struct rt2x00_dev { /* * This is the default TX/RX antenna setup as indicated - * by the device's EEPROM. When mac80211 sets its - * antenna value to 0 we should be using these values. + * by the device's EEPROM. */ struct antenna_setup default_ant; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3e4eee3..1059b4d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -109,15 +109,32 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - enum antenna rx, enum antenna tx) + struct antenna_setup *ant) { - struct antenna_setup ant; - - ant.rx = rx; - ant.tx = tx; + /* + * Failsafe: Make sure we are not sending the + * ANTENNA_SW_DIVERSITY state to the driver. + * If that happes fallback to hardware default, + * or our own default. + */ + if (ant->rx == ANTENNA_SW_DIVERSITY) { + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + ant->rx = ANTENNA_B; + else + ant->rx = rt2x00dev->default_ant.rx; + } + if (ant->tx == ANTENNA_SW_DIVERSITY) { + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + ant->tx = ANTENNA_B; + else + ant->tx = rt2x00dev->default_ant.tx; + } - if (rx == rt2x00dev->link.ant.active.rx && - tx == rt2x00dev->link.ant.active.tx) + /* + * Only reconfigure when something has changed. + */ + if (ant->rx == rt2x00dev->link.ant.active.rx && + ant->tx == rt2x00dev->link.ant.active.tx) return; /* @@ -132,12 +149,12 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); + rt2x00dev->ops->lib->config_ant(rt2x00dev, ant); rt2x00lib_reset_link_tuner(rt2x00dev); rt2x00_reset_link_ant_rssi(&rt2x00dev->link); - memcpy(&rt2x00dev->link.ant.active, &ant, sizeof(ant)); + memcpy(&rt2x00dev->link.ant.active, ant, sizeof(*ant)); 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 a8fee68..e8ca1cb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -176,13 +176,14 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) { - enum antenna rx = rt2x00dev->link.ant.active.rx; - enum antenna tx = rt2x00dev->link.ant.active.tx; + struct antenna_setup ant; int sample_a = rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A); int sample_b = rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B); + memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant)); + /* * We are done sampling. Now we should evaluate the results. */ @@ -200,21 +201,22 @@ static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) return; if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) - rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) - tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; - rt2x00lib_config_antenna(rt2x00dev, rx, tx); + rt2x00lib_config_antenna(rt2x00dev, &ant); } static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) { - enum antenna rx = rt2x00dev->link.ant.active.rx; - enum antenna tx = rt2x00dev->link.ant.active.tx; + struct antenna_setup ant; int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link); int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr); + memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant)); + /* * Legacy driver indicates that we should swap antenna's * when the difference in RSSI is greater that 5. This @@ -230,12 +232,12 @@ static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE; if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) - rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) - tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; - rt2x00lib_config_antenna(rt2x00dev, rx, tx); + rt2x00lib_config_antenna(rt2x00dev, &ant); } static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index c52ee21..0c3a355 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -93,7 +93,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, struct ieee80211_bss_conf *conf); void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - enum antenna rx, enum antenna tx); + struct antenna_setup *ant); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const unsigned int changed_flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 188f891..48636b0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -339,7 +339,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_conf *conf = &hw->conf; - int radio_on; int status; /* @@ -356,7 +355,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) * some configuration parameters (e.g. channel and antenna values) can * only be set when the radio is enabled. */ - 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); @@ -372,6 +370,17 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) */ rt2x00lib_config(rt2x00dev, conf, changed); + /* + * The radio was enabled, configure the antenna to the + * default settings, the link tuner will later start + * continue configuring the antenna based on the software + * diversity. But for non-diversity configurations, we need + * to have configured the correct state now. + */ + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) + rt2x00lib_config_antenna(rt2x00dev, + &rt2x00dev->default_ant); + /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); } else { -- cgit v1.1 From 8b0162a3dc5c30e862b7a73da29e32de3170f5e4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2008 11:27:38 +0100 Subject: ath5k: ignore the return value of ath5k_hw_noise_floor_calibration Noise floor calibration occasionally fails on Atheros hardware. This is not fatal and can happen if there's simply too much noise on the air. Ignoring the calibration error is the right thing to do here, because when the error is ignored, the hardware will still work, whereas if the error causes the driver to bail out of a bigger configuration function and does not configure the tx queues or the IMR (as is the case in reset.c), the hw no longer works properly until the next reset. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/phy.c | 4 +--- drivers/net/wireless/ath5k/reset.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 69625bf..7ba18e0 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -2196,9 +2196,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return ret; } - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* * Re-enable RX/TX and beacons diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index b51bc03..5003263 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -842,9 +842,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * * XXX: Find an interval that's OK for all cards... */ - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* * Reset queues and start beacon timers at the end of the reset routine -- cgit v1.1 From 392dff836f40370033bbe3b39e3b9bf4148d1435 Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Thu, 6 Nov 2008 22:26:49 +0100 Subject: ath9k : Display MAC/BB and RF version at startup (v2) This patch decodes the MAC/BB version (for instance: AR5416) and the RF part version (for instance: AR5133). It has been tested on AR5416/AR5133 which is a 2.4/5GHz 11n device. It also makes the differences between AR5416 (PCI) and AR5418 (PCI Express). Both are named AR5416 in the register definitions. Signed-off-by: Benoit Papillault Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 3 +- drivers/net/wireless/ath9k/main.c | 74 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index e05c9ef..ff6457e 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -382,8 +382,9 @@ static const char *ath9k_hw_devname(u16 devid) { switch (devid) { case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: return "Atheros 5416"; + case AR5416_DEVID_PCIE: + return "Atheros 5418"; case AR9160_DEVID_PCI: return "Atheros 9160"; case AR9280_DEVID_PCI: diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f830fe1..fbb2dd2 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -18,6 +18,7 @@ #include #include "core.h" +#include "reg.h" #define ATH_PCI_VERSION "0.1" @@ -1519,15 +1520,74 @@ static struct ieee80211_ops ath9k_ops = { .set_frag_threshold = ath9k_no_fragmentation, }; +static struct { + u32 version; + const char * name; +} ath_mac_bb_names[] = { + { AR_SREV_VERSION_5416_PCI, "5416" }, + { AR_SREV_VERSION_5416_PCIE, "5418" }, + { AR_SREV_VERSION_9100, "9100" }, + { AR_SREV_VERSION_9160, "9160" }, + { AR_SREV_VERSION_9280, "9280" }, + { AR_SREV_VERSION_9285, "9285" } +}; + +static struct { + u16 version; + const char * name; +} ath_rf_names[] = { + { 0, "5133" }, + { AR_RAD5133_SREV_MAJOR, "5133" }, + { AR_RAD5122_SREV_MAJOR, "5122" }, + { AR_RAD2133_SREV_MAJOR, "2133" }, + { AR_RAD2122_SREV_MAJOR, "2122" } +}; + +/* + * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. + */ + +static const char * +ath_mac_bb_name(u32 mac_bb_version) +{ + int i; + + for (i=0; ivendor, id->device); - - printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n", + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x " + "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - athname ? athname : "Atheros ???", + ath_mac_bb_name(ah->ah_macVersion), + ah->ah_macRev, + ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->ah_phyRev, (unsigned long)mem, pdev->irq); return 0; -- cgit v1.1 From 6a53a8a99cb044e1873648ba184440db6d9c65b8 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Tue, 4 Nov 2008 00:25:54 +0200 Subject: ath5k: Fix IMR init *On a previous patch i splitted AR5K_INT_TX to multiple different TX interrupt flags for better handling but i forgot to unmask the new TXDESC and TXEOL interrupts on ath5k_init and only left TXOK. However for each queue we enable TXDESC and TXEOL interrupts, not TXOK so we don't handle TX interrupts at all (because these interrupts remain masked on PISR) and under load it results packet loss. Fix the problem by unmasking TXDESC and TXEOL on ath5k_init. Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c7ffcbb..1ed152f 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2219,9 +2219,9 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume) */ sc->curchan = sc->hw->conf.channel; sc->curband = &sc->sbands[sc->curchan->band]; - sc->imask = AR5K_INT_RXOK | AR5K_INT_TXOK | AR5K_INT_RXEOL | - AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | - AR5K_INT_MIB; + sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; ret = ath5k_reset(sc, false, false); if (ret) goto done; -- cgit v1.1 From 296bf2aefdf7b4b1bf093a7b42a86ee21b46d07f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Nov 2008 14:43:00 -0800 Subject: ath5k: allow APs to receive beacons Allow APs to receive beacons to detect when it needs to use protection to update the NAV correctly on 11b stations. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 1ed152f..34cd1a4 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2953,9 +2953,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, test_bit(ATH_STAT_PROMISC, sc->status)) rfilt |= AR5K_RX_FILTER_PROM; if (sc->opmode == NL80211_IFTYPE_STATION || - sc->opmode == NL80211_IFTYPE_ADHOC) { + sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_AP) rfilt |= AR5K_RX_FILTER_BEACON; - } if (sc->opmode == NL80211_IFTYPE_MESH_POINT) rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; -- cgit v1.1 From ffb826767bffda61426d964a8fc24a216a14b0bd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Nov 2008 14:43:01 -0800 Subject: ath9k: enable RXing of beacons on STA/IBSS This enables beacons to come through on STA/IBSS. It should fix sporadic connection issues. Right now mac80211 expect beacons so give it beacons. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/recv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 2ecb0a0..2d72ac1 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -296,9 +296,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) && - (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) + if (sc->sc_ah->ah_opmode == ATH9K_M_STA || + sc->sc_ah->ah_opmode == ATH9K_M_IBSS) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames -- cgit v1.1 From 3e4127fa6db34765685599fb8d1177e51850a63c Mon Sep 17 00:00:00 2001 From: Alexey Fisher Date: Thu, 6 Nov 2008 09:51:16 +0100 Subject: ipw2200: make association only if SSID is known. 'iwconfig eth1 channel 6' would trigger association to _something_, which is wrong. Changing the channel should (and does) trigger reassociation, but only if there is an SSID to associate with. Signed-off-by: Alexey Fisher Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 051ae92..6ca0f1c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7575,8 +7575,7 @@ static int ipw_associate(void *data) } if (!(priv->config & CFG_ASSOCIATE) && - !(priv->config & (CFG_STATIC_ESSID | - CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) { + !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) { IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); return 0; } -- cgit v1.1 From 7f3704e992ee4044f8e0068e060458377004473a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Nov 2008 15:18:11 +0100 Subject: b43legacy: implement short slot and basic rate handling This implements proper short slot handling and adds code to program the hardware for the correct response rates derived from the basic rate set for the current BSS. (port from b43) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/b43legacy.h | 5 +- drivers/net/wireless/b43legacy/main.c | 111 +++++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index c40078e..97b0e06 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -145,6 +145,10 @@ #define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ #define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */ /* SHM_SHARED rate tables */ +#define B43legacy_SHM_SH_OFDMDIRECT 0x0480 /* Pointer to OFDM direct map */ +#define B43legacy_SHM_SH_OFDMBASIC 0x04A0 /* Pointer to OFDM basic rate map */ +#define B43legacy_SHM_SH_CCKDIRECT 0x04C0 /* Pointer to CCK direct map */ +#define B43legacy_SHM_SH_CCKBASIC 0x04E0 /* Pointer to CCK basic rate map */ /* SHM_SHARED microcode soft registers */ #define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ #define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ @@ -663,7 +667,6 @@ struct b43legacy_wldev { bool bad_frames_preempt;/* Use "Bad Frames Preemption". */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM). */ bool short_preamble; /* TRUE if using short preamble. */ - bool short_slot; /* TRUE if using short slot timing. */ bool radio_hw_enable; /* State of radio hardware enable bit. */ /* PHY/Radio device. */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 6c8eb4d..c1324e3 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -576,13 +576,11 @@ static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev) { b43legacy_set_slot_time(dev, 9); - dev->short_slot = 1; } static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) { b43legacy_set_slot_time(dev, 20); - dev->short_slot = 0; } /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. @@ -2608,16 +2606,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, if (conf->channel->hw_value != phy->channel) b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0); - /* Enable/Disable ShortSlot timing. */ - if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) - != dev->short_slot) { - B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G); - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) - b43legacy_short_slot_timing_enable(dev); - else - b43legacy_short_slot_timing_disable(dev); - } - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); /* Adjust the desired TX power level. */ @@ -2662,6 +2650,104 @@ out_unlock_mutex: return err; } +static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u64 brates) +{ + struct ieee80211_supported_band *sband = + dev->wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + struct ieee80211_rate *rate; + int i; + u16 basic, direct, offset, basic_offset, rateptr; + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + + if (b43legacy_is_cck_rate(rate->hw_value)) { + direct = B43legacy_SHM_SH_CCKDIRECT; + basic = B43legacy_SHM_SH_CCKBASIC; + offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value); + offset &= 0xF; + } else { + direct = B43legacy_SHM_SH_OFDMDIRECT; + basic = B43legacy_SHM_SH_OFDMBASIC; + offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value); + offset &= 0xF; + } + + rate = ieee80211_get_response_rate(sband, brates, rate->bitrate); + + if (b43legacy_is_cck_rate(rate->hw_value)) { + basic_offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value); + basic_offset &= 0xF; + } else { + basic_offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value); + basic_offset &= 0xF; + } + + /* + * Get the pointer that we need to point to + * from the direct map + */ + rateptr = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + direct + 2 * basic_offset); + /* and write it to the basic map */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + basic + 2 * offset, rateptr); + } +} + +static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + struct b43legacy_phy *phy; + unsigned long flags; + u32 savedirqs; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + b43legacy_mac_suspend(dev); + + if (changed & BSS_CHANGED_BASIC_RATES) + b43legacy_update_basic_rates(dev, conf->basic_rates); + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + b43legacy_short_slot_timing_enable(dev); + else + b43legacy_short_slot_timing_disable(dev); + } + + b43legacy_mac_enable(dev); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + /* XXX: why? */ + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); + out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return; +} + static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *fflags, @@ -3370,6 +3456,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .add_interface = b43legacy_op_add_interface, .remove_interface = b43legacy_op_remove_interface, .config = b43legacy_op_dev_config, + .bss_info_changed = b43legacy_op_bss_info_changed, .config_interface = b43legacy_op_config_interface, .configure_filter = b43legacy_op_configure_filter, .get_stats = b43legacy_op_get_stats, -- cgit v1.1 From 1e87d68083cd073c84edb3a71fa4365d7fc092bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Nov 2008 17:20:24 +0100 Subject: b43: remove rate index warning I frequently run into this warning, and added some debugging to see why, and got this: b43 bad rx: 00000000: 2f d2 e2 63 cf a7 14 04 28 18 c8 5f 88 4a a2 00 bogus junk | plcp | fctl| dur b43 bad rx: 00000010: 00 11 24 91 07 4d 00 06 25 ff 8f 78 00 06 25 ff my MAC address | BSSID | AP MAC b43 bad rx: 00000020: 8f 76 20 74 00 00 42 07 00 20 00 00 00 00 aa aa | seq | QoS | CCMP IV | data ... As you can see, there are 6 bogus bytes (sometimes only five) and then the frame. I don't know why, and I don't see how to recover, so let's just drop these frames. Signed-off-by: Johannes Berg Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index adba89b..eae9b80 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -46,7 +46,6 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) case 0x6E: return 3; } - B43_WARN_ON(1); return -1; } @@ -73,7 +72,6 @@ static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) case 0xC: return base + 7; } - B43_WARN_ON(1); return -1; } @@ -608,6 +606,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) phytype == B43_PHYTYPE_A); else status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); + if (unlikely(status.rate_idx == -1)) + goto drop; status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); /* -- cgit v1.1 From ada1751346b5539f393c2e9c9dc04d9e7078e53a Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 7 Nov 2008 09:58:34 -0800 Subject: iwlagn: fix resume for ADHOC network ieee80211_notify_mac only reconnect BSS networks. Since IBSS does not need any auth or assoc steps we can just resume to the same condition before suspend. This patch will reestablish the ad-hoc network once it comes back from resume. http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1774 Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 35cfa15..6404093 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2002,6 +2002,10 @@ static int iwl_read_ucode(struct iwl_priv *priv) return ret; } +/* temporary */ +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb); + /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2084,6 +2088,15 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_power_update_mode(priv, 1); + /* reassociate for ADHOC mode */ + if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { + struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, + priv->vif); + if (beacon) + iwl_mac_beacon_update(priv->hw, beacon); + } + + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) iwl_set_mode(priv, priv->iw_mode); @@ -2930,8 +2943,6 @@ static void iwl_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); static int iwl_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -2953,7 +2964,9 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; + mutex_lock(&priv->mutex); rc = iwl_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) return rc; } @@ -3529,18 +3542,15 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) unsigned long flags; __le64 timestamp; - mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); return -EIO; } if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); return -EIO; } @@ -3562,7 +3572,6 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) iwl_post_associate(priv); - mutex_unlock(&priv->mutex); return 0; } -- cgit v1.1 From 9bdf5ecabf1cd2fb012f87d9742590fdd8290da0 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 7 Nov 2008 09:58:35 -0800 Subject: iwl3945: fix resume for ADHOC network ieee80211_notify_mac only reconnect BSS networks. Since IBSS does not need any auth or assoc steps we can just resume to the same condition before suspend. This patch will reestablish the ad-hoc network once it comes back from resume. http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1774 Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a3ec4d0..0f992d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5601,6 +5601,10 @@ static void iwl3945_init_alive_start(struct iwl3945_priv *priv) } +/* temporary */ +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb); + /** * iwl3945_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -5704,6 +5708,14 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (priv->error_recovering) iwl3945_error_recovery(priv); + /* reassociate for ADHOC mode */ + if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { + struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, + priv->vif); + if (beacon) + iwl3945_mac_beacon_update(priv->hw, beacon); + } + return; restart: @@ -6710,9 +6722,6 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); - static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) @@ -6734,7 +6743,9 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; + mutex_lock(&priv->mutex); rc = iwl3945_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) return rc; } @@ -7188,18 +7199,15 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk struct iwl3945_priv *priv = hw->priv; unsigned long flags; - mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); return -EIO; } if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); return -EIO; } @@ -7219,7 +7227,6 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl3945_post_associate(priv); - mutex_unlock(&priv->mutex); return 0; } -- cgit v1.1 From 193357748979985498f21abc94c7a0a3ed5a3b8e Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 7 Nov 2008 09:58:36 -0800 Subject: iwlwifi: trivial fix in includes This patch removes one FIXME: in rearranging includes Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8eb0203..ec474db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -30,10 +30,9 @@ #include #include -struct iwl_priv; /* FIXME: remove */ -#include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-dev.h" /* FIXME: remove */ +#include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-rfkill.h" -- cgit v1.1 From a71c8f62d46e4496011182658dc058303960c068 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 7 Nov 2008 09:58:37 -0800 Subject: iwlwifi: don't fail power set when calibration is not done yet This patch doesn't fail power save setting when calibration is not done yet. The new power index is registered and will be evaluated again anyway upon calibration completion. This patch also eliminates WARN_ON in mac80211 hw_config during initialization Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 07a5f60..b429daa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -257,15 +257,11 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; u16 uninitialized_var(final_mode); + bool update_chains; /* Don't update the RX chain when chain noise calibration is running */ - if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE && - priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) { - IWL_DEBUG_POWER("Cannot update the power, chain noise " - "calibration running: %d\n", - priv->chain_noise_data.state); - return -EAGAIN; - } + update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || + priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; /* If on battery, set to 3, * if plugged into AC power, set to CAM ("continuously aware mode"), @@ -313,9 +309,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) else set_bit(STATUS_POWER_PMI, &priv->status); - if (priv->cfg->ops->lib->update_chain_flags) + if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); - + else + IWL_DEBUG_POWER("Cannot update the power, chain noise " + "calibration running: %d\n", + priv->chain_noise_data.state); if (!ret) setting->power_mode = final_mode; } -- cgit v1.1 From 5c5aa3f13a50881b8f6e529e321bbefb5faec37b Mon Sep 17 00:00:00 2001 From: "Halperin, Daniel C" Date: Fri, 7 Nov 2008 09:58:38 -0800 Subject: iwlwifi: update iwl-commands.h for 3 stream support This patch updates comments and constants to support 1, 2, or 3 spatial streams in rate_n_flags . Signed-off-by: Daniel Halperin Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8aade00..1fe83d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -213,10 +213,11 @@ struct iwl_cmd_header { } __attribute__ ((packed)); /** - * 4965 rate_n_flags bit fields + * iwlagn rate_n_flags bit fields * - * rate_n_flags format is used in following 4965 commands: + * rate_n_flags format is used in following iwlagn commands: * REPLY_RX (response only) + * REPLY_RX_MPDU (response only) * REPLY_TX (both command and response) * REPLY_TX_LINK_QUALITY_CMD * @@ -230,8 +231,9 @@ struct iwl_cmd_header { * 6) 54 Mbps * 7) 60 Mbps * - * 3: 0) Single stream (SISO) + * 4-3: 0) Single stream (SISO) * 1) Dual stream (MIMO) + * 2) Triple stream (MIMO) * * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data * @@ -252,8 +254,8 @@ struct iwl_cmd_header { * 110) 11 Mbps */ #define RATE_MCS_CODE_MSK 0x7 -#define RATE_MCS_MIMO_POS 3 -#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_SPATIAL_POS 3 +#define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 -- cgit v1.1 From 8d86422a83d79e3d3241cf0f269fca0c2640bcee Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 7 Nov 2008 09:58:39 -0800 Subject: iwlwifi: move rx queue read pointer into rxq This patch moves rx status/read registers into iwl_rx_queue structures. This solution is more memory hungry but is more structured and provides needed RX/TX separation Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 27 --------------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 9 --------- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 29 ----------------------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 9 --------- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 9 ++++----- drivers/net/wireless/iwlwifi/iwl-fh.h | 16 ++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-rx.c | 18 ++++++++++++++++-- 9 files changed, 37 insertions(+), 83 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 9da7c7b..94ae1a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -927,33 +927,6 @@ struct iwl4965_schedq_bc_tbl { */ struct iwl4965_shared { struct iwl4965_schedq_bc_tbl queues_bc_tbls[IWL49_NUM_QUEUES]; - __le32 rb_closed; - - /* __le32 rb_closed_stts_rb_num:12; */ -#define IWL_rb_closed_stts_rb_num_POS 0 -#define IWL_rb_closed_stts_rb_num_LEN 12 -#define IWL_rb_closed_stts_rb_num_SYM rb_closed - /* __le32 rsrv1:4; */ - /* __le32 rb_closed_stts_rx_frame_num:12; */ -#define IWL_rb_closed_stts_rx_frame_num_POS 16 -#define IWL_rb_closed_stts_rx_frame_num_LEN 12 -#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed - /* __le32 rsrv2:4; */ - - __le32 frm_finished; - /* __le32 frame_finished_stts_rb_num:12; */ -#define IWL_frame_finished_stts_rb_num_POS 0 -#define IWL_frame_finished_stts_rb_num_LEN 12 -#define IWL_frame_finished_stts_rb_num_SYM frm_finished - /* __le32 rsrv3:4; */ - /* __le32 frame_finished_stts_rx_frame_num:12; */ -#define IWL_frame_finished_stts_rx_frame_num_POS 16 -#define IWL_frame_finished_stts_rx_frame_num_LEN 12 -#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished - /* __le32 rsrv4:4; */ - - __le32 padding1; /* so that allocation will be aligned to 16B */ - __le32 padding2; } __attribute__ ((packed)); #endif /* __iwl4965_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 157cad4..017e5ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1631,12 +1631,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) } #endif -static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) -{ - struct iwl4965_shared *s = priv->shared_virt; - return le32_to_cpu(s->rb_closed) & 0xFFF; -} - static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) { priv->shared_virt = pci_alloc_consistent(priv->pci_dev, @@ -1647,8 +1641,6 @@ static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed); - return 0; } @@ -2306,7 +2298,6 @@ static struct iwl_lib_ops iwl4965_lib = { .set_hw_params = iwl4965_hw_set_hw_params, .alloc_shared_mem = iwl4965_alloc_shared_mem, .free_shared_mem = iwl4965_free_shared_mem, - .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .txq_set_sched = iwl4965_txq_set_sched, .txq_agg_enable = iwl4965_txq_agg_enable, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 12c7404..8f9edc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -96,38 +96,9 @@ struct iwl5000_schedq_bc_tbl { /** * struct iwl5000_shared - * @rb_closed - * address is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ struct iwl5000_shared { struct iwl5000_schedq_bc_tbl queues_bc_tbls[IWL50_NUM_QUEUES]; - __le32 rb_closed; - - /* __le32 rb_closed_stts_rb_num:12; */ -#define IWL_rb_closed_stts_rb_num_POS 0 -#define IWL_rb_closed_stts_rb_num_LEN 12 -#define IWL_rb_closed_stts_rb_num_SYM rb_closed - /* __le32 rsrv1:4; */ - /* __le32 rb_closed_stts_rx_frame_num:12; */ -#define IWL_rb_closed_stts_rx_frame_num_POS 16 -#define IWL_rb_closed_stts_rx_frame_num_LEN 12 -#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed - /* __le32 rsrv2:4; */ - - __le32 frm_finished; - /* __le32 frame_finished_stts_rb_num:12; */ -#define IWL_frame_finished_stts_rb_num_POS 0 -#define IWL_frame_finished_stts_rb_num_LEN 12 -#define IWL_frame_finished_stts_rb_num_SYM frm_finished - /* __le32 rsrv3:4; */ - /* __le32 frame_finished_stts_rx_frame_num:12; */ -#define IWL_frame_finished_stts_rx_frame_num_POS 16 -#define IWL_frame_finished_stts_rx_frame_num_LEN 12 -#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished - /* __le32 rsrv4:4; */ - - __le32 padding1; /* so that allocation will be aligned to 16B */ - __le32 padding2; } __attribute__ ((packed)); #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 31e62a8..e81000c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -863,8 +863,6 @@ static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); - priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); - return 0; } @@ -877,12 +875,6 @@ static void iwl5000_free_shared_mem(struct iwl_priv *priv) priv->shared_phys); } -static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) -{ - struct iwl5000_shared *s = priv->shared_virt; - return le32_to_cpu(s->rb_closed) & 0xFFF; -} - /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -1460,7 +1452,6 @@ static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .alloc_shared_mem = iwl5000_alloc_shared_mem, .free_shared_mem = iwl5000_free_shared_mem, - .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6404093..c1ed02e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1359,7 +1359,7 @@ void iwl_rx_handle(struct iwl_priv *priv) /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ - r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); + r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; /* Rx interrupt, but nothing sent from uCode */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 10f07f6..1dca9d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -105,7 +105,6 @@ struct iwl_lib_ops { /* ucode shared memory */ int (*alloc_shared_mem)(struct iwl_priv *priv); void (*free_shared_mem)(struct iwl_priv *priv); - int (*shared_mem_rx_idx)(struct iwl_priv *priv); /* Handling TX */ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d509aed..55590a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -301,7 +301,6 @@ struct iwl_host_cmd { /** * struct iwl_rx_queue - Rx queue - * @processed: Internal index to last handled Rx packet * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free @@ -316,13 +315,14 @@ struct iwl_rx_queue { dma_addr_t dma_addr; struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 processed; u32 read; u32 write; u32 free_count; struct list_head rx_free; struct list_head rx_used; int need_update; + struct iwl_rb_status *rb_stts; + dma_addr_t rb_stts_dma; spinlock_t lock; }; @@ -967,10 +967,9 @@ struct iwl_priv { struct ieee80211_vif *vif; struct iwl_hw_params hw_params; - /* driver/uCode shared Tx Byte Counts and Rx status */ + /* driver/uCode shared Tx Byte Counts */ void *shared_virt; - int rb_closed_offset; - /* Physical Pointer to Tx Byte Counts and Rx status */ + /* Physical Pointer to Tx Byte Counts */ dma_addr_t shared_phys; /* Current association information needed to configure the diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 97e2cf4..1537542 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -403,5 +403,21 @@ #define TFD_QUEUE_SIZE_BC_DUP (64) #define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) +/** + * struct iwl_rb_status - reseve buffer status + * host memory mapped FH registers + * @closed_rb_num [0:11] - Indicates the index of the RB which was closed + * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed + * @finished_rb_num [0:11] - Indicates the index of the current RB + * in which the last frame was written to + * @finished_fr_num [0:11] - Indicates the index of the RX Frame + * which was transfered + */ +struct iwl_rb_status { + __le16 closed_rb_num; + __le16 closed_fr_num; + __le16 finished_rb_num; + __le16 finished_fr_nam; +} __attribute__ ((packed)); #endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b3c35c6..48d5574 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -317,7 +317,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, rxq->dma_addr); + pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; + rxq->rb_stts = NULL; } EXPORT_SYMBOL(iwl_rx_queue_free); @@ -334,7 +337,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) - return -ENOMEM; + goto err_bd; + + rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status), + &rxq->rb_stts_dma); + if (!rxq->rb_stts) + goto err_rb; /* Fill the rx_used queue with _all_ of the Rx buffers */ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) @@ -346,6 +354,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) rxq->free_count = 0; rxq->need_update = 0; return 0; + +err_rb: + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); +err_bd: + return -ENOMEM; } EXPORT_SYMBOL(iwl_rx_queue_alloc); @@ -412,7 +426,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Tell device where in DRAM to update its Rx status */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->shared_phys + priv->rb_closed_offset) >> 4); + rxq->rb_stts_dma >> 4); /* Enable Rx DMA * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in -- cgit v1.1 From 4ddbb7d060061e584cb2137f4c7e41e502a560b4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 7 Nov 2008 09:58:40 -0800 Subject: iwlwifi: revamp tx scheduler byte count tables handling This moves byte count tables to tx domain removing completely ambivalent shared data. Changes handling of allocation byte count tables and keep warm consistent memory Moves general tx scheduler definitions from iwl-4956-hw.h to iwl-fh.h Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 90 +----------------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 35 ++---------- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 8 +-- drivers/net/wireless/iwlwifi/iwl-5000.c | 45 ++++----------- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 --- drivers/net/wireless/iwlwifi/iwl-core.c | 46 --------------- drivers/net/wireless/iwlwifi/iwl-core.h | 7 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 21 +++---- drivers/net/wireless/iwlwifi/iwl-fh.h | 65 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-tx.c | 48 ++++++++++++---- 10 files changed, 129 insertions(+), 244 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 94ae1a8..fb0fd77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -819,64 +819,6 @@ enum { #define IWL49_NUM_QUEUES 16 #define IWL49_NUM_AMPDU_QUEUES 8 -#define IWL_TX_DMA_MASK (DMA_BIT_MASK(36) & ~0x3) -#define IWL_NUM_OF_TBS 20 - -static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) -{ - return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF; -} -/** - * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor - * - * This structure contains dma address and length of transmission address - * - * @lo: low [31:0] portion of the dma address of TX buffer - * every even is unaligned on 16 bit boundary - * @hi_n_len 0-3 [35:32] portion of dma - * 4-16 length of the tx buffer - */ -struct iwl_tfd_tb { - __le32 lo; - __le16 hi_n_len; -} __attribute__((packed)); - -/** - * struct iwl_tfd - * - * Transmit Frame Descriptor (TFD) - * - * @ __reserved1[3] reserved - * @ num_tbs 0-5 number of active tbs - * 6-7 padding (not used) - * @ tbs[20] transmit frame buffer descriptors - * @ __pad padding - * - * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. - * Both driver and device share these circular buffers, each of which must be - * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes - * - * Driver must indicate the physical address of the base of each - * circular buffer via the FH_MEM_CBBC_QUEUE registers. - * - * Each TFD contains pointer/size information for up to 20 data buffers - * in host DRAM. These buffers collectively contain the (one) frame described - * by the TFD. Each buffer must be a single contiguous block of memory within - * itself, but buffers may be scattered in host DRAM. Each buffer has max size - * of (4K - 4). The concatenates all of a TFD's buffers into a single - * Tx frame, up to 8 KBytes in size. - * - * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. - * - * Bit fields in the control dword (val0): - */ -struct iwl_tfd { - u8 __reserved1[3]; - u8 num_tbs; - struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS]; - __le32 __pad; -} __attribute__ ((packed)); - /** * struct iwl4965_schedq_bc_tbl @@ -896,37 +838,9 @@ struct iwl_tfd { * padding puts each byte count table on a 1024-byte boundary; * 4965 assumes tables are separated by 1024 bytes. */ -struct iwl4965_schedq_bc_tbl { +struct iwl4965_scd_bc_tbl { __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)]; } __attribute__ ((packed)); - -/** - * struct iwl4965_shared - handshake area for Tx and Rx - * - * For convenience in allocating memory, this structure combines 2 areas of - * DRAM which must be shared between driver and 4965. These do not need to - * be combined, if better allocation would result from keeping them separate: - * - * 1) The Tx byte count tables occupy 1024 bytes each (16 KBytes total for - * 16 queues). Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find - * the first of these tables. 4965 assumes tables are 1024 bytes apart. - * - * 2) The Rx status (val0 and val1) occupies only 8 bytes. Driver uses - * FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area. - * Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD) - * that has been filled by the 4965. - * - * Bit fields val0: - * 31-12: Not used - * 11- 0: Index of last filled Rx buffer descriptor (4965 writes, driver reads) - * - * Bit fields val1: - * 31- 0: Not used - */ -struct iwl4965_shared { - struct iwl4965_schedq_bc_tbl queues_bc_tbls[IWL49_NUM_QUEUES]; -} __attribute__ ((packed)); - -#endif /* __iwl4965_4965_hw_h__ */ +#endif /* !__iwl_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 017e5ea..c43cf2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -715,8 +715,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) /* Tel 4965 where to find Tx byte count tables */ iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, - (priv->shared_phys + - offsetof(struct iwl4965_shared, queues_bc_tbls)) >> 10); + priv->scd_bc_tbls.dma >> 10); /* Disable chain mode for all queues */ iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); @@ -804,6 +803,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.scd_bc_tbls_size = + IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; @@ -1631,28 +1632,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) } #endif -static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) -{ - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; - - memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - - return 0; -} - -static void iwl4965_free_shared_mem(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - priv->shared_virt, - priv->shared_phys); -} - /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -1660,7 +1639,7 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - struct iwl4965_shared *shared_data = priv->shared_virt; + struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; int write_ptr = txq->q.write_ptr; int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; @@ -1670,11 +1649,11 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, bc_ent = cpu_to_le16(len & 0xFFF); /* Set up byte count within first 256 entries */ - shared_data->queues_bc_tbls[txq_id].tfd_offset[write_ptr] = bc_ent; + scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; /* If within first 64 entries, duplicate at end */ if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) - shared_data->queues_bc_tbls[txq_id]. + scd_bc_tbl[txq_id]. tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } @@ -2296,8 +2275,6 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { static struct iwl_lib_ops iwl4965_lib = { .set_hw_params = iwl4965_hw_set_hw_params, - .alloc_shared_mem = iwl4965_alloc_shared_mem, - .free_shared_mem = iwl4965_free_shared_mem, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .txq_set_sched = iwl4965_txq_set_sched, .txq_agg_enable = iwl4965_txq_agg_enable, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 8f9edc7..c6595e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -90,16 +90,10 @@ * @tfd_offset 0-12 - tx command byte count * 12-16 - station index */ -struct iwl5000_schedq_bc_tbl { +struct iwl5000_scd_bc_tbl { __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; } __attribute__ ((packed)); -/** - * struct iwl5000_shared - */ -struct iwl5000_shared { - struct iwl5000_schedq_bc_tbl queues_bc_tbls[IWL50_NUM_QUEUES]; -} __attribute__ ((packed)); #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e81000c..ee3613d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -721,11 +721,9 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_write_targ_mem(priv, a, 0); iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, - (priv->shared_phys + - offsetof(struct iwl5000_shared, queues_bc_tbls)) >> 10); + priv->scd_bc_tbls.dma >> 10); iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, - IWL50_SCD_QUEUECHAIN_SEL_ALL( - priv->hw_params.max_txq_num)); + IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); /* initiate the queues */ @@ -788,6 +786,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.scd_bc_tbls_size = + IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; @@ -853,28 +853,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) return 0; } -static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) -{ - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl5000_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; - - memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); - - return 0; -} - -static void iwl5000_free_shared_mem(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl5000_shared), - priv->shared_virt, - priv->shared_phys); -} - /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -882,7 +860,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - struct iwl5000_shared *shared_data = priv->shared_virt; + struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int write_ptr = txq->q.write_ptr; int txq_id = txq->q.id; u8 sec_ctl = 0; @@ -911,17 +889,17 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); - shared_data->queues_bc_tbls[txq_id].tfd_offset[write_ptr] = bc_ent; + scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) - shared_data->queues_bc_tbls[txq_id]. + scd_bc_tbl[txq_id]. tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - struct iwl5000_shared *shared_data = priv->shared_virt; + struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; int read_ptr = txq->q.read_ptr; u8 sta_id = 0; @@ -933,11 +911,10 @@ static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; bc_ent = cpu_to_le16(1 | (sta_id << 12)); - shared_data->queues_bc_tbls[txq_id]. - tfd_offset[read_ptr] = bc_ent; + scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) - shared_data->queues_bc_tbls[txq_id]. + scd_bc_tbl[txq_id]. tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } @@ -1450,8 +1427,6 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, - .alloc_shared_mem = iwl5000_alloc_shared_mem, - .free_shared_mem = iwl5000_free_shared_mem, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1ed02e..a9000f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2196,8 +2196,6 @@ static void __iwl_down(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); - priv->cfg->ops->lib->free_shared_mem(priv); - exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); @@ -2250,12 +2248,6 @@ static int __iwl_up(struct iwl_priv *priv) iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - ret = priv->cfg->ops->lib->alloc_shared_mem(priv); - if (ret) { - IWL_ERROR("Unable to allocate shared memory\n"); - return ret; - } - ret = iwl_hw_nic_init(priv); if (ret) { IWL_ERROR("Unable to init nic\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ec474db..8bd4d08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -189,52 +189,6 @@ void iwl_hw_detect(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_detect); -/* Tell nic where to find the "keep warm" buffer */ -int iwl_kw_init(struct iwl_priv *priv) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, - priv->kw.dma_addr >> 4); - iwl_release_nic_access(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; -} - -int iwl_kw_alloc(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; - - kw->size = IWL_KW_SIZE; - kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); - if (!kw->v_addr) - return -ENOMEM; - - return 0; -} - -/** - * iwl_kw_free - Free the "keep warm" buffer - */ -void iwl_kw_free(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; - - if (kw->v_addr) { - pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); - memset(kw, 0, sizeof(*kw)); - } -} - int iwl_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 1dca9d3..1ae7a11 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -102,9 +102,6 @@ struct iwl_hcmd_utils_ops { struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); - /* ucode shared memory */ - int (*alloc_shared_mem)(struct iwl_priv *priv); - void (*free_shared_mem)(struct iwl_priv *priv); /* Handling TX */ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq, @@ -197,10 +194,6 @@ int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); -/* "keep warm" functions */ -int iwl_kw_init(struct iwl_priv *priv); -int iwl_kw_alloc(struct iwl_priv *priv); -void iwl_kw_free(struct iwl_priv *priv); /***************************************************** * RX diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 55590a5..c360960 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -507,6 +507,7 @@ struct iwl_sensitivity_ranges { /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported + * @scd_bc_tbls_size: size of scheduler byte count tables * @tx/rx_chains_num: Number of TX/RX chains * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) @@ -524,6 +525,7 @@ struct iwl_sensitivity_ranges { */ struct iwl_hw_params { u16 max_txq_num; + u16 scd_bc_tbls_size; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; @@ -605,13 +607,9 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) struct iwl_priv; -/* Structures, enum, and defines specific to the 4965 */ - -#define IWL_KW_SIZE 0x1000 /*4k */ - -struct iwl_kw { - dma_addr_t dma_addr; - void *v_addr; +struct iwl_dma_ptr { + dma_addr_t dma; + void *addr; size_t size; }; @@ -907,7 +905,9 @@ struct iwl_priv { struct iwl_rx_queue rxq; struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long txq_ctx_active_msk; - struct iwl_kw kw; /* keep warm address */ + struct iwl_dma_ptr kw; /* keep warm address */ + struct iwl_dma_ptr scd_bc_tbls; + u32 scd_base_addr; /* scheduler sram base address */ unsigned long status; @@ -967,10 +967,7 @@ struct iwl_priv { struct ieee80211_vif *vif; struct iwl_hw_params hw_params; - /* driver/uCode shared Tx Byte Counts */ - void *shared_virt; - /* Physical Pointer to Tx Byte Counts */ - dma_addr_t shared_phys; + /* Current association information needed to configure the * hardware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 1537542..2c5f919 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -420,4 +420,69 @@ struct iwl_rb_status { __le16 finished_fr_nam; } __attribute__ ((packed)); + + +#define IWL_TX_DMA_MASK DMA_BIT_MASK(36) + +#define IWL_NUM_OF_TBS 20 + +static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) +{ + return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF; +} +/** + * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor + * + * This structure contains dma address and length of transmission address + * + * @lo: low [31:0] portion of the dma address of TX buffer + * every even is unaligned on 16 bit boundary + * @hi_n_len 0-3 [35:32] portion of dma + * 4-16 length of the tx buffer + */ +struct iwl_tfd_tb { + __le32 lo; + __le16 hi_n_len; +} __attribute__((packed)); + +/** + * struct iwl_tfd + * + * Transmit Frame Descriptor (TFD) + * + * @ __reserved1[3] reserved + * @ num_tbs 0-5 number of active tbs + * 6-7 padding (not used) + * @ tbs[20] transmit frame buffer descriptors + * @ __pad padding + * + * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. + * Both driver and device share these circular buffers, each of which must be + * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes + * + * Driver must indicate the physical address of the base of each + * circular buffer via the FH_MEM_CBBC_QUEUE registers. + * + * Each TFD contains pointer/size information for up to 20 data buffers + * in host DRAM. These buffers collectively contain the (one) frame described + * by the TFD. Each buffer must be a single contiguous block of memory within + * itself, but buffers may be scattered in host DRAM. Each buffer has max size + * of (4K - 4). The concatenates all of a TFD's buffers into a single + * Tx frame, up to 8 KBytes in size. + * + * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. + * + * Bit fields in the control dword (val0): + */ +struct iwl_tfd { + u8 __reserved1[3]; + u8 num_tbs; + struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS]; + __le32 __pad; +} __attribute__ ((packed)); + + +/* Keep Warm Size */ +#define IWL_KW_SIZE 0x1000 /*4k */ + #endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7d8b4e2..725f62f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -56,6 +56,26 @@ static const u16 default_tid_to_tx_fifo[] = { IWL_TX_FIFO_AC3 }; +static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr, size_t size) +{ + ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma); + if (!ptr->addr) + return -ENOMEM; + ptr->size = size; + return 0; +} + +static inline void iwl_free_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr) +{ + if (unlikely(!ptr->addr)) + return; + + pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma); + memset(ptr, 0, sizeof(*ptr)); +} + static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) { struct iwl_tfd_tb *tb = &tfd->tbs[idx]; @@ -517,8 +537,9 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) else iwl_tx_queue_free(priv, txq_id); - /* Keep-warm buffer */ - iwl_kw_free(priv); + iwl_free_dma_ptr(priv, &priv->kw); + + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); @@ -535,13 +556,17 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) int txq_id, slots_num; unsigned long flags; - iwl_kw_free(priv); - /* Free all tx/cmd queues and keep-warm buffer */ iwl_hw_txq_ctx_free(priv); + ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls, + priv->hw_params.scd_bc_tbls_size); + if (ret) { + IWL_ERROR("Scheduler BC Table allocation failed\n"); + goto error_bc_tbls; + } /* Alloc keep-warm buffer */ - ret = iwl_kw_alloc(priv); + ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); if (ret) { IWL_ERROR("Keep Warm allocation failed\n"); goto error_kw; @@ -556,16 +581,13 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) /* Turn off all Tx DMA fifos */ priv->cfg->ops->lib->txq_set_sched(priv, 0); + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - /* Tell nic where to find the keep-warm buffer */ - ret = iwl_kw_init(priv); - if (ret) { - IWL_ERROR("kw_init failed\n"); - goto error_reset; - } /* Alloc and init all Tx queues, including the command queue (#4) */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { @@ -584,8 +606,10 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error: iwl_hw_txq_ctx_free(priv); error_reset: - iwl_kw_free(priv); + iwl_free_dma_ptr(priv, &priv->kw); error_kw: + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); + error_bc_tbls: return ret; } -- cgit v1.1 From 21c339bf51ad46c6f8143df907b4bcce99dbe0b8 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 7 Nov 2008 09:58:41 -0800 Subject: iwlwifi: move spectrum measurement code to iwl-spectrum.c file This patch moves spectrum measurement code into iwl-sepctrum.c file. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 229 +--------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 8 + drivers/net/wireless/iwlwifi/iwl-spectrum.c | 198 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-spectrum.h | 1 + 5 files changed, 209 insertions(+), 228 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-spectrum.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 47aa28f..8b45b30 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,6 +5,7 @@ iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o +iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a9000f1..8fa4f7a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -871,138 +871,6 @@ static void iwl_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - -#include "iwl-spectrum.h" - -#define BEACON_TIME_MASK_LOW 0x00FFFFFF -#define BEACON_TIME_MASK_HIGH 0xFF000000 -#define TIME_UNIT 1024 - -/* - * extended beacon time format - * time in usec will be changed into a 32-bit value in 8:24 format - * the high 1 byte is the beacon counts - * the lower 3 bytes is the time in usec within one beacon interval - */ - -static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) -{ - u32 quot; - u32 rem; - u32 interval = beacon_interval * 1024; - - if (!interval || !usec) - return 0; - - quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); - rem = (usec % interval) & BEACON_TIME_MASK_LOW; - - return (quot << 24) + rem; -} - -/* base is usually what we get from ucode with each received frame, - * the same as HW timer counter counting down - */ - -static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) -{ - u32 base_low = base & BEACON_TIME_MASK_LOW; - u32 addon_low = addon & BEACON_TIME_MASK_LOW; - u32 interval = beacon_interval * TIME_UNIT; - u32 res = (base & BEACON_TIME_MASK_HIGH) + - (addon & BEACON_TIME_MASK_HIGH); - - if (base_low > addon_low) - res += base_low - addon_low; - else if (base_low < addon_low) { - res += interval + base_low - addon_low; - res += (1 << 24); - } else - res += (1 << 24); - - return cpu_to_le32(res); -} - -static int iwl_get_measurement(struct iwl_priv *priv, - struct ieee80211_measurement_params *params, - u8 type) -{ - struct iwl4965_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SPECTRUM_MEASUREMENT_CMD, - .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, - }; - u32 add_time = le64_to_cpu(params->start_time); - int rc; - int spectrum_resp_status; - int duration = le16_to_cpu(params->duration); - - if (iwl_is_associated(priv)) - add_time = - iwl_usecs_to_beacons( - le64_to_cpu(params->start_time) - priv->last_tsf, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - - memset(&spectrum, 0, sizeof(spectrum)); - - spectrum.channel_count = cpu_to_le16(1); - spectrum.flags = - RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; - spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; - cmd.len = sizeof(spectrum); - spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - - if (iwl_is_associated(priv)) - spectrum.start_time = - iwl_add_beacon_time(priv->last_beacon_time, - add_time, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - else - spectrum.start_time = 0; - - spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); - spectrum.channels[0].channel = params->channel; - spectrum.channels[0].type = type; - if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) - spectrum.flags |= RXON_FLG_BAND_24G_MSK | - RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); - rc = -EIO; - } - - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); - switch (spectrum_resp_status) { - case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { - IWL_DEBUG_INFO - ("Replaced existing measurement: %d\n", - res->u.spectrum.id); - priv->measurement_status &= ~MEASUREMENT_READY; - } - priv->measurement_status |= MEASUREMENT_ACTIVE; - rc = 0; - break; - - case 1: /* Command will not be handled */ - rc = -EAGAIN; - break; - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} -#endif /****************************************************************************** * @@ -1072,24 +940,6 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) priv->staging_rxon.channel = csa->channel; } -static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); - - if (!report->state) { - IWL_DEBUG(IWL_DL_11H, - "Spectrum Measure Notification: Start\n"); - return; - } - - memcpy(&priv->measure_report, report, sizeof(*report)); - priv->measurement_status |= MEASUREMENT_READY; -#endif -} - static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -1298,8 +1148,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; @@ -1313,6 +1161,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); /* status change handler */ @@ -3767,79 +3616,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - -static ssize_t show_measurement(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl4965_spectrum_notification measure_report; - u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *)&measure_report; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!(priv->measurement_status & MEASUREMENT_READY)) { - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } - memcpy(&measure_report, &priv->measure_report, size); - priv->measurement_status = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (size && (PAGE_SIZE - len)) { - hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); - len = strlen(buf); - if (PAGE_SIZE - len) - buf[len++] = '\n'; - - ofs += 16; - size -= min(size, 16U); - } - - return len; -} - -static ssize_t store_measurement(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_measurement_params params = { - .channel = le16_to_cpu(priv->active_rxon.channel), - .start_time = cpu_to_le64(priv->last_tsf), - .duration = cpu_to_le16(1), - }; - u8 type = IWL_MEASURE_BASIC; - u8 buffer[32]; - u8 channel; - - if (count) { - char *p = buffer; - strncpy(buffer, buf, min(sizeof(buffer), count)); - channel = simple_strtoul(p, NULL, 0); - if (channel) - params.channel = channel; - - p = buffer; - while (*p && *p != ' ') - p++; - if (*p) - type = simple_strtoul(p + 1, NULL, 0); - } - - IWL_DEBUG_INFO("Invoking measurement of type %d on " - "channel %d (for '%s')\n", type, params.channel, buf); - iwl_get_measurement(priv, ¶ms, type); - - return count; -} - -static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, - show_measurement, store_measurement); -#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */ - static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -4092,9 +3868,6 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_channels.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - &dev_attr_measurement.attr, -#endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 1ae7a11..ff966b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -289,6 +289,14 @@ int iwl_send_calib_results(struct iwl_priv *priv); int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); void iwl_calib_free_results(struct iwl_priv *priv); +/******************************************************************************* + * Spectrum Measureemtns in iwl-spectrum.c + ******************************************************************************/ +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT +void iwl_setup_spectrum_handlers(struct iwl_priv *priv); +#else +static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} +#endif /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c new file mode 100644 index 0000000..ad319a1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +/* TOOD: was used in sysfs debug interface need to add to mac */ +#if 0 +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl4965_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +} + +void iwl_setup_spectrum_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; +} +EXPORT_SYMBOL(iwl_setup_spectrum_handlers); diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index a40a217..fa990a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -88,4 +88,5 @@ struct ieee80211_measurement_report { struct ieee80211_basic_report basic[0]; } u; } __attribute__ ((packed)); + #endif -- cgit v1.1 From e720ce9d15050d06e5162d5f70b133caccd64258 Mon Sep 17 00:00:00 2001 From: "Kolekar, Abhijeet" Date: Fri, 7 Nov 2008 09:58:42 -0800 Subject: iwl3945 : Fix Sparse Warnings Patch fixes sparse warnings. No need to convert u8 variable to 32. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0f992d0..dc4c489 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4741,7 +4741,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) +#define IWL_SCAN_PROBE_MASK(n) (BIT(n) | (BIT(n) - BIT(1))) static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, enum ieee80211_band band, -- cgit v1.1 From cb299bae8929705bf025fdbd6ce0ffcc62f5b3d0 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 7 Nov 2008 09:58:43 -0800 Subject: iwlwifi: move iwl_print_hex_dump to iwl-debug.h This patch moves iwl_print_hex_dump to iwl-debug.h where it belongs Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 17 ----------------- 2 files changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 84b7772..0e79a6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -40,6 +40,13 @@ do { if ((priv->debug_level & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) +#define iwl_print_hex_dump(priv, level, p, len) \ +do { \ + if (priv->debug_level & level) \ + print_hex_dump(KERN_DEBUG, "iwl data: ", \ + DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ +} while (0) + #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_debugfs { const char *name; @@ -70,6 +77,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(level, fmt, args...) #define IWL_DEBUG_LIMIT(level, fmt, args...) +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c360960..bd3df55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1089,23 +1089,6 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) -{ - if (!(priv->debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -} -#else -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) -{ -} -#endif - extern const struct iwl_channel_info *iwl_get_channel_info( const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); -- cgit v1.1 From c24f0817458464fc9c54489dba19cd94787e5eaf Mon Sep 17 00:00:00 2001 From: "Kolekar, Abhijeet" Date: Fri, 7 Nov 2008 09:58:44 -0800 Subject: iwl3945 : Simplify iwl3945_send_beacon_cmd Moved rate_msk calculation to iwl3945_rate_get_lowest_plcp. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index dc4c489..3344841 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1418,9 +1418,16 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) +static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv) { u8 i; + int rate_mask; + + /* Set rate mask*/ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + rate_mask = priv->active_rate_basic & 0xF; + else + rate_mask = priv->active_rate_basic & 0xFF0; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; i = iwl3945_rates[i].next_ieee) { @@ -1428,7 +1435,11 @@ static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) return iwl3945_rates[i].plcp; } - return IWL_RATE_INVALID; + /* No valid rate was found. Assign the lowest one */ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + return IWL_RATE_1M_PLCP; + else + return IWL_RATE_6M_PLCP; } static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) @@ -1446,16 +1457,7 @@ static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) return -ENOMEM; } - if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & - 0xFF0); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_6M_PLCP; - } else { - rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_1M_PLCP; - } + rate = iwl3945_rate_get_lowest_plcp(priv); frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate); -- cgit v1.1 From 01ef932341de1fb69848ee0b9206e11baac9c340 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 7 Nov 2008 09:58:45 -0800 Subject: iwlwifi: get some more information about command failure This patch adds additional info about wrong command queue bug Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 725f62f..166f000 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1260,8 +1260,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) * command queue then there a command routing bug has been introduced * in the queue management code. */ if (WARN(txq_id != IWL_CMD_QUEUE_NUM, - "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd)) + "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n", + txq_id, sequence, + priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, + priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { + iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32); return; + } cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; -- cgit v1.1 From e4e58cf8cc646d93de852f32f972448a95387c60 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Fri, 7 Nov 2008 09:58:46 -0800 Subject: iwlwifi: use Rx single frame mode (one Rx frame per RB) The RCSR default value for single frame mode is off (a RB contains more than one frames). But the driver assumes single frame mode apparently. This patch enables single frame mode for the hardware. It also adds a BUG_ON to make sure the allocated skb satisfies the hardware alignment requirement and removes a useless check. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-fh.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-rx.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 2c5f919..e46300c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -266,6 +266,8 @@ #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) +#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME (0x00008000) + /** * Rx Shared Status Registers (RSSR) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 48d5574..876afd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -218,8 +218,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) - || (abs(rxq->write - rxq->read) > 7)) { + if (write != (rxq->write & ~0x7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); @@ -440,6 +439,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME | rb_size| (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); -- cgit v1.1 From 798b7adb4ed3533ab1282f51d16892034cfd8aae Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Nov 2008 15:25:33 +0100 Subject: rt2x00: Cleanup TX/RX entry handling Merge the callback functions init_txentry() and init_rxentry(). This makes life in rt2x00lib a lot simpler and we can cleanup several functions. rt2x00pci contained "fake" FIELD definitions for descriptor words. This is not flexible since it assumes the driver will always have the same field to indicate if a driver is available or not. This should be dependent on the driver, and we should add a callback function for this. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 51 +++++++++++++++++++------------ drivers/net/wireless/rt2x00/rt2500pci.c | 45 ++++++++++++++++----------- drivers/net/wireless/rt2x00/rt2500usb.c | 3 +- drivers/net/wireless/rt2x00/rt2x00.h | 6 ++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 7 ++--- drivers/net/wireless/rt2x00/rt2x00lib.h | 12 ++++++-- drivers/net/wireless/rt2x00/rt2x00pci.c | 13 +++----- drivers/net/wireless/rt2x00/rt2x00pci.h | 11 ------- drivers/net/wireless/rt2x00/rt2x00queue.c | 28 ++--------------- drivers/net/wireless/rt2x00/rt2x00usb.c | 31 +++++++++---------- drivers/net/wireless/rt2x00/rt2x00usb.h | 5 +-- drivers/net/wireless/rt2x00/rt61pci.c | 47 +++++++++++++++++----------- drivers/net/wireless/rt2x00/rt73usb.c | 3 +- 13 files changed, 127 insertions(+), 135 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 42bd38a..861577e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -626,36 +626,47 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Initialization functions. */ -static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt2400pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 2, &word); - rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); - rt2x00_desc_write(entry_priv->desc, 2, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 1, word); + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2400pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); + rt2x00_desc_write(entry_priv->desc, 2, word); + + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1570,8 +1581,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .probe_hw = rt2400pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt2400pci_init_rxentry, - .init_txentry = rt2400pci_init_txentry, + .get_entry_state = rt2400pci_get_entry_state, + .clear_entry = rt2400pci_clear_entry, .set_device_state = rt2400pci_set_device_state, .rfkill_poll = rt2400pci_rfkill_poll, .link_stats = rt2400pci_link_stats, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 928452f..e43ff9c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -722,32 +722,43 @@ dynamic_cca_tune: /* * Initialization functions. */ -static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt2500pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 1, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); + + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2500pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1871,8 +1882,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .probe_hw = rt2500pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt2500pci_init_rxentry, - .init_txentry = rt2500pci_init_txentry, + .get_entry_state = rt2500pci_get_entry_state, + .clear_entry = rt2500pci_clear_entry, .set_device_state = rt2500pci_set_device_state, .rfkill_poll = rt2500pci_rfkill_poll, .link_stats = rt2500pci_link_stats, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 639d5a2..3868e98 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1777,8 +1777,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .probe_hw = rt2500usb_probe_hw, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, - .init_rxentry = rt2x00usb_init_rxentry, - .init_txentry = rt2x00usb_init_txentry, + .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt2500usb_set_device_state, .link_stats = rt2500usb_link_stats, .reset_tuner = rt2500usb_reset_tuner, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8fa971c..4506f6c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -523,10 +523,8 @@ struct rt2x00lib_ops { /* * queue initialization handlers */ - void (*init_rxentry) (struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); - void (*init_txentry) (struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); + bool (*get_entry_state) (struct queue_entry *entry); + void (*clear_entry) (struct queue_entry *entry); /* * Radio control handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e8ca1cb..bb510a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -101,8 +101,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all data queues. */ - rt2x00queue_init_rx(rt2x00dev); - rt2x00queue_init_tx(rt2x00dev); + rt2x00queue_init_queues(rt2x00dev); /* * Enable radio. @@ -576,7 +575,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, entry->skb = NULL; entry->flags = 0; - rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); + rt2x00dev->ops->lib->clear_entry(entry); clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); @@ -708,7 +707,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, entry->skb = skb; entry->flags = 0; - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry); + rt2x00dev->ops->lib->clear_entry(entry); rt2x00queue_index_inc(entry->queue, Q_INDEX); } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 0c3a355..9399733 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -150,8 +150,16 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, */ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); -void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev); -void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev); +/** + * rt2x00queue_init_queues - Initialize all data queues + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * + * This function will loop through all available queues to clear all + * index numbers and set the queue entry to the correct initialization + * state. + */ +void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev); + int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev); int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 62449da..e33bd0f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -36,20 +36,17 @@ */ int rt2x00pci_write_tx_data(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; - u32 word; - - rt2x00_desc_read(entry_priv->desc, 0, &word); /* * This should not happen, we already checked the entry * was ours. When the hardware disagrees there has been * a queue corruption! */ - if (unlikely(rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || - rt2x00_get_field32(word, TXD_ENTRY_VALID))) { - ERROR(entry->queue->rt2x00dev, + if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) { + ERROR(rt2x00dev, "Corrupt queue %d, accessing entry which is not ours.\n" "Please file bug report to %s.\n", entry->queue->qid, DRV_PROJECT); @@ -76,14 +73,12 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; - u32 word; while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); - if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) + if (rt2x00dev->ops->lib->get_entry_state(entry)) break; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index a83f45f..96a2082 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -44,17 +44,6 @@ #define REGISTER_BUSY_DELAY 100 /* - * Descriptor availability flags. - * All PCI device descriptors have these 2 flags - * with the exact same definition. - * By storing them here we can use them inside rt2x00pci - * for some simple entry availability checking. - */ -#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001) -#define TXD_ENTRY_VALID FIELD32(0x00000002) -#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001) - -/* * Register access. */ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e9f4261..7fc9c6e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -589,40 +589,18 @@ static void rt2x00queue_reset(struct data_queue *queue) spin_unlock_irqrestore(&queue->lock, irqflags); } -void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue = rt2x00dev->rx; - unsigned int i; - - rt2x00queue_reset(queue); - - if (!rt2x00dev->ops->lib->init_rxentry) - return; - - for (i = 0; i < queue->limit; i++) { - queue->entries[i].flags = 0; - - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, - &queue->entries[i]); - } -} - -void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) +void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; unsigned int i; - txall_queue_for_each(rt2x00dev, queue) { + queue_for_each(rt2x00dev, queue) { rt2x00queue_reset(queue); - if (!rt2x00dev->ops->lib->init_txentry) - continue; - for (i = 0; i < queue->limit; i++) { queue->entries[i].flags = 0; - rt2x00dev->ops->lib->init_txentry(rt2x00dev, - &queue->entries[i]); + rt2x00dev->ops->lib->clear_entry(&queue->entries[i]); } } } diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index b73a7e0..4eb550f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -351,28 +351,25 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); /* * Device initialization handlers. */ -void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +void rt2x00usb_clear_entry(struct queue_entry *entry) { - struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct usb_device *usb_dev = + to_usb_device_intf(entry->queue->rt2x00dev->dev); struct queue_entry_priv_usb *entry_priv = entry->priv_data; - usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_rcvbulkpipe(usb_dev, 1), - entry->skb->data, entry->skb->len, - rt2x00usb_interrupt_rxdone, entry); + if (entry->queue->qid == QID_RX) { + usb_fill_bulk_urb(entry_priv->urb, usb_dev, + usb_rcvbulkpipe(usb_dev, 1), + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); - set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); -} -EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); - -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) -{ - entry->flags = 0; + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + } else { + entry->flags = 0; + } } -EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); +EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 3b4a674..4104f0e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -286,10 +286,7 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * Device initialization handlers. */ -void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +void rt2x00usb_clear_entry(struct queue_entry *entry); int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3f27279..abfe33b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1261,33 +1261,44 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, /* * Initialization functions. */ -static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt61pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 5, &word); - rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 5, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt61pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 5, &word); + rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, + skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 5, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -2722,8 +2733,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .load_firmware = rt61pci_load_firmware, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt61pci_init_rxentry, - .init_txentry = rt61pci_init_txentry, + .get_entry_state = rt61pci_get_entry_state, + .clear_entry = rt61pci_clear_entry, .set_device_state = rt61pci_set_device_state, .rfkill_poll = rt61pci_rfkill_poll, .link_stats = rt61pci_link_stats, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 767e3c9..f2c8d97 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2313,8 +2313,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .load_firmware = rt73usb_load_firmware, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, - .init_rxentry = rt2x00usb_init_rxentry, - .init_txentry = rt2x00usb_init_txentry, + .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt73usb_set_device_state, .link_stats = rt73usb_link_stats, .reset_tuner = rt73usb_reset_tuner, -- cgit v1.1 From 87c1687d1a7bf0d4975d613cb699ba95b329359e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 9 Nov 2008 17:56:10 +0100 Subject: drivers/net/wireless/ath9k/rc.c: use ARRAY_SIZE ARRAY_SIZE is more concise to use when the size of an array is divided by the size of its type or the size of its first element. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @i@ @@ #include @depends on i using "paren.iso"@ type T; T[] E; @@ - (sizeof(E)/sizeof(E[...])) + ARRAY_SIZE(E) // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index aa6bfd7..517992d 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1272,8 +1272,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_ctrl->state[tx_rate].per = 100; } else { /* xretries == 2 */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ @@ -1291,8 +1290,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, } else { /* xretries == 0 */ /* Update the PER. */ /* Make sure it doesn't index out of array's bounds. */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; if (info_priv->n_bad_frames) { -- cgit v1.1 From bad13639a30e1557fbe9d440adc1906673c9de4e Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 9 Nov 2008 20:47:00 +0100 Subject: rt2x00: Optimize get_duration / get_duration_res We can optimize get_duration and get_duration_res by making them a macro. They are really simple calculation handlers so this doesn't matter much. Often (especially in rt2400pci and rt2500pci, the arguments are hardcoded, and the result value is passed into other hardcoded values. By making the functions a macro GCC can optimize the entire thing much better. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 10 +++++----- drivers/net/wireless/rt2x00/rt2500pci.c | 10 +++++----- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 31 ++++++++++++------------------ drivers/net/wireless/rt2x00/rt2x00config.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00queue.c | 4 ++-- 6 files changed, 27 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 861577e..9bda388 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -322,7 +322,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); @@ -367,25 +367,25 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e43ff9c..885844c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -327,7 +327,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min); @@ -373,25 +373,25 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3868e98..c40c9e7 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -385,7 +385,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4506f6c..baccea7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -92,6 +92,16 @@ DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args) /* + * Duration calculations + * The rate variable passed is: 100kbs. + * To convert from bytes to bits we multiply size with 8, + * then the size is multiplied with 10 to make the + * real rate -> rate argument correction. + */ +#define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate)) +#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) + +/* * Standard timing and size defines. * These values should follow the ieee80211 specifications. */ @@ -109,9 +119,9 @@ #define DIFS ( PIFS + SLOT_TIME ) #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) #define EIFS ( SIFS + DIFS + \ - (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ - (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) /* * Chipset identification @@ -920,23 +930,6 @@ static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset, !!(chipset->rev & 0x0000f)); } -/* - * Duration calculations - * The rate variable passed is: 100kbs. - * To convert from bytes to bits we multiply size with 8, - * then the size is multiplied with 10 to make the - * real rate -> rate argument correction. - */ -static inline u16 get_duration(const unsigned int size, const u8 rate) -{ - return ((size * 8 * 10) / rate); -} - -static inline u16 get_duration_res(const unsigned int size, const u8 rate) -{ - return ((size * 8 * 10) % rate); -} - /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. * @rt2x00dev: Pointer to &struct rt2x00_dev. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 1059b4d..7c62ce1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -92,8 +92,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - erp.ack_timeout = PLCP + erp.difs + get_duration(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); + erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); + erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); if (bss_conf->use_short_preamble) { erp.ack_timeout += SHORT_PREAMBLE; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7fc9c6e..d7752db 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -319,8 +319,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Convert length to microseconds. */ - residual = get_duration_res(data_length, hwrate->bitrate); - duration = get_duration(data_length, hwrate->bitrate); + residual = GET_DURATION_RES(data_length, hwrate->bitrate); + duration = GET_DURATION(data_length, hwrate->bitrate); if (residual != 0) { duration++; -- cgit v1.1 From 8ff48a8bbe4a1ba29dea2836dfce74660f97c1be Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 9 Nov 2008 23:40:46 +0100 Subject: rt2x00: Fix race condition when using inderect registers Indirect registers require multiple calls to the CSR register in order to access the indirect registers. This must be protected under a lock to prevent race conditions which could cause invalid data to be returned when reading from the indirect register or silent failures when writing data to the indirect register. USB drivers where already protected under a mutex, so rename the mutex and make PCI drivers use the mutex as well. This now means that BBP and RF registers are no longer accessible in interrupt context. That is not a bad situation since the slow behavior of accessing those registers means we don't _want_ to access them in interrupt context either. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 47 ++++++++++++++++------- drivers/net/wireless/rt2x00/rt2500pci.c | 47 ++++++++++++++++------- drivers/net/wireless/rt2x00/rt2500usb.c | 20 +++++----- drivers/net/wireless/rt2x00/rt2x00.h | 19 +++++----- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 + drivers/net/wireless/rt2x00/rt2x00usb.c | 11 +++--- drivers/net/wireless/rt2x00/rt61pci.c | 66 +++++++++++++++++++++++---------- drivers/net/wireless/rt2x00/rt73usb.c | 21 ++++++----- 8 files changed, 152 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 9bda388..78fca1bc 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -69,14 +69,14 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); - return; - } + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) + goto exit_fail; /* * Write the data into the BBP. @@ -88,6 +88,15 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); } static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,14 +104,14 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - return; - } + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) + goto exit_fail; /* * Write the request into the BBP. @@ -118,13 +127,20 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, * Wait until the BBP becomes ready. */ reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; - } + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) + goto exit_fail; *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + *value = 0xff; } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -136,6 +152,8 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, if (!word) return; + mutex_lock(&rt2x00dev->csr_mutex); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_register_read(rt2x00dev, RFCSR, ®); if (!rt2x00_get_field32(reg, RFCSR_BUSY)) @@ -143,6 +161,7 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, udelay(REGISTER_BUSY_DELAY); } + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); return; @@ -155,6 +174,8 @@ rf_write: rt2x00pci_register_write(rt2x00dev, RFCSR, reg); rt2x00_rf_write(rt2x00dev, word, value); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 885844c..972b5a5 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -69,14 +69,14 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); - return; - } + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) + goto exit_fail; /* * Write the data into the BBP. @@ -88,6 +88,15 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); } static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,14 +104,14 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - return; - } + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) + goto exit_fail; /* * Write the request into the BBP. @@ -118,13 +127,20 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, * Wait until the BBP becomes ready. */ reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; - } + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) + goto exit_fail; *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + *value = 0xff; } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -136,6 +152,8 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, if (!word) return; + mutex_lock(&rt2x00dev->csr_mutex); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_register_read(rt2x00dev, RFCSR, ®); if (!rt2x00_get_field32(reg, RFCSR_BUSY)) @@ -143,6 +161,7 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, udelay(REGISTER_BUSY_DELAY); } + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); return; @@ -155,6 +174,8 @@ rf_write: rt2x00pci_register_write(rt2x00dev, RFCSR, reg); rt2x00_rf_write(rt2x00dev, word, value); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c40c9e7..e6bae4a 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -47,7 +47,7 @@ * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. - * If the usb_cache_mutex is already held then the _lock variants must + * If the csr_mutex is already held then the _lock variants must * be used instead. */ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, @@ -132,7 +132,7 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the BBP becomes ready. @@ -151,12 +151,12 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return; exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); } @@ -166,7 +166,7 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the BBP becomes ready. @@ -194,12 +194,12 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return; exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); *value = 0xff; @@ -214,7 +214,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, if (!word) return; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®); @@ -223,7 +223,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, udelay(REGISTER_BUSY_DELAY); } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); return; @@ -241,7 +241,7 @@ rf_write: rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); rt2x00_rf_write(rt2x00dev, word, value); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index baccea7..fee61be 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -746,16 +746,15 @@ struct rt2x00_dev { } csr; /* - * Mutex to protect register accesses on USB devices. - * There are 2 reasons this is needed, one is to ensure - * use of the csr_cache (for USB devices) by one thread - * isn't corrupted by another thread trying to access it. - * The other is that access to BBP and RF registers - * require multiple BUS transactions and if another thread - * attempted to access one of those registers at the same - * time one of the writes could silently fail. - */ - struct mutex usb_cache_mutex; + * Mutex to protect register accesses. + * For PCI and USB devices it protects against concurrent indirect + * register access (BBP, RF, MCU) since accessing those + * registers require multiple calls to the CSR registers. + * For USB devices it also protects the csr_cache since that + * field is used for normal CSR access and it cannot support + * multiple callers simultaneously. + */ + struct mutex csr_mutex; /* * Current packet filter configuration for the device. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index bb510a2..7fc1d76 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1051,6 +1051,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { int retval = -ENOMEM; + mutex_init(&rt2x00dev->csr_mutex); + /* * Make room for rt2x00_intf inside the per-interface * structure ieee80211_vif. diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 4eb550f..c507b0d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -79,7 +79,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, { int status; - BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex)); + BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex)); /* * Check for Cache availability. @@ -110,13 +110,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, { int status; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, requesttype, offset, buffer, buffer_length, timeout); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return status; } @@ -132,7 +132,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, unsigned char *tb; u16 off, len, bsize; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); tb = (char *)buffer; off = offset; @@ -148,7 +148,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, off += bsize; } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return status; } @@ -531,7 +531,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00dev->dev = &usb_intf->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; - mutex_init(&rt2x00dev->usb_cache_mutex); rt2x00dev->usb_maxpacket = usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index abfe33b..89ac34f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -75,14 +75,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); - return; - } + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + goto exit_fail; /* * Write the data into the BBP. @@ -94,6 +94,14 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); } static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -101,14 +109,14 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - return; - } + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + goto exit_fail; /* * Write the request into the BBP. @@ -124,13 +132,19 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, * Wait until the BBP becomes ready. */ reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; - return; - } + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + goto exit_fail; *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + *value = 0xff; } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -142,6 +156,8 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, if (!word) return; + mutex_lock(&rt2x00dev->csr_mutex); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) @@ -149,6 +165,7 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, udelay(REGISTER_BUSY_DELAY); } + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); return; @@ -161,6 +178,8 @@ rf_write: rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); rt2x00_rf_write(rt2x00dev, word, value); + + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_LEDS @@ -175,14 +194,12 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, { u32 reg; + mutex_lock(&rt2x00dev->csr_mutex); + rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); - if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) { - ERROR(rt2x00dev, "mcu request error. " - "Request 0x%02x failed for token 0x%02x.\n", - command, token); - return; - } + if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) + goto exit_fail; rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); @@ -194,6 +211,17 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); + + mutex_unlock(&rt2x00dev->csr_mutex); + + return; + +exit_fail: + mutex_unlock(&rt2x00dev->csr_mutex); + + ERROR(rt2x00dev, + "mcu request error. Request 0x%02x failed for token 0x%02x.\n", + command, token); } #endif /* CONFIG_RT2X00_LIB_LEDS */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index f2c8d97..d1a63e00 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -55,7 +55,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. - * The _lock versions must be used if you already hold the usb_cache_mutex + * The _lock versions must be used if you already hold the csr_mutex */ static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value) @@ -135,7 +135,7 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the BBP becomes ready. @@ -154,12 +154,12 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return; exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); } @@ -169,7 +169,7 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the BBP becomes ready. @@ -196,12 +196,12 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, goto exit_fail; *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return; exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); *value = 0xff; @@ -216,7 +216,7 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, if (!word) return; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, ®); @@ -225,7 +225,7 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, udelay(REGISTER_BUSY_DELAY); } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); return; @@ -245,7 +245,8 @@ rf_write: rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); rt2x00_rf_write(rt2x00dev, word, value); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -- cgit v1.1 From dfe1bafdbac1c7b48b636fb7ace799e78170e0d6 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 10 Nov 2008 09:25:53 -0500 Subject: orinoco: fix last beacon reporting on 64-bit systems orinoco_translate_scan() and orinoco_translate_ext_scan() wrongly truncate last_scanned argument from unsigned long to unsigned int. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index 072be44..fd92639 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -5444,7 +5444,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev, char *current_ev, char *end_buf, union hermes_scan_info *bss, - unsigned int last_scanned) + unsigned long last_scanned) { struct orinoco_private *priv = netdev_priv(dev); u16 capabilities; @@ -5591,7 +5591,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, char *current_ev, char *end_buf, struct agere_ext_scan_info *bss, - unsigned int last_scanned) + unsigned long last_scanned) { u16 capabilities; u16 channel; -- cgit v1.1 From 274bfb8dc5ffa16cb073801bebe76ab7f4e2e73d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 29 Oct 2008 11:35:05 -0400 Subject: lib80211: absorb crypto bits from net/ieee80211 These bits are shared already between ipw2x00 and hostap, and could probably be shared both more cleanly and with other drivers. This commit simply relocates the code to lib80211 and adjusts the drivers appropriately. Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/Kconfig | 6 +- drivers/net/wireless/hostap/hostap.h | 2 +- drivers/net/wireless/hostap/hostap_80211.h | 2 +- drivers/net/wireless/hostap/hostap_80211_rx.c | 10 +-- drivers/net/wireless/hostap/hostap_80211_tx.c | 8 +- drivers/net/wireless/hostap/hostap_ap.c | 12 +-- drivers/net/wireless/hostap/hostap_ap.h | 8 +- drivers/net/wireless/hostap/hostap_hw.c | 36 +++++---- drivers/net/wireless/hostap/hostap_ioctl.c | 110 +++++++++++++------------- drivers/net/wireless/hostap/hostap_main.c | 19 ++--- drivers/net/wireless/hostap/hostap_proc.c | 20 ++--- drivers/net/wireless/hostap/hostap_wlan.h | 6 +- drivers/net/wireless/ipw2100.c | 12 +-- drivers/net/wireless/ipw2200.c | 12 +-- 14 files changed, 136 insertions(+), 127 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 1fef331..87bbd4d 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,8 +2,10 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" depends on WLAN_80211 select WIRELESS_EXT - select IEEE80211 - select IEEE80211_CRYPT_WEP + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_TKIP + select LIB80211_CRYPT_CCMP ---help--- Shared driver code for IEEE 802.11b wireless cards based on Intersil Prism2/2.5/3 chipset. This driver supports so called diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 3a386a6..2453dea 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -63,7 +63,7 @@ void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); void ap_control_kickall(struct ap_data *ap); void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt); + struct lib80211_crypt_data ***crypt); int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], struct iw_quality qual[], int buf_size, int aplist); diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 3694b1e..3a9474d 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -2,7 +2,7 @@ #define HOSTAP_80211_H #include -#include +#include struct hostap_ieee80211_mgmt { __le16 frame_control; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 5f64461..19b1bf0 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,5 +1,5 @@ #include -#include +#include #include "hostap_80211.h" #include "hostap.h" @@ -649,7 +649,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) /* Called only as a tasklet (software IRQ) */ static int hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; @@ -687,7 +687,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, /* Called only as a tasklet (software IRQ) */ static int hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, - int keyidx, struct ieee80211_crypt_data *crypt) + int keyidx, struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; @@ -733,7 +733,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, int from_assoc_ap = 0; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; void *sta = NULL; int keyidx = 0; @@ -785,7 +785,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt[idx]; + crypt = local->crypt_info.crypt[idx]; sta = NULL; /* Use station specific key to override default keys if the diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 0752471..078a010 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -306,7 +306,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Called only from software IRQ */ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct hostap_interface *iface; local_info_t *local; @@ -405,7 +405,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (local->host_encrypt) { /* Set crypt to default algorithm and key; will be replaced in * AP code if STA has own alg/key */ - tx.crypt = local->crypt[local->tx_keyidx]; + tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; tx.host_encrypt = 1; } else { tx.crypt = NULL; @@ -487,7 +487,9 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) tx.crypt = NULL; - else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) { + else if ((tx.crypt || + local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && + !no_encrypt) { /* Add ISWEP flag both for firmware and host based encryption */ fc |= IEEE80211_FCTL_PROTECTED; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index dec3dbe..0903db7 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -1206,7 +1206,7 @@ static void prism2_check_tx_rates(struct sta_info *sta) static void ap_crypt_init(struct ap_data *ap) { - ap->crypt = ieee80211_get_crypto_ops("WEP"); + ap->crypt = lib80211_get_crypto_ops("WEP"); if (ap->crypt) { if (ap->crypt->init) { @@ -1224,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap) if (ap->crypt == NULL) { printk(KERN_WARNING "AP could not initialize WEP: load module " - "ieee80211_crypt_wep.ko\n"); + "lib80211_crypt_wep.ko\n"); } } @@ -1293,7 +1293,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, __le16 *pos; u16 resp = WLAN_STATUS_SUCCESS, fc; struct sta_info *sta = NULL; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; char *txt = ""; len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1319,7 +1319,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt[idx]; + crypt = local->crypt_info.crypt[idx]; } pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); @@ -3065,7 +3065,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, /* Called only as a tasklet (software IRQ) */ int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, - struct ieee80211_crypt_data **crypt, + struct lib80211_crypt_data **crypt, void **sta_ptr) { struct sta_info *sta; @@ -3213,7 +3213,7 @@ void hostap_update_rates(local_info_t *local) void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt) + struct lib80211_crypt_data ***crypt) { struct sta_info *sta; diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 2fa2452..d36e4b1 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -74,7 +74,7 @@ struct sta_info { u32 tx_since_last_failure; u32 tx_consecutive_exc; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int ap; /* whether this station is an AP */ @@ -209,7 +209,7 @@ struct ap_data { /* WEP operations for generating challenges to be used with shared key * authentication */ - struct ieee80211_crypto_ops *crypt; + struct lib80211_crypto_ops *crypt; void *crypt_priv; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ }; @@ -229,7 +229,7 @@ typedef enum { struct hostap_tx_data { struct sk_buff *skb; int host_encrypt; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; void *sta_ptr; }; ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); @@ -244,7 +244,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct hostap_80211_rx_status *rx_stats, int wds); int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, - struct ieee80211_crypt_data **crypt, + struct lib80211_crypt_data **crypt, void **sta_ptr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index fd7f7ce..066299f 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include "hostap_80211.h" @@ -2791,11 +2791,12 @@ static void prism2_check_sta_fw_version(local_info_t *local) static void prism2_crypt_deinit_entries(local_info_t *local, int force) { struct list_head *ptr, *n; - struct ieee80211_crypt_data *entry; + struct lib80211_crypt_data *entry; - for (ptr = local->crypt_deinit_list.next, n = ptr->next; - ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct ieee80211_crypt_data, list); + for (ptr = local->crypt_info.crypt_deinit_list.next, n = ptr->next; + ptr != &local->crypt_info.crypt_deinit_list; + ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct lib80211_crypt_data, list); if (atomic_read(&entry->refcnt) != 0 && !force) continue; @@ -2816,11 +2817,11 @@ static void prism2_crypt_deinit_handler(unsigned long data) spin_lock_irqsave(&local->lock, flags); prism2_crypt_deinit_entries(local, 0); - if (!list_empty(&local->crypt_deinit_list)) { + if (!list_empty(&local->crypt_info.crypt_deinit_list)) { printk(KERN_DEBUG "%s: entries remaining in delayed crypt " "deletion list\n", local->dev->name); - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_deinit_timer); + local->crypt_info.crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&local->crypt_info.crypt_deinit_timer); } spin_unlock_irqrestore(&local->lock, flags); @@ -3250,10 +3251,13 @@ while (0) INIT_LIST_HEAD(&local->cmd_queue); init_waitqueue_head(&local->hostscan_wq); - INIT_LIST_HEAD(&local->crypt_deinit_list); - init_timer(&local->crypt_deinit_timer); - local->crypt_deinit_timer.data = (unsigned long) local; - local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; + + local->crypt_info.name = dev->name; + local->crypt_info.lock = &local->lock; + INIT_LIST_HEAD(&local->crypt_info.crypt_deinit_list); + init_timer(&local->crypt_info.crypt_deinit_timer); + local->crypt_info.crypt_deinit_timer.data = (unsigned long) local; + local->crypt_info.crypt_deinit_timer.function = prism2_crypt_deinit_handler; init_timer(&local->passive_scan_timer); local->passive_scan_timer.data = (unsigned long) local; @@ -3354,8 +3358,8 @@ static void prism2_free_local_data(struct net_device *dev) flush_scheduled_work(); - if (timer_pending(&local->crypt_deinit_timer)) - del_timer(&local->crypt_deinit_timer); + if (timer_pending(&local->crypt_info.crypt_deinit_timer)) + del_timer(&local->crypt_info.crypt_deinit_timer); prism2_crypt_deinit_entries(local, 1); if (timer_pending(&local->passive_scan_timer)) @@ -3374,12 +3378,12 @@ static void prism2_free_local_data(struct net_device *dev) prism2_callback(local, PRISM2_CALLBACK_DISABLE); for (i = 0; i < WEP_KEYS; i++) { - struct ieee80211_crypt_data *crypt = local->crypt[i]; + struct lib80211_crypt_data *crypt = local->crypt_info.crypt[i]; if (crypt) { if (crypt->ops) crypt->ops->deinit(crypt->priv); kfree(crypt); - local->crypt[i] = NULL; + local->crypt_info.crypt[i] = NULL; } } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 2318c5d..29aebb6 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "hostap_wlan.h" #include "hostap.h" @@ -117,9 +117,9 @@ static int prism2_get_name(struct net_device *dev, static void prism2_crypt_delayed_deinit(local_info_t *local, - struct ieee80211_crypt_data **crypt) + struct lib80211_crypt_data **crypt) { - struct ieee80211_crypt_data *tmp; + struct lib80211_crypt_data *tmp; unsigned long flags; tmp = *crypt; @@ -133,10 +133,10 @@ static void prism2_crypt_delayed_deinit(local_info_t *local, * locking. */ spin_lock_irqsave(&local->lock, flags); - list_add(&tmp->list, &local->crypt_deinit_list); - if (!timer_pending(&local->crypt_deinit_timer)) { - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_deinit_timer); + list_add(&tmp->list, &local->crypt_info.crypt_deinit_list); + if (!timer_pending(&local->crypt_info.crypt_deinit_timer)) { + local->crypt_info.crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&local->crypt_info.crypt_deinit_timer); } spin_unlock_irqrestore(&local->lock, flags); } @@ -149,20 +149,20 @@ static int prism2_ioctl_siwencode(struct net_device *dev, struct hostap_interface *iface; local_info_t *local; int i; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; iface = netdev_priv(dev); local = iface->local; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; if (erq->flags & IW_ENCODE_DISABLED) { if (*crypt) @@ -177,17 +177,17 @@ static int prism2_ioctl_siwencode(struct net_device *dev, } if (*crypt == NULL) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("ieee80211_crypt_wep"); - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + request_module("lib80211_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); } if (new_crypt->ops) new_crypt->priv = new_crypt->ops->init(i); @@ -210,16 +210,16 @@ static int prism2_ioctl_siwencode(struct net_device *dev, memset(keybuf + erq->length, 0, len - erq->length); (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt[j]) { + if (j != i && local->crypt_info.crypt[j]) { first = 0; break; } } if (first) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } else { /* No key data - just set the default TX key index */ - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } done: @@ -252,20 +252,20 @@ static int prism2_ioctl_giwencode(struct net_device *dev, local_info_t *local; int i, len; u16 val; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; iface = netdev_priv(dev); local = iface->local; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; - crypt = local->crypt[i]; + crypt = local->crypt_info.crypt[i]; erq->flags = i + 1; if (crypt == NULL || crypt->ops == NULL) { @@ -3227,8 +3227,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, local_info_t *local = iface->local; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; int i, ret = 0; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; void *sta_ptr; u8 *addr; const char *alg, *module; @@ -3237,7 +3237,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (i > WEP_KEYS) return -EINVAL; if (i < 1 || i > WEP_KEYS) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) @@ -3247,7 +3247,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { sta_ptr = NULL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else { if (i != 0) return -EINVAL; @@ -3260,7 +3260,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, * is emulated by using default key idx 0. */ i = 0; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else return -EINVAL; } @@ -3276,15 +3276,15 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "ieee80211_crypt_wep"; + module = "lib80211_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "ieee80211_crypt_tkip"; + module = "lib80211_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "ieee80211_crypt_ccmp"; + module = "lib80211_crypt_ccmp"; break; default: printk(KERN_DEBUG "%s: unsupported algorithm %d\n", @@ -3293,10 +3293,10 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, goto done; } - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", @@ -3315,11 +3315,11 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; prism2_crypt_delayed_deinit(local, crypt); - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; @@ -3354,20 +3354,20 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { if (!sta_ptr) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } if (sta_ptr == NULL && ext->key_len > 0) { int first = 1, j; for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt[j]) { + if (j != i && local->crypt_info.crypt[j]) { first = 0; break; } } if (first) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } done: @@ -3399,7 +3399,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, { struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; void *sta_ptr; int max_key_len, i; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; @@ -3411,7 +3411,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > WEP_KEYS) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; @@ -3419,7 +3419,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { sta_ptr = NULL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else { i = 0; sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); @@ -3468,8 +3468,8 @@ static int prism2_ioctl_set_encryption(local_info_t *local, int param_len) { int ret = 0; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; void *sta_ptr; param->u.crypt.err = 0; @@ -3486,7 +3486,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (param->u.crypt.idx >= WEP_KEYS) return -EINVAL; sta_ptr = NULL; - crypt = &local->crypt[param->u.crypt.idx]; + crypt = &local->crypt_info.crypt[param->u.crypt.idx]; } else { if (param->u.crypt.idx) return -EINVAL; @@ -3507,16 +3507,16 @@ static int prism2_ioctl_set_encryption(local_info_t *local, goto done; } - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("ieee80211_crypt_wep"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_wep"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("ieee80211_crypt_tkip"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_tkip"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("ieee80211_crypt_ccmp"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_ccmp"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } if (ops == NULL) { printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", @@ -3531,11 +3531,11 @@ static int prism2_ioctl_set_encryption(local_info_t *local, local->host_decrypt = local->host_encrypt = 1; if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; prism2_crypt_delayed_deinit(local, crypt); - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; @@ -3568,7 +3568,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { if (!sta_ptr) - local->tx_keyidx = param->u.crypt.idx; + local->crypt_info.tx_keyidx = param->u.crypt.idx; else if (param->u.crypt.idx) { printk(KERN_DEBUG "%s: TX key idx setting failed\n", local->dev->name); @@ -3604,7 +3604,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; void *sta_ptr; int max_key_len; @@ -3620,8 +3620,8 @@ static int prism2_ioctl_get_encryption(local_info_t *local, param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { sta_ptr = NULL; if (param->u.crypt.idx >= WEP_KEYS) - param->u.crypt.idx = local->tx_keyidx; - crypt = &local->crypt[param->u.crypt.idx]; + param->u.crypt.idx = local->crypt_info.tx_keyidx; + crypt = &local->crypt_info.crypt[param->u.crypt.idx]; } else { param->u.crypt.idx = 0; sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 4c36eb2..02a312c 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include "hostap_wlan.h" @@ -343,10 +343,11 @@ int hostap_set_encryption(local_info_t *local) char keybuf[WEP_KEY_LEN + 1]; enum { NONE, WEP, OTHER } encrypt_type; - idx = local->tx_keyidx; - if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL) + idx = local->crypt_info.tx_keyidx; + if (local->crypt_info.crypt[idx] == NULL || + local->crypt_info.crypt[idx]->ops == NULL) encrypt_type = NONE; - else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0) + else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0) encrypt_type = WEP; else encrypt_type = OTHER; @@ -394,17 +395,17 @@ int hostap_set_encryption(local_info_t *local) /* 104-bit support seems to require that all the keys are set to the * same keylen */ keylen = 6; /* first 5 octets */ - len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), - NULL, local->crypt[idx]->priv); + len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL, + local->crypt_info.crypt[idx]->priv); if (idx >= 0 && idx < WEP_KEYS && len > 5) keylen = WEP_KEY_LEN + 1; /* first 13 octets */ for (i = 0; i < WEP_KEYS; i++) { memset(keybuf, 0, sizeof(keybuf)); - if (local->crypt[i]) { - (void) local->crypt[i]->ops->get_key( + if (local->crypt_info.crypt[i]) { + (void) local->crypt_info.crypt[i]->ops->get_key( keybuf, sizeof(keybuf), - NULL, local->crypt[i]->priv); + NULL, local->crypt_info.crypt[i]->priv); } if (local->func->set_rid(local->dev, HFA384X_RID_CNFDEFAULTKEY0 + i, diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index ae7d3ca..005ff25 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "hostap_wlan.h" #include "hostap.h" @@ -36,9 +36,10 @@ static int prism2_debug_proc_read(char *page, char **start, off_t off, p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt[i] && local->crypt[i]->ops) { - p += sprintf(p, "crypt[%d]=%s\n", - i, local->crypt[i]->ops->name); + if (local->crypt_info.crypt[i] && + local->crypt_info.crypt[i]->ops) { + p += sprintf(p, "crypt[%d]=%s\n", i, + local->crypt_info.crypt[i]->ops->name); } } p += sprintf(p, "pri_only=%d\n", local->pri_only); @@ -206,12 +207,13 @@ static int prism2_crypt_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx); + p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt[i] && local->crypt[i]->ops && - local->crypt[i]->ops->print_stats) { - p = local->crypt[i]->ops->print_stats( - p, local->crypt[i]->priv); + if (local->crypt_info.crypt[i] && + local->crypt_info.crypt[i]->ops && + local->crypt_info.crypt[i]->ops->print_stats) { + p = local->crypt_info.crypt[i]->ops->print_stats( + p, local->crypt_info.crypt[i]->priv); } } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index d2c7a56..4d8d51a3 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "hostap_config.h" #include "hostap_common.h" @@ -763,10 +764,7 @@ struct local_info { #define WEP_KEYS 4 #define WEP_KEY_LEN 13 - struct ieee80211_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ - struct timer_list crypt_deinit_timer; - struct list_head crypt_deinit_list; + struct lib80211_crypt_info crypt_info; int open_wep; /* allow unencrypted frames */ int host_encrypt; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 062c9f2..2d2044d 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -4010,7 +4010,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, else len += sprintf(buf + len, "not connected\n"); - DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p"); + DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p"); DUMP_VAR(status, "08lx"); DUMP_VAR(config, "08lx"); DUMP_VAR(capability, "08lx"); @@ -5514,7 +5514,7 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) } } - ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1); + ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1); } /* Always enable privacy so the Host can filter WEP packets if @@ -7620,7 +7620,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -7635,7 +7635,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; @@ -7712,7 +7712,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, { struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -7728,7 +7728,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->get_flags) { IPW_DEBUG_WARNING("Can't get TKIP countermeasures: " "crypt not set!\n"); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 6ca0f1c..d2a2b75 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6600,7 +6600,7 @@ static int ipw_wx_set_auth(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -6622,7 +6622,7 @@ static int ipw_wx_set_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; @@ -6699,7 +6699,7 @@ static int ipw_wx_get_auth(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -6715,7 +6715,7 @@ static int ipw_wx_get_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->get_flags) break; @@ -10251,8 +10251,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, case SEC_LEVEL_1: tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - tfd->u.data.key_index = priv->ieee->tx_keyidx; - if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <= + tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx; + if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <= 40) tfd->u.data.key_index |= DCT_WEP_KEY_64Bit; else -- cgit v1.1 From 2ba4b32ecf748d5f45f298fc9677fa46d1dd9aff Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 11 Nov 2008 16:00:06 -0500 Subject: lib80211: consolidate crypt init routines Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_hw.c | 61 +----------------------------- drivers/net/wireless/hostap/hostap_ioctl.c | 43 +++++---------------- 2 files changed, 11 insertions(+), 93 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 066299f..0f27059 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2788,46 +2788,6 @@ static void prism2_check_sta_fw_version(local_info_t *local) } -static void prism2_crypt_deinit_entries(local_info_t *local, int force) -{ - struct list_head *ptr, *n; - struct lib80211_crypt_data *entry; - - for (ptr = local->crypt_info.crypt_deinit_list.next, n = ptr->next; - ptr != &local->crypt_info.crypt_deinit_list; - ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct lib80211_crypt_data, list); - - if (atomic_read(&entry->refcnt) != 0 && !force) - continue; - - list_del(ptr); - - if (entry->ops) - entry->ops->deinit(entry->priv); - kfree(entry); - } -} - - -static void prism2_crypt_deinit_handler(unsigned long data) -{ - local_info_t *local = (local_info_t *) data; - unsigned long flags; - - spin_lock_irqsave(&local->lock, flags); - prism2_crypt_deinit_entries(local, 0); - if (!list_empty(&local->crypt_info.crypt_deinit_list)) { - printk(KERN_DEBUG "%s: entries remaining in delayed crypt " - "deletion list\n", local->dev->name); - local->crypt_info.crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_info.crypt_deinit_timer); - } - spin_unlock_irqrestore(&local->lock, flags); - -} - - static void hostap_passive_scan(unsigned long data) { local_info_t *local = (local_info_t *) data; @@ -3252,12 +3212,7 @@ while (0) INIT_LIST_HEAD(&local->cmd_queue); init_waitqueue_head(&local->hostscan_wq); - local->crypt_info.name = dev->name; - local->crypt_info.lock = &local->lock; - INIT_LIST_HEAD(&local->crypt_info.crypt_deinit_list); - init_timer(&local->crypt_info.crypt_deinit_timer); - local->crypt_info.crypt_deinit_timer.data = (unsigned long) local; - local->crypt_info.crypt_deinit_timer.function = prism2_crypt_deinit_handler; + lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock); init_timer(&local->passive_scan_timer); local->passive_scan_timer.data = (unsigned long) local; @@ -3358,9 +3313,7 @@ static void prism2_free_local_data(struct net_device *dev) flush_scheduled_work(); - if (timer_pending(&local->crypt_info.crypt_deinit_timer)) - del_timer(&local->crypt_info.crypt_deinit_timer); - prism2_crypt_deinit_entries(local, 1); + lib80211_crypt_info_free(&local->crypt_info); if (timer_pending(&local->passive_scan_timer)) del_timer(&local->passive_scan_timer); @@ -3377,16 +3330,6 @@ static void prism2_free_local_data(struct net_device *dev) if (local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_DISABLE); - for (i = 0; i < WEP_KEYS; i++) { - struct lib80211_crypt_data *crypt = local->crypt_info.crypt[i]; - if (crypt) { - if (crypt->ops) - crypt->ops->deinit(crypt->priv); - kfree(crypt); - local->crypt_info.crypt[i] = NULL; - } - } - if (local->ap != NULL) hostap_free_data(local->ap); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 29aebb6..c40fdf4 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -116,32 +116,6 @@ static int prism2_get_name(struct net_device *dev, } -static void prism2_crypt_delayed_deinit(local_info_t *local, - struct lib80211_crypt_data **crypt) -{ - struct lib80211_crypt_data *tmp; - unsigned long flags; - - tmp = *crypt; - *crypt = NULL; - - if (tmp == NULL) - return; - - /* must not run ops->deinit() while there may be pending encrypt or - * decrypt operations. Use a list of delayed deinits to avoid needing - * locking. */ - - spin_lock_irqsave(&local->lock, flags); - list_add(&tmp->list, &local->crypt_info.crypt_deinit_list); - if (!timer_pending(&local->crypt_info.crypt_deinit_timer)) { - local->crypt_info.crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_info.crypt_deinit_timer); - } - spin_unlock_irqrestore(&local->lock, flags); -} - - static int prism2_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) @@ -166,14 +140,14 @@ static int prism2_ioctl_siwencode(struct net_device *dev, if (erq->flags & IW_ENCODE_DISABLED) { if (*crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } if (*crypt != NULL && (*crypt)->ops != NULL && strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm */ - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); } if (*crypt == NULL) { @@ -189,7 +163,7 @@ static int prism2_ioctl_siwencode(struct net_device *dev, request_module("lib80211_crypt_wep"); new_crypt->ops = lib80211_get_crypto_ops("WEP"); } - if (new_crypt->ops) + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) new_crypt->priv = new_crypt->ops->init(i); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); @@ -3269,7 +3243,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if ((erq->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } @@ -3317,7 +3291,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (*crypt == NULL || (*crypt)->ops != ops) { struct lib80211_crypt_data *new_crypt; - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); @@ -3326,7 +3300,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, goto done; } new_crypt->ops = ops; - new_crypt->priv = new_crypt->ops->init(i); + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(i); if (new_crypt->priv == NULL) { kfree(new_crypt); ret = -EINVAL; @@ -3503,7 +3478,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } @@ -3533,7 +3508,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (*crypt == NULL || (*crypt)->ops != ops) { struct lib80211_crypt_data *new_crypt; - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); -- cgit v1.1 From 0795cd29b6fe05107b40080cb1fccadb96320c96 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 11 Nov 2008 16:22:09 -0500 Subject: ipw2x00: relocate ipw2100/ipw2200 to common directory Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 147 +- drivers/net/wireless/Makefile | 5 +- drivers/net/wireless/ipw2100.c | 8649 ---------------------- drivers/net/wireless/ipw2100.h | 1162 --- drivers/net/wireless/ipw2200.c | 11984 ------------------------------- drivers/net/wireless/ipw2200.h | 2011 ------ drivers/net/wireless/ipw2x00/Kconfig | 150 + drivers/net/wireless/ipw2x00/Makefile | 6 + drivers/net/wireless/ipw2x00/ipw2100.c | 8649 ++++++++++++++++++++++ drivers/net/wireless/ipw2x00/ipw2100.h | 1162 +++ drivers/net/wireless/ipw2x00/ipw2200.c | 11984 +++++++++++++++++++++++++++++++ drivers/net/wireless/ipw2x00/ipw2200.h | 2011 ++++++ 12 files changed, 23965 insertions(+), 23955 deletions(-) delete mode 100644 drivers/net/wireless/ipw2100.c delete mode 100644 drivers/net/wireless/ipw2100.h delete mode 100644 drivers/net/wireless/ipw2200.c delete mode 100644 drivers/net/wireless/ipw2200.h create mode 100644 drivers/net/wireless/ipw2x00/Kconfig create mode 100644 drivers/net/wireless/ipw2x00/Makefile create mode 100644 drivers/net/wireless/ipw2x00/ipw2100.c create mode 100644 drivers/net/wireless/ipw2x00/ipw2100.h create mode 100644 drivers/net/wireless/ipw2x00/ipw2200.c create mode 100644 drivers/net/wireless/ipw2x00/ipw2200.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 35dbc89..84b49c8 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -123,152 +123,6 @@ config PCMCIA_RAYCS To compile this driver as a module, choose M here: the module will be called ray_cs. If unsure, say N. -config IPW2100 - tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select LIB80211 - select IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2100 Network - Connection 802.11b wireless network adapter. - - See for information on - the capabilities currently enabled in this driver and for tips - for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . Once you have the firmware image, you - will need to place it in /lib/firmware. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - It is recommended that you compile this driver as a module (M) - rather than built-in (Y). This driver requires firmware at device - initialization time, and when built-in this typically happens - before the filesystem is accessible (hence firmware will be - unavailable and initialization will fail). If you do choose to build - this driver into your kernel image, you can avoid this problem by - including the firmware and a firmware loader in an initramfs. - -config IPW2100_MONITOR - bool "Enable promiscuous mode" - depends on IPW2100 - ---help--- - Enables promiscuous/monitor mode support for the ipw2100 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2100_DEBUG - bool "Enable full debugging output in IPW2100 module." - depends on IPW2100 - ---help--- - This option will enable debug tracing output for the IPW2100. - - This will result in the kernel module being ~60k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/bus/pci/drivers/ipw2100/debug_level - - This entry will only exist if this option is enabled. - - If you are not trying to debug or develop the IPW2100 driver, you - most likely want to say N here. - -config IPW2200 - tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select LIB80211 - select IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network - Connection adapters. - - See for - information on the capabilities currently enabled in this - driver and for tips for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . See the above referenced README.ipw2200 - for information on where to install the firmware images. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - It is recommended that you compile this driver as a module (M) - rather than built-in (Y). This driver requires firmware at device - initialization time, and when built-in this typically happens - before the filesystem is accessible (hence firmware will be - unavailable and initialization will fail). If you do choose to build - this driver into your kernel image, you can avoid this problem by - including the firmware and a firmware loader in an initramfs. - -config IPW2200_MONITOR - bool "Enable promiscuous mode" - depends on IPW2200 - ---help--- - Enables promiscuous/monitor mode support for the ipw2200 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2200_RADIOTAP - bool "Enable radiotap format 802.11 raw packet support" - depends on IPW2200_MONITOR - -config IPW2200_PROMISCUOUS - bool "Enable creation of a RF radiotap promiscuous interface" - depends on IPW2200_MONITOR - select IPW2200_RADIOTAP - ---help--- - Enables the creation of a second interface prefixed 'rtap'. - This second interface will provide every received in radiotap - format. - - This is useful for performing wireless network analysis while - maintaining an active association. - - Example usage: - - % modprobe ipw2200 rtap_iface=1 - % ifconfig rtap0 up - % tethereal -i rtap0 - - If you do not specify 'rtap_iface=1' as a module parameter then - the rtap interface will not be created and you will need to turn - it on via sysfs: - - % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface - -config IPW2200_QOS - bool "Enable QoS support" - depends on IPW2200 && EXPERIMENTAL - -config IPW2200_DEBUG - bool "Enable full debugging output in IPW2200 module." - depends on IPW2200 - ---help--- - This option will enable low level debug tracing output for IPW2200. - - Note, normal debug code is already compiled in. This low level - debug option enables debug on hot paths (e.g Tx, Rx, ISR) and - will result in the kernel module being ~70 larger. Most users - will typically not need this high verbosity debug information. - - If you are not sure, say N here. - config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 @@ -714,6 +568,7 @@ config MAC80211_HWSIM source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/ath5k/Kconfig" source "drivers/net/wireless/ath9k/Kconfig" +source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/b43/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ed0023d..ac590e1c 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -2,9 +2,8 @@ # Makefile for the Linux Wireless network device drivers. # -obj-$(CONFIG_IPW2100) += ipw2100.o - -obj-$(CONFIG_IPW2200) += ipw2200.o +obj-$(CONFIG_IPW2100) += ipw2x00/ +obj-$(CONFIG_IPW2200) += ipw2x00/ obj-$(CONFIG_STRIP) += strip.o obj-$(CONFIG_ARLAN) += arlan.o diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c deleted file mode 100644 index 2d2044d..0000000 --- a/drivers/net/wireless/ipw2100.c +++ /dev/null @@ -1,8649 +0,0 @@ -/****************************************************************************** - - Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - 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; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - James P. Ketrenos - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - - Portions of this file are based on the sample_* files provided by Wireless - Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes - - - Portions of this file are based on the Host AP project, - Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - - Copyright (c) 2002-2003, Jouni Malinen - - Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and - ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c - available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox - -******************************************************************************/ -/* - - Initial driver on which this is based was developed by Janusz Gorycki, - Maciej Urbaniak, and Maciej Sosnowski. - - Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak. - -Theory of Operation - -Tx - Commands and Data - -Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs) -Each TBD contains a pointer to the physical (dma_addr_t) address of data being -sent to the firmware as well as the length of the data. - -The host writes to the TBD queue at the WRITE index. The WRITE index points -to the _next_ packet to be written and is advanced when after the TBD has been -filled. - -The firmware pulls from the TBD queue at the READ index. The READ index points -to the currently being read entry, and is advanced once the firmware is -done with a packet. - -When data is sent to the firmware, the first TBD is used to indicate to the -firmware if a Command or Data is being sent. If it is Command, all of the -command information is contained within the physical address referred to by the -TBD. If it is Data, the first TBD indicates the type of data packet, number -of fragments, etc. The next TBD then referrs to the actual packet location. - -The Tx flow cycle is as follows: - -1) ipw2100_tx() is called by kernel with SKB to transmit -2) Packet is move from the tx_free_list and appended to the transmit pending - list (tx_pend_list) -3) work is scheduled to move pending packets into the shared circular queue. -4) when placing packet in the circular queue, the incoming SKB is DMA mapped - to a physical address. That address is entered into a TBD. Two TBDs are - filled out. The first indicating a data packet, the second referring to the - actual payload data. -5) the packet is removed from tx_pend_list and placed on the end of the - firmware pending list (fw_pend_list) -6) firmware is notified that the WRITE index has -7) Once the firmware has processed the TBD, INTA is triggered. -8) For each Tx interrupt received from the firmware, the READ index is checked - to see which TBDs are done being processed. -9) For each TBD that has been processed, the ISR pulls the oldest packet - from the fw_pend_list. -10)The packet structure contained in the fw_pend_list is then used - to unmap the DMA address and to free the SKB originally passed to the driver - from the kernel. -11)The packet structure is placed onto the tx_free_list - -The above steps are the same for commands, only the msg_free_list/msg_pend_list -are used instead of tx_free_list/tx_pend_list - -... - -Critical Sections / Locking : - -There are two locks utilized. The first is the low level lock (priv->low_lock) -that protects the following: - -- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows: - - tx_free_list : Holds pre-allocated Tx buffers. - TAIL modified in __ipw2100_tx_process() - HEAD modified in ipw2100_tx() - - tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring - TAIL modified ipw2100_tx() - HEAD modified by ipw2100_tx_send_data() - - msg_free_list : Holds pre-allocated Msg (Command) buffers - TAIL modified in __ipw2100_tx_process() - HEAD modified in ipw2100_hw_send_command() - - msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring - TAIL modified in ipw2100_hw_send_command() - HEAD modified in ipw2100_tx_send_commands() - - The flow of data on the TX side is as follows: - - MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST - TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST - - The methods that work on the TBD ring are protected via priv->low_lock. - -- The internal data state of the device itself -- Access to the firmware read/write indexes for the BD queues - and associated logic - -All external entry functions are locked with the priv->action_lock to ensure -that only one external action is invoked at a time. - - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "ipw2100.h" - -#define IPW2100_VERSION "git-1.2.2" - -#define DRV_NAME "ipw2100" -#define DRV_VERSION IPW2100_VERSION -#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" - -/* Debugging stuff */ -#ifdef CONFIG_IPW2100_DEBUG -#define IPW2100_RX_DEBUG /* Reception debugging */ -#endif - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL"); - -static int debug = 0; -static int mode = 0; -static int channel = 0; -static int associate = 0; -static int disable = 0; -#ifdef CONFIG_PM -static struct ipw2100_fw ipw2100_firmware; -#endif - -#include -module_param(debug, int, 0444); -module_param(mode, int, 0444); -module_param(channel, int, 0444); -module_param(associate, int, 0444); -module_param(disable, int, 0444); - -MODULE_PARM_DESC(debug, "debug level"); -MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); -MODULE_PARM_DESC(channel, "channel"); -MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); - -static u32 ipw2100_debug_level = IPW_DL_NONE; - -#ifdef CONFIG_IPW2100_DEBUG -#define IPW_DEBUG(level, message...) \ -do { \ - if (ipw2100_debug_level & (level)) { \ - printk(KERN_DEBUG "ipw2100: %c %s ", \ - in_interrupt() ? 'I' : 'U', __func__); \ - printk(message); \ - } \ -} while (0) -#else -#define IPW_DEBUG(level, message...) do {} while (0) -#endif /* CONFIG_IPW2100_DEBUG */ - -#ifdef CONFIG_IPW2100_DEBUG -static const char *command_types[] = { - "undefined", - "unused", /* HOST_ATTENTION */ - "HOST_COMPLETE", - "unused", /* SLEEP */ - "unused", /* HOST_POWER_DOWN */ - "unused", - "SYSTEM_CONFIG", - "unused", /* SET_IMR */ - "SSID", - "MANDATORY_BSSID", - "AUTHENTICATION_TYPE", - "ADAPTER_ADDRESS", - "PORT_TYPE", - "INTERNATIONAL_MODE", - "CHANNEL", - "RTS_THRESHOLD", - "FRAG_THRESHOLD", - "POWER_MODE", - "TX_RATES", - "BASIC_TX_RATES", - "WEP_KEY_INFO", - "unused", - "unused", - "unused", - "unused", - "WEP_KEY_INDEX", - "WEP_FLAGS", - "ADD_MULTICAST", - "CLEAR_ALL_MULTICAST", - "BEACON_INTERVAL", - "ATIM_WINDOW", - "CLEAR_STATISTICS", - "undefined", - "undefined", - "undefined", - "undefined", - "TX_POWER_INDEX", - "undefined", - "undefined", - "undefined", - "undefined", - "undefined", - "undefined", - "BROADCAST_SCAN", - "CARD_DISABLE", - "PREFERRED_BSSID", - "SET_SCAN_OPTIONS", - "SCAN_DWELL_TIME", - "SWEEP_TABLE", - "AP_OR_STATION_TABLE", - "GROUP_ORDINALS", - "SHORT_RETRY_LIMIT", - "LONG_RETRY_LIMIT", - "unused", /* SAVE_CALIBRATION */ - "unused", /* RESTORE_CALIBRATION */ - "undefined", - "undefined", - "undefined", - "HOST_PRE_POWER_DOWN", - "unused", /* HOST_INTERRUPT_COALESCING */ - "undefined", - "CARD_DISABLE_PHY_OFF", - "MSDU_TX_RATES" "undefined", - "undefined", - "SET_STATION_STAT_BITS", - "CLEAR_STATIONS_STAT_BITS", - "LEAP_ROGUE_MODE", - "SET_SECURITY_INFORMATION", - "DISASSOCIATION_BSSID", - "SET_WPA_ASS_IE" -}; -#endif - -/* Pre-decl until we get the code solid and then we can clean it up */ -static void ipw2100_tx_send_commands(struct ipw2100_priv *priv); -static void ipw2100_tx_send_data(struct ipw2100_priv *priv); -static int ipw2100_adapter_setup(struct ipw2100_priv *priv); - -static void ipw2100_queues_initialize(struct ipw2100_priv *priv); -static void ipw2100_queues_free(struct ipw2100_priv *priv); -static int ipw2100_queues_allocate(struct ipw2100_priv *priv); - -static int ipw2100_fw_download(struct ipw2100_priv *priv, - struct ipw2100_fw *fw); -static int ipw2100_get_firmware(struct ipw2100_priv *priv, - struct ipw2100_fw *fw); -static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, - size_t max); -static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, - size_t max); -static void ipw2100_release_firmware(struct ipw2100_priv *priv, - struct ipw2100_fw *fw); -static int ipw2100_ucode_download(struct ipw2100_priv *priv, - struct ipw2100_fw *fw); -static void ipw2100_wx_event_work(struct work_struct *work); -static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev); -static struct iw_handler_def ipw2100_wx_handler_def; - -static inline void read_register(struct net_device *dev, u32 reg, u32 * val) -{ - *val = readl((void __iomem *)(dev->base_addr + reg)); - IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val); -} - -static inline void write_register(struct net_device *dev, u32 reg, u32 val) -{ - writel(val, (void __iomem *)(dev->base_addr + reg)); - IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val); -} - -static inline void read_register_word(struct net_device *dev, u32 reg, - u16 * val) -{ - *val = readw((void __iomem *)(dev->base_addr + reg)); - IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val); -} - -static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val) -{ - *val = readb((void __iomem *)(dev->base_addr + reg)); - IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val); -} - -static inline void write_register_word(struct net_device *dev, u32 reg, u16 val) -{ - writew(val, (void __iomem *)(dev->base_addr + reg)); - IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val); -} - -static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val) -{ - writeb(val, (void __iomem *)(dev->base_addr + reg)); - IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val); -} - -static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val) -{ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); - read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); -} - -static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val) -{ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); - write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); -} - -static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val) -{ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); - read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); -} - -static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val) -{ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); - write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); -} - -static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val) -{ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); - read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); -} - -static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val) -{ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); - write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); -} - -static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr) -{ - write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, - addr & IPW_REG_INDIRECT_ADDR_MASK); -} - -static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val) -{ - write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val); -} - -static void write_nic_memory(struct net_device *dev, u32 addr, u32 len, - const u8 * buf) -{ - u32 aligned_addr; - u32 aligned_len; - u32 dif_len; - u32 i; - - /* read first nibble byte by byte */ - aligned_addr = addr & (~0x3); - dif_len = addr - aligned_addr; - if (dif_len) { - /* Start reading at aligned_addr + dif_len */ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - aligned_addr); - for (i = dif_len; i < 4; i++, buf++) - write_register_byte(dev, - IPW_REG_INDIRECT_ACCESS_DATA + i, - *buf); - - len -= dif_len; - aligned_addr += 4; - } - - /* read DWs through autoincrement registers */ - write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr); - aligned_len = len & (~0x3); - for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) - write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf); - - /* copy the last nibble */ - dif_len = len - aligned_len; - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); - for (i = 0; i < dif_len; i++, buf++) - write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, - *buf); -} - -static void read_nic_memory(struct net_device *dev, u32 addr, u32 len, - u8 * buf) -{ - u32 aligned_addr; - u32 aligned_len; - u32 dif_len; - u32 i; - - /* read first nibble byte by byte */ - aligned_addr = addr & (~0x3); - dif_len = addr - aligned_addr; - if (dif_len) { - /* Start reading at aligned_addr + dif_len */ - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - aligned_addr); - for (i = dif_len; i < 4; i++, buf++) - read_register_byte(dev, - IPW_REG_INDIRECT_ACCESS_DATA + i, - buf); - - len -= dif_len; - aligned_addr += 4; - } - - /* read DWs through autoincrement registers */ - write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr); - aligned_len = len & (~0x3); - for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) - read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf); - - /* copy the last nibble */ - dif_len = len - aligned_len; - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); - for (i = 0; i < dif_len; i++, buf++) - read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf); -} - -static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev) -{ - return (dev->base_addr && - (readl - ((void __iomem *)(dev->base_addr + - IPW_REG_DOA_DEBUG_AREA_START)) - == IPW_DATA_DOA_DEBUG_VALUE)); -} - -static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, - void *val, u32 * len) -{ - struct ipw2100_ordinals *ordinals = &priv->ordinals; - u32 addr; - u32 field_info; - u16 field_len; - u16 field_count; - u32 total_length; - - if (ordinals->table1_addr == 0) { - printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals " - "before they have been loaded.\n"); - return -EINVAL; - } - - if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { - if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) { - *len = IPW_ORD_TAB_1_ENTRY_SIZE; - - printk(KERN_WARNING DRV_NAME - ": ordinal buffer length too small, need %zd\n", - IPW_ORD_TAB_1_ENTRY_SIZE); - - return -EINVAL; - } - - read_nic_dword(priv->net_dev, - ordinals->table1_addr + (ord << 2), &addr); - read_nic_dword(priv->net_dev, addr, val); - - *len = IPW_ORD_TAB_1_ENTRY_SIZE; - - return 0; - } - - if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) { - - ord -= IPW_START_ORD_TAB_2; - - /* get the address of statistic */ - read_nic_dword(priv->net_dev, - ordinals->table2_addr + (ord << 3), &addr); - - /* get the second DW of statistics ; - * two 16-bit words - first is length, second is count */ - read_nic_dword(priv->net_dev, - ordinals->table2_addr + (ord << 3) + sizeof(u32), - &field_info); - - /* get each entry length */ - field_len = *((u16 *) & field_info); - - /* get number of entries */ - field_count = *(((u16 *) & field_info) + 1); - - /* abort if no enought memory */ - total_length = field_len * field_count; - if (total_length > *len) { - *len = total_length; - return -EINVAL; - } - - *len = total_length; - if (!total_length) - return 0; - - /* read the ordinal data from the SRAM */ - read_nic_memory(priv->net_dev, addr, total_length, val); - - return 0; - } - - printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor " - "in table 2\n", ord); - - return -EINVAL; -} - -static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val, - u32 * len) -{ - struct ipw2100_ordinals *ordinals = &priv->ordinals; - u32 addr; - - if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { - if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) { - *len = IPW_ORD_TAB_1_ENTRY_SIZE; - IPW_DEBUG_INFO("wrong size\n"); - return -EINVAL; - } - - read_nic_dword(priv->net_dev, - ordinals->table1_addr + (ord << 2), &addr); - - write_nic_dword(priv->net_dev, addr, *val); - - *len = IPW_ORD_TAB_1_ENTRY_SIZE; - - return 0; - } - - IPW_DEBUG_INFO("wrong table\n"); - if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) - return -EINVAL; - - return -EINVAL; -} - -static char *snprint_line(char *buf, size_t count, - const u8 * data, u32 len, u32 ofs) -{ - int out, i, j, l; - char c; - - out = snprintf(buf, count, "%08X", ofs); - - for (l = 0, i = 0; i < 2; i++) { - out += snprintf(buf + out, count - out, " "); - for (j = 0; j < 8 && l < len; j++, l++) - out += snprintf(buf + out, count - out, "%02X ", - data[(i * 8 + j)]); - for (; j < 8; j++) - out += snprintf(buf + out, count - out, " "); - } - - out += snprintf(buf + out, count - out, " "); - for (l = 0, i = 0; i < 2; i++) { - out += snprintf(buf + out, count - out, " "); - for (j = 0; j < 8 && l < len; j++, l++) { - c = data[(i * 8 + j)]; - if (!isascii(c) || !isprint(c)) - c = '.'; - - out += snprintf(buf + out, count - out, "%c", c); - } - - for (; j < 8; j++) - out += snprintf(buf + out, count - out, " "); - } - - return buf; -} - -static void printk_buf(int level, const u8 * data, u32 len) -{ - char line[81]; - u32 ofs = 0; - if (!(ipw2100_debug_level & level)) - return; - - while (len) { - printk(KERN_DEBUG "%s\n", - snprint_line(line, sizeof(line), &data[ofs], - min(len, 16U), ofs)); - ofs += 16; - len -= min(len, 16U); - } -} - -#define MAX_RESET_BACKOFF 10 - -static void schedule_reset(struct ipw2100_priv *priv) -{ - unsigned long now = get_seconds(); - - /* If we haven't received a reset request within the backoff period, - * then we can reset the backoff interval so this reset occurs - * immediately */ - if (priv->reset_backoff && - (now - priv->last_reset > priv->reset_backoff)) - priv->reset_backoff = 0; - - priv->last_reset = get_seconds(); - - if (!(priv->status & STATUS_RESET_PENDING)) { - IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n", - priv->net_dev->name, priv->reset_backoff); - netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); - priv->status |= STATUS_RESET_PENDING; - if (priv->reset_backoff) - queue_delayed_work(priv->workqueue, &priv->reset_work, - priv->reset_backoff * HZ); - else - queue_delayed_work(priv->workqueue, &priv->reset_work, - 0); - - if (priv->reset_backoff < MAX_RESET_BACKOFF) - priv->reset_backoff++; - - wake_up_interruptible(&priv->wait_command_queue); - } else - IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n", - priv->net_dev->name); - -} - -#define HOST_COMPLETE_TIMEOUT (2 * HZ) -static int ipw2100_hw_send_command(struct ipw2100_priv *priv, - struct host_command *cmd) -{ - struct list_head *element; - struct ipw2100_tx_packet *packet; - unsigned long flags; - int err = 0; - - IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", - command_types[cmd->host_command], cmd->host_command, - cmd->host_command_length); - printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters, - cmd->host_command_length); - - spin_lock_irqsave(&priv->low_lock, flags); - - if (priv->fatal_error) { - IPW_DEBUG_INFO - ("Attempt to send command while hardware in fatal error condition.\n"); - err = -EIO; - goto fail_unlock; - } - - if (!(priv->status & STATUS_RUNNING)) { - IPW_DEBUG_INFO - ("Attempt to send command while hardware is not running.\n"); - err = -EIO; - goto fail_unlock; - } - - if (priv->status & STATUS_CMD_ACTIVE) { - IPW_DEBUG_INFO - ("Attempt to send command while another command is pending.\n"); - err = -EBUSY; - goto fail_unlock; - } - - if (list_empty(&priv->msg_free_list)) { - IPW_DEBUG_INFO("no available msg buffers\n"); - goto fail_unlock; - } - - priv->status |= STATUS_CMD_ACTIVE; - priv->messages_sent++; - - element = priv->msg_free_list.next; - - packet = list_entry(element, struct ipw2100_tx_packet, list); - packet->jiffy_start = jiffies; - - /* initialize the firmware command packet */ - packet->info.c_struct.cmd->host_command_reg = cmd->host_command; - packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1; - packet->info.c_struct.cmd->host_command_len_reg = - cmd->host_command_length; - packet->info.c_struct.cmd->sequence = cmd->host_command_sequence; - - memcpy(packet->info.c_struct.cmd->host_command_params_reg, - cmd->host_command_parameters, - sizeof(packet->info.c_struct.cmd->host_command_params_reg)); - - list_del(element); - DEC_STAT(&priv->msg_free_stat); - - list_add_tail(element, &priv->msg_pend_list); - INC_STAT(&priv->msg_pend_stat); - - ipw2100_tx_send_commands(priv); - ipw2100_tx_send_data(priv); - - spin_unlock_irqrestore(&priv->low_lock, flags); - - /* - * We must wait for this command to complete before another - * command can be sent... but if we wait more than 3 seconds - * then there is a problem. - */ - - err = - wait_event_interruptible_timeout(priv->wait_command_queue, - !(priv-> - status & STATUS_CMD_ACTIVE), - HOST_COMPLETE_TIMEOUT); - - if (err == 0) { - IPW_DEBUG_INFO("Command completion failed out after %dms.\n", - 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); - priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT; - priv->status &= ~STATUS_CMD_ACTIVE; - schedule_reset(priv); - return -EIO; - } - - if (priv->fatal_error) { - printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n", - priv->net_dev->name); - return -EIO; - } - - /* !!!!! HACK TEST !!!!! - * When lots of debug trace statements are enabled, the driver - * doesn't seem to have as many firmware restart cycles... - * - * As a test, we're sticking in a 1/100s delay here */ - schedule_timeout_uninterruptible(msecs_to_jiffies(10)); - - return 0; - - fail_unlock: - spin_unlock_irqrestore(&priv->low_lock, flags); - - return err; -} - -/* - * Verify the values and data access of the hardware - * No locks needed or used. No functions called. - */ -static int ipw2100_verify(struct ipw2100_priv *priv) -{ - u32 data1, data2; - u32 address; - - u32 val1 = 0x76543210; - u32 val2 = 0xFEDCBA98; - - /* Domain 0 check - all values should be DOA_DEBUG */ - for (address = IPW_REG_DOA_DEBUG_AREA_START; - address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) { - read_register(priv->net_dev, address, &data1); - if (data1 != IPW_DATA_DOA_DEBUG_VALUE) - return -EIO; - } - - /* Domain 1 check - use arbitrary read/write compare */ - for (address = 0; address < 5; address++) { - /* The memory area is not used now */ - write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, - val1); - write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, - val2); - read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, - &data1); - read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, - &data2); - if (val1 == data1 && val2 == data2) - return 0; - } - - return -EIO; -} - -/* - * - * Loop until the CARD_DISABLED bit is the same value as the - * supplied parameter - * - * TODO: See if it would be more efficient to do a wait/wake - * cycle and have the completion event trigger the wakeup - * - */ -#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli -static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state) -{ - int i; - u32 card_state; - u32 len = sizeof(card_state); - int err; - - for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) { - err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED, - &card_state, &len); - if (err) { - IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal " - "failed.\n"); - return 0; - } - - /* We'll break out if either the HW state says it is - * in the state we want, or if HOST_COMPLETE command - * finishes */ - if ((card_state == state) || - ((priv->status & STATUS_ENABLED) ? - IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) { - if (state == IPW_HW_STATE_ENABLED) - priv->status |= STATUS_ENABLED; - else - priv->status &= ~STATUS_ENABLED; - - return 0; - } - - udelay(50); - } - - IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n", - state ? "DISABLED" : "ENABLED"); - return -EIO; -} - -/********************************************************************* - Procedure : sw_reset_and_clock - Purpose : Asserts s/w reset, asserts clock initialization - and waits for clock stabilization - ********************************************************************/ -static int sw_reset_and_clock(struct ipw2100_priv *priv) -{ - int i; - u32 r; - - // assert s/w reset - write_register(priv->net_dev, IPW_REG_RESET_REG, - IPW_AUX_HOST_RESET_REG_SW_RESET); - - // wait for clock stabilization - for (i = 0; i < 1000; i++) { - udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY); - - // check clock ready bit - read_register(priv->net_dev, IPW_REG_RESET_REG, &r); - if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET) - break; - } - - if (i == 1000) - return -EIO; // TODO: better error value - - /* set "initialization complete" bit to move adapter to - * D0 state */ - write_register(priv->net_dev, IPW_REG_GP_CNTRL, - IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE); - - /* wait for clock stabilization */ - for (i = 0; i < 10000; i++) { - udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4); - - /* check clock ready bit */ - read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); - if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY) - break; - } - - if (i == 10000) - return -EIO; /* TODO: better error value */ - - /* set D0 standby bit */ - read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); - write_register(priv->net_dev, IPW_REG_GP_CNTRL, - r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); - - return 0; -} - -/********************************************************************* - Procedure : ipw2100_download_firmware - Purpose : Initiaze adapter after power on. - The sequence is: - 1. assert s/w reset first! - 2. awake clocks & wait for clock stabilization - 3. hold ARC (don't ask me why...) - 4. load Dino ucode and reset/clock init again - 5. zero-out shared mem - 6. download f/w - *******************************************************************/ -static int ipw2100_download_firmware(struct ipw2100_priv *priv) -{ - u32 address; - int err; - -#ifndef CONFIG_PM - /* Fetch the firmware and microcode */ - struct ipw2100_fw ipw2100_firmware; -#endif - - if (priv->fatal_error) { - IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after " - "fatal error %d. Interface must be brought down.\n", - priv->net_dev->name, priv->fatal_error); - return -EINVAL; - } -#ifdef CONFIG_PM - if (!ipw2100_firmware.version) { - err = ipw2100_get_firmware(priv, &ipw2100_firmware); - if (err) { - IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", - priv->net_dev->name, err); - priv->fatal_error = IPW2100_ERR_FW_LOAD; - goto fail; - } - } -#else - err = ipw2100_get_firmware(priv, &ipw2100_firmware); - if (err) { - IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", - priv->net_dev->name, err); - priv->fatal_error = IPW2100_ERR_FW_LOAD; - goto fail; - } -#endif - priv->firmware_version = ipw2100_firmware.version; - - /* s/w reset and clock stabilization */ - err = sw_reset_and_clock(priv); - if (err) { - IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n", - priv->net_dev->name, err); - goto fail; - } - - err = ipw2100_verify(priv); - if (err) { - IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n", - priv->net_dev->name, err); - goto fail; - } - - /* Hold ARC */ - write_nic_dword(priv->net_dev, - IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000); - - /* allow ARC to run */ - write_register(priv->net_dev, IPW_REG_RESET_REG, 0); - - /* load microcode */ - err = ipw2100_ucode_download(priv, &ipw2100_firmware); - if (err) { - printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n", - priv->net_dev->name, err); - goto fail; - } - - /* release ARC */ - write_nic_dword(priv->net_dev, - IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000); - - /* s/w reset and clock stabilization (again!!!) */ - err = sw_reset_and_clock(priv); - if (err) { - printk(KERN_ERR DRV_NAME - ": %s: sw_reset_and_clock failed: %d\n", - priv->net_dev->name, err); - goto fail; - } - - /* load f/w */ - err = ipw2100_fw_download(priv, &ipw2100_firmware); - if (err) { - IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n", - priv->net_dev->name, err); - goto fail; - } -#ifndef CONFIG_PM - /* - * When the .resume method of the driver is called, the other - * part of the system, i.e. the ide driver could still stay in - * the suspend stage. This prevents us from loading the firmware - * from the disk. --YZ - */ - - /* free any storage allocated for firmware image */ - ipw2100_release_firmware(priv, &ipw2100_firmware); -#endif - - /* zero out Domain 1 area indirectly (Si requirement) */ - for (address = IPW_HOST_FW_SHARED_AREA0; - address < IPW_HOST_FW_SHARED_AREA0_END; address += 4) - write_nic_dword(priv->net_dev, address, 0); - for (address = IPW_HOST_FW_SHARED_AREA1; - address < IPW_HOST_FW_SHARED_AREA1_END; address += 4) - write_nic_dword(priv->net_dev, address, 0); - for (address = IPW_HOST_FW_SHARED_AREA2; - address < IPW_HOST_FW_SHARED_AREA2_END; address += 4) - write_nic_dword(priv->net_dev, address, 0); - for (address = IPW_HOST_FW_SHARED_AREA3; - address < IPW_HOST_FW_SHARED_AREA3_END; address += 4) - write_nic_dword(priv->net_dev, address, 0); - for (address = IPW_HOST_FW_INTERRUPT_AREA; - address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4) - write_nic_dword(priv->net_dev, address, 0); - - return 0; - - fail: - ipw2100_release_firmware(priv, &ipw2100_firmware); - return err; -} - -static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv) -{ - if (priv->status & STATUS_INT_ENABLED) - return; - priv->status |= STATUS_INT_ENABLED; - write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK); -} - -static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv) -{ - if (!(priv->status & STATUS_INT_ENABLED)) - return; - priv->status &= ~STATUS_INT_ENABLED; - write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0); -} - -static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv) -{ - struct ipw2100_ordinals *ord = &priv->ordinals; - - IPW_DEBUG_INFO("enter\n"); - - read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1, - &ord->table1_addr); - - read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2, - &ord->table2_addr); - - read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size); - read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size); - - ord->table2_size &= 0x0000FFFF; - - IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size); - IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size); - IPW_DEBUG_INFO("exit\n"); -} - -static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv) -{ - u32 reg = 0; - /* - * Set GPIO 3 writable by FW; GPIO 1 writable - * by driver and enable clock - */ - reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE | - IPW_BIT_GPIO_LED_OFF); - write_register(priv->net_dev, IPW_REG_GPIO, reg); -} - -static int rf_kill_active(struct ipw2100_priv *priv) -{ -#define MAX_RF_KILL_CHECKS 5 -#define RF_KILL_CHECK_DELAY 40 - - unsigned short value = 0; - u32 reg = 0; - int i; - - if (!(priv->hw_features & HW_FEATURE_RFKILL)) { - priv->status &= ~STATUS_RF_KILL_HW; - return 0; - } - - for (i = 0; i < MAX_RF_KILL_CHECKS; i++) { - udelay(RF_KILL_CHECK_DELAY); - read_register(priv->net_dev, IPW_REG_GPIO, ®); - value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1); - } - - if (value == 0) - priv->status |= STATUS_RF_KILL_HW; - else - priv->status &= ~STATUS_RF_KILL_HW; - - return (value == 0); -} - -static int ipw2100_get_hw_features(struct ipw2100_priv *priv) -{ - u32 addr, len; - u32 val; - - /* - * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1 - */ - len = sizeof(addr); - if (ipw2100_get_ordinal - (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) { - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - return -EIO; - } - - IPW_DEBUG_INFO("EEPROM address: %08X\n", addr); - - /* - * EEPROM version is the byte at offset 0xfd in firmware - * We read 4 bytes, then shift out the byte we actually want */ - read_nic_dword(priv->net_dev, addr + 0xFC, &val); - priv->eeprom_version = (val >> 24) & 0xFF; - IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version); - - /* - * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware - * - * notice that the EEPROM bit is reverse polarity, i.e. - * bit = 0 signifies HW RF kill switch is supported - * bit = 1 signifies HW RF kill switch is NOT supported - */ - read_nic_dword(priv->net_dev, addr + 0x20, &val); - if (!((val >> 24) & 0x01)) - priv->hw_features |= HW_FEATURE_RFKILL; - - IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n", - (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not "); - - return 0; -} - -/* - * Start firmware execution after power on and intialization - * The sequence is: - * 1. Release ARC - * 2. Wait for f/w initialization completes; - */ -static int ipw2100_start_adapter(struct ipw2100_priv *priv) -{ - int i; - u32 inta, inta_mask, gpio; - - IPW_DEBUG_INFO("enter\n"); - - if (priv->status & STATUS_RUNNING) - return 0; - - /* - * Initialize the hw - drive adapter to DO state by setting - * init_done bit. Wait for clk_ready bit and Download - * fw & dino ucode - */ - if (ipw2100_download_firmware(priv)) { - printk(KERN_ERR DRV_NAME - ": %s: Failed to power on the adapter.\n", - priv->net_dev->name); - return -EIO; - } - - /* Clear the Tx, Rx and Msg queues and the r/w indexes - * in the firmware RBD and TBD ring queue */ - ipw2100_queues_initialize(priv); - - ipw2100_hw_set_gpio(priv); - - /* TODO -- Look at disabling interrupts here to make sure none - * get fired during FW initialization */ - - /* Release ARC - clear reset bit */ - write_register(priv->net_dev, IPW_REG_RESET_REG, 0); - - /* wait for f/w intialization complete */ - IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); - i = 5000; - do { - schedule_timeout_uninterruptible(msecs_to_jiffies(40)); - /* Todo... wait for sync command ... */ - - read_register(priv->net_dev, IPW_REG_INTA, &inta); - - /* check "init done" bit */ - if (inta & IPW2100_INTA_FW_INIT_DONE) { - /* reset "init done" bit */ - write_register(priv->net_dev, IPW_REG_INTA, - IPW2100_INTA_FW_INIT_DONE); - break; - } - - /* check error conditions : we check these after the firmware - * check so that if there is an error, the interrupt handler - * will see it and the adapter will be reset */ - if (inta & - (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) { - /* clear error conditions */ - write_register(priv->net_dev, IPW_REG_INTA, - IPW2100_INTA_FATAL_ERROR | - IPW2100_INTA_PARITY_ERROR); - } - } while (--i); - - /* Clear out any pending INTAs since we aren't supposed to have - * interrupts enabled at this point... */ - read_register(priv->net_dev, IPW_REG_INTA, &inta); - read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); - inta &= IPW_INTERRUPT_MASK; - /* Clear out any pending interrupts */ - if (inta & inta_mask) - write_register(priv->net_dev, IPW_REG_INTA, inta); - - IPW_DEBUG_FW("f/w initialization complete: %s\n", - i ? "SUCCESS" : "FAILED"); - - if (!i) { - printk(KERN_WARNING DRV_NAME - ": %s: Firmware did not initialize.\n", - priv->net_dev->name); - return -EIO; - } - - /* allow firmware to write to GPIO1 & GPIO3 */ - read_register(priv->net_dev, IPW_REG_GPIO, &gpio); - - gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK); - - write_register(priv->net_dev, IPW_REG_GPIO, gpio); - - /* Ready to receive commands */ - priv->status |= STATUS_RUNNING; - - /* The adapter has been reset; we are not associated */ - priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); - - IPW_DEBUG_INFO("exit\n"); - - return 0; -} - -static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv) -{ - if (!priv->fatal_error) - return; - - priv->fatal_errors[priv->fatal_index++] = priv->fatal_error; - priv->fatal_index %= IPW2100_ERROR_QUEUE; - priv->fatal_error = 0; -} - -/* NOTE: Our interrupt is disabled when this method is called */ -static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) -{ - u32 reg; - int i; - - IPW_DEBUG_INFO("Power cycling the hardware.\n"); - - ipw2100_hw_set_gpio(priv); - - /* Step 1. Stop Master Assert */ - write_register(priv->net_dev, IPW_REG_RESET_REG, - IPW_AUX_HOST_RESET_REG_STOP_MASTER); - - /* Step 2. Wait for stop Master Assert - * (not more then 50us, otherwise ret error */ - i = 5; - do { - udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); - read_register(priv->net_dev, IPW_REG_RESET_REG, ®); - - if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) - break; - } while (--i); - - priv->status &= ~STATUS_RESET_PENDING; - - if (!i) { - IPW_DEBUG_INFO - ("exit - waited too long for master assert stop\n"); - return -EIO; - } - - write_register(priv->net_dev, IPW_REG_RESET_REG, - IPW_AUX_HOST_RESET_REG_SW_RESET); - - /* Reset any fatal_error conditions */ - ipw2100_reset_fatalerror(priv); - - /* At this point, the adapter is now stopped and disabled */ - priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING | - STATUS_ASSOCIATED | STATUS_ENABLED); - - return 0; -} - -/* - * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it - * - * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent. - * - * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of - * if STATUS_ASSN_LOST is sent. - */ -static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) -{ - -#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) - - struct host_command cmd = { - .host_command = CARD_DISABLE_PHY_OFF, - .host_command_sequence = 0, - .host_command_length = 0, - }; - int err, i; - u32 val1, val2; - - IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n"); - - /* Turn off the radio */ - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - - for (i = 0; i < 2500; i++) { - read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1); - read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2); - - if ((val1 & IPW2100_CONTROL_PHY_OFF) && - (val2 & IPW2100_COMMAND_PHY_OFF)) - return 0; - - schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY); - } - - return -EIO; -} - -static int ipw2100_enable_adapter(struct ipw2100_priv *priv) -{ - struct host_command cmd = { - .host_command = HOST_COMPLETE, - .host_command_sequence = 0, - .host_command_length = 0 - }; - int err = 0; - - IPW_DEBUG_HC("HOST_COMPLETE\n"); - - if (priv->status & STATUS_ENABLED) - return 0; - - mutex_lock(&priv->adapter_mutex); - - if (rf_kill_active(priv)) { - IPW_DEBUG_HC("Command aborted due to RF kill active.\n"); - goto fail_up; - } - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) { - IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n"); - goto fail_up; - } - - err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED); - if (err) { - IPW_DEBUG_INFO("%s: card not responding to init command.\n", - priv->net_dev->name); - goto fail_up; - } - - if (priv->stop_hang_check) { - priv->stop_hang_check = 0; - queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); - } - - fail_up: - mutex_unlock(&priv->adapter_mutex); - return err; -} - -static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) -{ -#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100)) - - struct host_command cmd = { - .host_command = HOST_PRE_POWER_DOWN, - .host_command_sequence = 0, - .host_command_length = 0, - }; - int err, i; - u32 reg; - - if (!(priv->status & STATUS_RUNNING)) - return 0; - - priv->status |= STATUS_STOPPING; - - /* We can only shut down the card if the firmware is operational. So, - * if we haven't reset since a fatal_error, then we can not send the - * shutdown commands. */ - if (!priv->fatal_error) { - /* First, make sure the adapter is enabled so that the PHY_OFF - * command can shut it down */ - ipw2100_enable_adapter(priv); - - err = ipw2100_hw_phy_off(priv); - if (err) - printk(KERN_WARNING DRV_NAME - ": Error disabling radio %d\n", err); - - /* - * If in D0-standby mode going directly to D3 may cause a - * PCI bus violation. Therefore we must change out of the D0 - * state. - * - * Sending the PREPARE_FOR_POWER_DOWN will restrict the - * hardware from going into standby mode and will transition - * out of D0-standby if it is already in that state. - * - * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the - * driver upon completion. Once received, the driver can - * proceed to the D3 state. - * - * Prepare for power down command to fw. This command would - * take HW out of D0-standby and prepare it for D3 state. - * - * Currently FW does not support event notification for this - * event. Therefore, skip waiting for it. Just wait a fixed - * 100ms - */ - IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n"); - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - printk(KERN_WARNING DRV_NAME ": " - "%s: Power down command failed: Error %d\n", - priv->net_dev->name, err); - else - schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY); - } - - priv->status &= ~STATUS_ENABLED; - - /* - * Set GPIO 3 writable by FW; GPIO 1 writable - * by driver and enable clock - */ - ipw2100_hw_set_gpio(priv); - - /* - * Power down adapter. Sequence: - * 1. Stop master assert (RESET_REG[9]=1) - * 2. Wait for stop master (RESET_REG[8]==1) - * 3. S/w reset assert (RESET_REG[7] = 1) - */ - - /* Stop master assert */ - write_register(priv->net_dev, IPW_REG_RESET_REG, - IPW_AUX_HOST_RESET_REG_STOP_MASTER); - - /* wait stop master not more than 50 usec. - * Otherwise return error. */ - for (i = 5; i > 0; i--) { - udelay(10); - - /* Check master stop bit */ - read_register(priv->net_dev, IPW_REG_RESET_REG, ®); - - if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) - break; - } - - if (i == 0) - printk(KERN_WARNING DRV_NAME - ": %s: Could now power down adapter.\n", - priv->net_dev->name); - - /* assert s/w reset */ - write_register(priv->net_dev, IPW_REG_RESET_REG, - IPW_AUX_HOST_RESET_REG_SW_RESET); - - priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING); - - return 0; -} - -static int ipw2100_disable_adapter(struct ipw2100_priv *priv) -{ - struct host_command cmd = { - .host_command = CARD_DISABLE, - .host_command_sequence = 0, - .host_command_length = 0 - }; - int err = 0; - - IPW_DEBUG_HC("CARD_DISABLE\n"); - - if (!(priv->status & STATUS_ENABLED)) - return 0; - - /* Make sure we clear the associated state */ - priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); - - if (!priv->stop_hang_check) { - priv->stop_hang_check = 1; - cancel_delayed_work(&priv->hang_check); - } - - mutex_lock(&priv->adapter_mutex); - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) { - printk(KERN_WARNING DRV_NAME - ": exit - failed to send CARD_DISABLE command\n"); - goto fail_up; - } - - err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED); - if (err) { - printk(KERN_WARNING DRV_NAME - ": exit - card failed to change to DISABLED\n"); - goto fail_up; - } - - IPW_DEBUG_INFO("TODO: implement scan state machine\n"); - - fail_up: - mutex_unlock(&priv->adapter_mutex); - return err; -} - -static int ipw2100_set_scan_options(struct ipw2100_priv *priv) -{ - struct host_command cmd = { - .host_command = SET_SCAN_OPTIONS, - .host_command_sequence = 0, - .host_command_length = 8 - }; - int err; - - IPW_DEBUG_INFO("enter\n"); - - IPW_DEBUG_SCAN("setting scan options\n"); - - cmd.host_command_parameters[0] = 0; - - if (!(priv->config & CFG_ASSOCIATE)) - cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE; - if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled) - cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL; - if (priv->config & CFG_PASSIVE_SCAN) - cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE; - - cmd.host_command_parameters[1] = priv->channel_mask; - - err = ipw2100_hw_send_command(priv, &cmd); - - IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n", - cmd.host_command_parameters[0]); - - return err; -} - -static int ipw2100_start_scan(struct ipw2100_priv *priv) -{ - struct host_command cmd = { - .host_command = BROADCAST_SCAN, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - IPW_DEBUG_HC("START_SCAN\n"); - - cmd.host_command_parameters[0] = 0; - - /* No scanning if in monitor mode */ - if (priv->ieee->iw_mode == IW_MODE_MONITOR) - return 1; - - if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_SCAN("Scan requested while already in scan...\n"); - return 0; - } - - IPW_DEBUG_INFO("enter\n"); - - /* Not clearing here; doing so makes iwlist always return nothing... - * - * We should modify the table logic to use aging tables vs. clearing - * the table on each scan start. - */ - IPW_DEBUG_SCAN("starting scan\n"); - - priv->status |= STATUS_SCANNING; - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - priv->status &= ~STATUS_SCANNING; - - IPW_DEBUG_INFO("exit\n"); - - return err; -} - -static const struct ieee80211_geo ipw_geos[] = { - { /* Restricted */ - "---", - .bg_channels = 14, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14}}, - }, -}; - -static int ipw2100_up(struct ipw2100_priv *priv, int deferred) -{ - unsigned long flags; - int rc = 0; - u32 lock; - u32 ord_len = sizeof(lock); - - /* Quite if manually disabled. */ - if (priv->status & STATUS_RF_KILL_SW) { - IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable " - "switch\n", priv->net_dev->name); - return 0; - } - - /* the ipw2100 hardware really doesn't want power management delays - * longer than 175usec - */ - pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175); - - /* If the interrupt is enabled, turn it off... */ - spin_lock_irqsave(&priv->low_lock, flags); - ipw2100_disable_interrupts(priv); - - /* Reset any fatal_error conditions */ - ipw2100_reset_fatalerror(priv); - spin_unlock_irqrestore(&priv->low_lock, flags); - - if (priv->status & STATUS_POWERED || - (priv->status & STATUS_RESET_PENDING)) { - /* Power cycle the card ... */ - if (ipw2100_power_cycle_adapter(priv)) { - printk(KERN_WARNING DRV_NAME - ": %s: Could not cycle adapter.\n", - priv->net_dev->name); - rc = 1; - goto exit; - } - } else - priv->status |= STATUS_POWERED; - - /* Load the firmware, start the clocks, etc. */ - if (ipw2100_start_adapter(priv)) { - printk(KERN_ERR DRV_NAME - ": %s: Failed to start the firmware.\n", - priv->net_dev->name); - rc = 1; - goto exit; - } - - ipw2100_initialize_ordinals(priv); - - /* Determine capabilities of this particular HW configuration */ - if (ipw2100_get_hw_features(priv)) { - printk(KERN_ERR DRV_NAME - ": %s: Failed to determine HW features.\n", - priv->net_dev->name); - rc = 1; - goto exit; - } - - /* Initialize the geo */ - if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) { - printk(KERN_WARNING DRV_NAME "Could not set geo\n"); - return 0; - } - priv->ieee->freq_band = IEEE80211_24GHZ_BAND; - - lock = LOCK_NONE; - if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { - printk(KERN_ERR DRV_NAME - ": %s: Failed to clear ordinal lock.\n", - priv->net_dev->name); - rc = 1; - goto exit; - } - - priv->status &= ~STATUS_SCANNING; - - if (rf_kill_active(priv)) { - printk(KERN_INFO "%s: Radio is disabled by RF switch.\n", - priv->net_dev->name); - - if (priv->stop_rf_kill) { - priv->stop_rf_kill = 0; - queue_delayed_work(priv->workqueue, &priv->rf_kill, - round_jiffies_relative(HZ)); - } - - deferred = 1; - } - - /* Turn on the interrupt so that commands can be processed */ - ipw2100_enable_interrupts(priv); - - /* Send all of the commands that must be sent prior to - * HOST_COMPLETE */ - if (ipw2100_adapter_setup(priv)) { - printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n", - priv->net_dev->name); - rc = 1; - goto exit; - } - - if (!deferred) { - /* Enable the adapter - sends HOST_COMPLETE */ - if (ipw2100_enable_adapter(priv)) { - printk(KERN_ERR DRV_NAME ": " - "%s: failed in call to enable adapter.\n", - priv->net_dev->name); - ipw2100_hw_stop_adapter(priv); - rc = 1; - goto exit; - } - - /* Start a scan . . . */ - ipw2100_set_scan_options(priv); - ipw2100_start_scan(priv); - } - - exit: - return rc; -} - -/* Called by register_netdev() */ -static int ipw2100_net_init(struct net_device *dev) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ipw2100_up(priv, 1); -} - -static void ipw2100_down(struct ipw2100_priv *priv) -{ - unsigned long flags; - union iwreq_data wrqu = { - .ap_addr = { - .sa_family = ARPHRD_ETHER} - }; - int associated = priv->status & STATUS_ASSOCIATED; - - /* Kill the RF switch timer */ - if (!priv->stop_rf_kill) { - priv->stop_rf_kill = 1; - cancel_delayed_work(&priv->rf_kill); - } - - /* Kill the firmare hang check timer */ - if (!priv->stop_hang_check) { - priv->stop_hang_check = 1; - cancel_delayed_work(&priv->hang_check); - } - - /* Kill any pending resets */ - if (priv->status & STATUS_RESET_PENDING) - cancel_delayed_work(&priv->reset_work); - - /* Make sure the interrupt is on so that FW commands will be - * processed correctly */ - spin_lock_irqsave(&priv->low_lock, flags); - ipw2100_enable_interrupts(priv); - spin_unlock_irqrestore(&priv->low_lock, flags); - - if (ipw2100_hw_stop_adapter(priv)) - printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n", - priv->net_dev->name); - - /* Do not disable the interrupt until _after_ we disable - * the adaptor. Otherwise the CARD_DISABLE command will never - * be ack'd by the firmware */ - spin_lock_irqsave(&priv->low_lock, flags); - ipw2100_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->low_lock, flags); - - pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", - PM_QOS_DEFAULT_VALUE); - - /* We have to signal any supplicant if we are disassociating */ - if (associated) - wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); - - priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); - netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); -} - -static void ipw2100_reset_adapter(struct work_struct *work) -{ - struct ipw2100_priv *priv = - container_of(work, struct ipw2100_priv, reset_work.work); - unsigned long flags; - union iwreq_data wrqu = { - .ap_addr = { - .sa_family = ARPHRD_ETHER} - }; - int associated = priv->status & STATUS_ASSOCIATED; - - spin_lock_irqsave(&priv->low_lock, flags); - IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name); - priv->resets++; - priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); - priv->status |= STATUS_SECURITY_UPDATED; - - /* Force a power cycle even if interface hasn't been opened - * yet */ - cancel_delayed_work(&priv->reset_work); - priv->status |= STATUS_RESET_PENDING; - spin_unlock_irqrestore(&priv->low_lock, flags); - - mutex_lock(&priv->action_mutex); - /* stop timed checks so that they don't interfere with reset */ - priv->stop_hang_check = 1; - cancel_delayed_work(&priv->hang_check); - - /* We have to signal any supplicant if we are disassociating */ - if (associated) - wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); - - ipw2100_up(priv, 0); - mutex_unlock(&priv->action_mutex); - -} - -static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) -{ - -#define MAC_ASSOCIATION_READ_DELAY (HZ) - int ret, len, essid_len; - char essid[IW_ESSID_MAX_SIZE]; - u32 txrate; - u32 chan; - char *txratename; - u8 bssid[ETH_ALEN]; - DECLARE_SSID_BUF(ssid); - - /* - * TBD: BSSID is usually 00:00:00:00:00:00 here and not - * an actual MAC of the AP. Seems like FW sets this - * address too late. Read it later and expose through - * /proc or schedule a later task to query and update - */ - - essid_len = IW_ESSID_MAX_SIZE; - ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, - essid, &essid_len); - if (ret) { - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - return; - } - - len = sizeof(u32); - ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len); - if (ret) { - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - return; - } - - len = sizeof(u32); - ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len); - if (ret) { - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - return; - } - len = ETH_ALEN; - ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); - if (ret) { - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - return; - } - memcpy(priv->ieee->bssid, bssid, ETH_ALEN); - - switch (txrate) { - case TX_RATE_1_MBIT: - txratename = "1Mbps"; - break; - case TX_RATE_2_MBIT: - txratename = "2Mbsp"; - break; - case TX_RATE_5_5_MBIT: - txratename = "5.5Mbps"; - break; - case TX_RATE_11_MBIT: - txratename = "11Mbps"; - break; - default: - IPW_DEBUG_INFO("Unknown rate: %d\n", txrate); - txratename = "unknown rate"; - break; - } - - IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", - priv->net_dev->name, print_ssid(ssid, essid, essid_len), - txratename, chan, bssid); - - /* now we copy read ssid into dev */ - if (!(priv->config & CFG_STATIC_ESSID)) { - priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE); - memcpy(priv->essid, essid, priv->essid_len); - } - priv->channel = chan; - memcpy(priv->bssid, bssid, ETH_ALEN); - - priv->status |= STATUS_ASSOCIATING; - priv->connect_start = get_seconds(); - - queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10); -} - -static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, - int length, int batch_mode) -{ - int ssid_len = min(length, IW_ESSID_MAX_SIZE); - struct host_command cmd = { - .host_command = SSID, - .host_command_sequence = 0, - .host_command_length = ssid_len - }; - int err; - DECLARE_SSID_BUF(ssid); - - IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len)); - - if (ssid_len) - memcpy(cmd.host_command_parameters, essid, ssid_len); - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to - * disable auto association -- so we cheat by setting a bogus SSID */ - if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) { - int i; - u8 *bogus = (u8 *) cmd.host_command_parameters; - for (i = 0; i < IW_ESSID_MAX_SIZE; i++) - bogus[i] = 0x18 + i; - cmd.host_command_length = IW_ESSID_MAX_SIZE; - } - - /* NOTE: We always send the SSID command even if the provided ESSID is - * the same as what we currently think is set. */ - - err = ipw2100_hw_send_command(priv, &cmd); - if (!err) { - memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len); - memcpy(priv->essid, essid, ssid_len); - priv->essid_len = ssid_len; - } - - if (!batch_mode) { - if (ipw2100_enable_adapter(priv)) - err = -EIO; - } - - return err; -} - -static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) -{ - DECLARE_SSID_BUF(ssid); - - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %pM \n", - print_ssid(ssid, priv->essid, priv->essid_len), - priv->bssid); - - priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); - - if (priv->status & STATUS_STOPPING) { - IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n"); - return; - } - - memset(priv->bssid, 0, ETH_ALEN); - memset(priv->ieee->bssid, 0, ETH_ALEN); - - netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); - - if (!(priv->status & STATUS_RUNNING)) - return; - - if (priv->status & STATUS_SECURITY_UPDATED) - queue_delayed_work(priv->workqueue, &priv->security_work, 0); - - queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0); -} - -static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) -{ - IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n", - priv->net_dev->name); - - /* RF_KILL is now enabled (else we wouldn't be here) */ - priv->status |= STATUS_RF_KILL_HW; - - /* Make sure the RF Kill check timer is running */ - priv->stop_rf_kill = 0; - cancel_delayed_work(&priv->rf_kill); - queue_delayed_work(priv->workqueue, &priv->rf_kill, - round_jiffies_relative(HZ)); -} - -static void send_scan_event(void *data) -{ - struct ipw2100_priv *priv = data; - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); -} - -static void ipw2100_scan_event_later(struct work_struct *work) -{ - send_scan_event(container_of(work, struct ipw2100_priv, - scan_event_later.work)); -} - -static void ipw2100_scan_event_now(struct work_struct *work) -{ - send_scan_event(container_of(work, struct ipw2100_priv, - scan_event_now)); -} - -static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) -{ - IPW_DEBUG_SCAN("scan complete\n"); - /* Age the scan results... */ - priv->ieee->scans++; - priv->status &= ~STATUS_SCANNING; - - /* Only userspace-requested scan completion events go out immediately */ - if (!priv->user_requested_scan) { - if (!delayed_work_pending(&priv->scan_event_later)) - queue_delayed_work(priv->workqueue, - &priv->scan_event_later, - round_jiffies_relative(msecs_to_jiffies(4000))); - } else { - priv->user_requested_scan = 0; - cancel_delayed_work(&priv->scan_event_later); - queue_work(priv->workqueue, &priv->scan_event_now); - } -} - -#ifdef CONFIG_IPW2100_DEBUG -#define IPW2100_HANDLER(v, f) { v, f, # v } -struct ipw2100_status_indicator { - int status; - void (*cb) (struct ipw2100_priv * priv, u32 status); - char *name; -}; -#else -#define IPW2100_HANDLER(v, f) { v, f } -struct ipw2100_status_indicator { - int status; - void (*cb) (struct ipw2100_priv * priv, u32 status); -}; -#endif /* CONFIG_IPW2100_DEBUG */ - -static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status) -{ - IPW_DEBUG_SCAN("Scanning...\n"); - priv->status |= STATUS_SCANNING; -} - -static const struct ipw2100_status_indicator status_handlers[] = { - IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL), - IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL), - IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated), - IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost), - IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL), - IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete), - IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL), - IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL), - IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill), - IPW2100_HANDLER(IPW_STATE_DISABLED, NULL), - IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL), - IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning), - IPW2100_HANDLER(-1, NULL) -}; - -static void isr_status_change(struct ipw2100_priv *priv, int status) -{ - int i; - - if (status == IPW_STATE_SCANNING && - priv->status & STATUS_ASSOCIATED && - !(priv->status & STATUS_SCANNING)) { - IPW_DEBUG_INFO("Scan detected while associated, with " - "no scan request. Restarting firmware.\n"); - - /* Wake up any sleeping jobs */ - schedule_reset(priv); - } - - for (i = 0; status_handlers[i].status != -1; i++) { - if (status == status_handlers[i].status) { - IPW_DEBUG_NOTIF("Status change: %s\n", - status_handlers[i].name); - if (status_handlers[i].cb) - status_handlers[i].cb(priv, status); - priv->wstats.status = status; - return; - } - } - - IPW_DEBUG_NOTIF("unknown status received: %04x\n", status); -} - -static void isr_rx_complete_command(struct ipw2100_priv *priv, - struct ipw2100_cmd_header *cmd) -{ -#ifdef CONFIG_IPW2100_DEBUG - if (cmd->host_command_reg < ARRAY_SIZE(command_types)) { - IPW_DEBUG_HC("Command completed '%s (%d)'\n", - command_types[cmd->host_command_reg], - cmd->host_command_reg); - } -#endif - if (cmd->host_command_reg == HOST_COMPLETE) - priv->status |= STATUS_ENABLED; - - if (cmd->host_command_reg == CARD_DISABLE) - priv->status &= ~STATUS_ENABLED; - - priv->status &= ~STATUS_CMD_ACTIVE; - - wake_up_interruptible(&priv->wait_command_queue); -} - -#ifdef CONFIG_IPW2100_DEBUG -static const char *frame_types[] = { - "COMMAND_STATUS_VAL", - "STATUS_CHANGE_VAL", - "P80211_DATA_VAL", - "P8023_DATA_VAL", - "HOST_NOTIFICATION_VAL" -}; -#endif - -static int ipw2100_alloc_skb(struct ipw2100_priv *priv, - struct ipw2100_rx_packet *packet) -{ - packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx)); - if (!packet->skb) - return -ENOMEM; - - packet->rxp = (struct ipw2100_rx *)packet->skb->data; - packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, - sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); - /* NOTE: pci_map_single does not return an error code, and 0 is a valid - * dma_addr */ - - return 0; -} - -#define SEARCH_ERROR 0xffffffff -#define SEARCH_FAIL 0xfffffffe -#define SEARCH_SUCCESS 0xfffffff0 -#define SEARCH_DISCARD 0 -#define SEARCH_SNAPSHOT 1 - -#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff)) -static void ipw2100_snapshot_free(struct ipw2100_priv *priv) -{ - int i; - if (!priv->snapshot[0]) - return; - for (i = 0; i < 0x30; i++) - kfree(priv->snapshot[i]); - priv->snapshot[0] = NULL; -} - -#ifdef IPW2100_DEBUG_C3 -static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv) -{ - int i; - if (priv->snapshot[0]) - return 1; - for (i = 0; i < 0x30; i++) { - priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC); - if (!priv->snapshot[i]) { - IPW_DEBUG_INFO("%s: Error allocating snapshot " - "buffer %d\n", priv->net_dev->name, i); - while (i > 0) - kfree(priv->snapshot[--i]); - priv->snapshot[0] = NULL; - return 0; - } - } - - return 1; -} - -static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, - size_t len, int mode) -{ - u32 i, j; - u32 tmp; - u8 *s, *d; - u32 ret; - - s = in_buf; - if (mode == SEARCH_SNAPSHOT) { - if (!ipw2100_snapshot_alloc(priv)) - mode = SEARCH_DISCARD; - } - - for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) { - read_nic_dword(priv->net_dev, i, &tmp); - if (mode == SEARCH_SNAPSHOT) - *(u32 *) SNAPSHOT_ADDR(i) = tmp; - if (ret == SEARCH_FAIL) { - d = (u8 *) & tmp; - for (j = 0; j < 4; j++) { - if (*s != *d) { - s = in_buf; - continue; - } - - s++; - d++; - - if ((s - in_buf) == len) - ret = (i + j) - len + 1; - } - } else if (mode == SEARCH_DISCARD) - return ret; - } - - return ret; -} -#endif - -/* - * - * 0) Disconnect the SKB from the firmware (just unmap) - * 1) Pack the ETH header into the SKB - * 2) Pass the SKB to the network stack - * - * When packet is provided by the firmware, it contains the following: - * - * . ieee80211_hdr - * . ieee80211_snap_hdr - * - * The size of the constructed ethernet - * - */ -#ifdef IPW2100_RX_DEBUG -static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH]; -#endif - -static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) -{ -#ifdef IPW2100_DEBUG_C3 - struct ipw2100_status *status = &priv->status_queue.drv[i]; - u32 match, reg; - int j; -#endif - - IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n", - i * sizeof(struct ipw2100_status)); - -#ifdef IPW2100_DEBUG_C3 - /* Halt the fimrware so we can get a good image */ - write_register(priv->net_dev, IPW_REG_RESET_REG, - IPW_AUX_HOST_RESET_REG_STOP_MASTER); - j = 5; - do { - udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); - read_register(priv->net_dev, IPW_REG_RESET_REG, ®); - - if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) - break; - } while (j--); - - match = ipw2100_match_buf(priv, (u8 *) status, - sizeof(struct ipw2100_status), - SEARCH_SNAPSHOT); - if (match < SEARCH_SUCCESS) - IPW_DEBUG_INFO("%s: DMA status match in Firmware at " - "offset 0x%06X, length %d:\n", - priv->net_dev->name, match, - sizeof(struct ipw2100_status)); - else - IPW_DEBUG_INFO("%s: No DMA status match in " - "Firmware.\n", priv->net_dev->name); - - printk_buf((u8 *) priv->status_queue.drv, - sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH); -#endif - - priv->fatal_error = IPW2100_ERR_C3_CORRUPTION; - priv->ieee->stats.rx_errors++; - schedule_reset(priv); -} - -static void isr_rx(struct ipw2100_priv *priv, int i, - struct ieee80211_rx_stats *stats) -{ - struct ipw2100_status *status = &priv->status_queue.drv[i]; - struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; - - IPW_DEBUG_RX("Handler...\n"); - - if (unlikely(status->frame_size > skb_tailroom(packet->skb))) { - IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" - " Dropping.\n", - priv->net_dev->name, - status->frame_size, skb_tailroom(packet->skb)); - priv->ieee->stats.rx_errors++; - return; - } - - if (unlikely(!netif_running(priv->net_dev))) { - priv->ieee->stats.rx_errors++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); - return; - } - - if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && - !(priv->status & STATUS_ASSOCIATED))) { - IPW_DEBUG_DROP("Dropping packet while not associated.\n"); - priv->wstats.discard.misc++; - return; - } - - pci_unmap_single(priv->pci_dev, - packet->dma_addr, - sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); - - skb_put(packet->skb, status->frame_size); - -#ifdef IPW2100_RX_DEBUG - /* Make a copy of the frame so we can dump it to the logs if - * ieee80211_rx fails */ - skb_copy_from_linear_data(packet->skb, packet_data, - min_t(u32, status->frame_size, - IPW_RX_NIC_BUFFER_LENGTH)); -#endif - - if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { -#ifdef IPW2100_RX_DEBUG - IPW_DEBUG_DROP("%s: Non consumed packet:\n", - priv->net_dev->name); - printk_buf(IPW_DL_DROP, packet_data, status->frame_size); -#endif - priv->ieee->stats.rx_errors++; - - /* ieee80211_rx failed, so it didn't free the SKB */ - dev_kfree_skb_any(packet->skb); - packet->skb = NULL; - } - - /* We need to allocate a new SKB and attach it to the RDB. */ - if (unlikely(ipw2100_alloc_skb(priv, packet))) { - printk(KERN_WARNING DRV_NAME ": " - "%s: Unable to allocate SKB onto RBD ring - disabling " - "adapter.\n", priv->net_dev->name); - /* TODO: schedule adapter shutdown */ - IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); - } - - /* Update the RDB entry */ - priv->rx_queue.drv[i].host_addr = packet->dma_addr; -} - -#ifdef CONFIG_IPW2100_MONITOR - -static void isr_rx_monitor(struct ipw2100_priv *priv, int i, - struct ieee80211_rx_stats *stats) -{ - struct ipw2100_status *status = &priv->status_queue.drv[i]; - struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; - - /* Magic struct that slots into the radiotap header -- no reason - * to build this manually element by element, we can write it much - * more efficiently than we can parse it. ORDER MATTERS HERE */ - struct ipw_rt_hdr { - struct ieee80211_radiotap_header rt_hdr; - s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ - } *ipw_rt; - - IPW_DEBUG_RX("Handler...\n"); - - if (unlikely(status->frame_size > skb_tailroom(packet->skb) - - sizeof(struct ipw_rt_hdr))) { - IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" - " Dropping.\n", - priv->net_dev->name, - status->frame_size, - skb_tailroom(packet->skb)); - priv->ieee->stats.rx_errors++; - return; - } - - if (unlikely(!netif_running(priv->net_dev))) { - priv->ieee->stats.rx_errors++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); - return; - } - - if (unlikely(priv->config & CFG_CRC_CHECK && - status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { - IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); - priv->ieee->stats.rx_errors++; - return; - } - - pci_unmap_single(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); - memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), - packet->skb->data, status->frame_size); - - ipw_rt = (struct ipw_rt_hdr *) packet->skb->data; - - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */ - - ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); - - ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM; - - skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); - - if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { - priv->ieee->stats.rx_errors++; - - /* ieee80211_rx failed, so it didn't free the SKB */ - dev_kfree_skb_any(packet->skb); - packet->skb = NULL; - } - - /* We need to allocate a new SKB and attach it to the RDB. */ - if (unlikely(ipw2100_alloc_skb(priv, packet))) { - IPW_DEBUG_WARNING( - "%s: Unable to allocate SKB onto RBD ring - disabling " - "adapter.\n", priv->net_dev->name); - /* TODO: schedule adapter shutdown */ - IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); - } - - /* Update the RDB entry */ - priv->rx_queue.drv[i].host_addr = packet->dma_addr; -} - -#endif - -static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) -{ - struct ipw2100_status *status = &priv->status_queue.drv[i]; - struct ipw2100_rx *u = priv->rx_buffers[i].rxp; - u16 frame_type = status->status_fields & STATUS_TYPE_MASK; - - switch (frame_type) { - case COMMAND_STATUS_VAL: - return (status->frame_size != sizeof(u->rx_data.command)); - case STATUS_CHANGE_VAL: - return (status->frame_size != sizeof(u->rx_data.status)); - case HOST_NOTIFICATION_VAL: - return (status->frame_size < sizeof(u->rx_data.notification)); - case P80211_DATA_VAL: - case P8023_DATA_VAL: -#ifdef CONFIG_IPW2100_MONITOR - return 0; -#else - switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { - case IEEE80211_FTYPE_MGMT: - case IEEE80211_FTYPE_CTL: - return 0; - case IEEE80211_FTYPE_DATA: - return (status->frame_size > - IPW_MAX_802_11_PAYLOAD_LENGTH); - } -#endif - } - - return 1; -} - -/* - * ipw2100 interrupts are disabled at this point, and the ISR - * is the only code that calls this method. So, we do not need - * to play with any locks. - * - * RX Queue works as follows: - * - * Read index - firmware places packet in entry identified by the - * Read index and advances Read index. In this manner, - * Read index will always point to the next packet to - * be filled--but not yet valid. - * - * Write index - driver fills this entry with an unused RBD entry. - * This entry has not filled by the firmware yet. - * - * In between the W and R indexes are the RBDs that have been received - * but not yet processed. - * - * The process of handling packets will start at WRITE + 1 and advance - * until it reaches the READ index. - * - * The WRITE index is cached in the variable 'priv->rx_queue.next'. - * - */ -static void __ipw2100_rx_process(struct ipw2100_priv *priv) -{ - struct ipw2100_bd_queue *rxq = &priv->rx_queue; - struct ipw2100_status_queue *sq = &priv->status_queue; - struct ipw2100_rx_packet *packet; - u16 frame_type; - u32 r, w, i, s; - struct ipw2100_rx *u; - struct ieee80211_rx_stats stats = { - .mac_time = jiffies, - }; - - read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r); - read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w); - - if (r >= rxq->entries) { - IPW_DEBUG_RX("exit - bad read index\n"); - return; - } - - i = (rxq->next + 1) % rxq->entries; - s = i; - while (i != r) { - /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n", - r, rxq->next, i); */ - - packet = &priv->rx_buffers[i]; - - /* Sync the DMA for the STATUS buffer so CPU is sure to get - * the correct values */ - pci_dma_sync_single_for_cpu(priv->pci_dev, - sq->nic + - sizeof(struct ipw2100_status) * i, - sizeof(struct ipw2100_status), - PCI_DMA_FROMDEVICE); - - /* Sync the DMA for the RX buffer so CPU is sure to get - * the correct values */ - pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); - - if (unlikely(ipw2100_corruption_check(priv, i))) { - ipw2100_corruption_detected(priv, i); - goto increment; - } - - u = packet->rxp; - frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK; - stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM; - stats.len = sq->drv[i].frame_size; - - stats.mask = 0; - if (stats.rssi != 0) - stats.mask |= IEEE80211_STATMASK_RSSI; - stats.freq = IEEE80211_24GHZ_BAND; - - IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n", - priv->net_dev->name, frame_types[frame_type], - stats.len); - - switch (frame_type) { - case COMMAND_STATUS_VAL: - /* Reset Rx watchdog */ - isr_rx_complete_command(priv, &u->rx_data.command); - break; - - case STATUS_CHANGE_VAL: - isr_status_change(priv, u->rx_data.status); - break; - - case P80211_DATA_VAL: - case P8023_DATA_VAL: -#ifdef CONFIG_IPW2100_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - isr_rx_monitor(priv, i, &stats); - break; - } -#endif - if (stats.len < sizeof(struct ieee80211_hdr_3addr)) - break; - switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { - case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(priv->ieee, - &u->rx_data.header, &stats); - break; - - case IEEE80211_FTYPE_CTL: - break; - - case IEEE80211_FTYPE_DATA: - isr_rx(priv, i, &stats); - break; - - } - break; - } - - increment: - /* clear status field associated with this RBD */ - rxq->drv[i].status.info.field = 0; - - i = (i + 1) % rxq->entries; - } - - if (i != s) { - /* backtrack one entry, wrapping to end if at 0 */ - rxq->next = (i ? i : rxq->entries) - 1; - - write_register(priv->net_dev, - IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next); - } -} - -/* - * __ipw2100_tx_process - * - * This routine will determine whether the next packet on - * the fw_pend_list has been processed by the firmware yet. - * - * If not, then it does nothing and returns. - * - * If so, then it removes the item from the fw_pend_list, frees - * any associated storage, and places the item back on the - * free list of its source (either msg_free_list or tx_free_list) - * - * TX Queue works as follows: - * - * Read index - points to the next TBD that the firmware will - * process. The firmware will read the data, and once - * done processing, it will advance the Read index. - * - * Write index - driver fills this entry with an constructed TBD - * entry. The Write index is not advanced until the - * packet has been configured. - * - * In between the W and R indexes are the TBDs that have NOT been - * processed. Lagging behind the R index are packets that have - * been processed but have not been freed by the driver. - * - * In order to free old storage, an internal index will be maintained - * that points to the next packet to be freed. When all used - * packets have been freed, the oldest index will be the same as the - * firmware's read index. - * - * The OLDEST index is cached in the variable 'priv->tx_queue.oldest' - * - * Because the TBD structure can not contain arbitrary data, the - * driver must keep an internal queue of cached allocations such that - * it can put that data back into the tx_free_list and msg_free_list - * for use by future command and data packets. - * - */ -static int __ipw2100_tx_process(struct ipw2100_priv *priv) -{ - struct ipw2100_bd_queue *txq = &priv->tx_queue; - struct ipw2100_bd *tbd; - struct list_head *element; - struct ipw2100_tx_packet *packet; - int descriptors_used; - int e, i; - u32 r, w, frag_num = 0; - - if (list_empty(&priv->fw_pend_list)) - return 0; - - element = priv->fw_pend_list.next; - - packet = list_entry(element, struct ipw2100_tx_packet, list); - tbd = &txq->drv[packet->index]; - - /* Determine how many TBD entries must be finished... */ - switch (packet->type) { - case COMMAND: - /* COMMAND uses only one slot; don't advance */ - descriptors_used = 1; - e = txq->oldest; - break; - - case DATA: - /* DATA uses two slots; advance and loop position. */ - descriptors_used = tbd->num_fragments; - frag_num = tbd->num_fragments - 1; - e = txq->oldest + frag_num; - e %= txq->entries; - break; - - default: - printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n", - priv->net_dev->name); - return 0; - } - - /* if the last TBD is not done by NIC yet, then packet is - * not ready to be released. - * - */ - read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX, - &r); - read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, - &w); - if (w != txq->next) - printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n", - priv->net_dev->name); - - /* - * txq->next is the index of the last packet written txq->oldest is - * the index of the r is the index of the next packet to be read by - * firmware - */ - - /* - * Quick graphic to help you visualize the following - * if / else statement - * - * ===>| s---->|=============== - * e>| - * | a | b | c | d | e | f | g | h | i | j | k | l - * r---->| - * w - * - * w - updated by driver - * r - updated by firmware - * s - start of oldest BD entry (txq->oldest) - * e - end of oldest BD entry - * - */ - if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) { - IPW_DEBUG_TX("exit - no processed packets ready to release.\n"); - return 0; - } - - list_del(element); - DEC_STAT(&priv->fw_pend_stat); - -#ifdef CONFIG_IPW2100_DEBUG - { - int i = txq->oldest; - IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, - &txq->drv[i], - (u32) (txq->nic + i * sizeof(struct ipw2100_bd)), - txq->drv[i].host_addr, txq->drv[i].buf_length); - - if (packet->type == DATA) { - i = (i + 1) % txq->entries; - - IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, - &txq->drv[i], - (u32) (txq->nic + i * - sizeof(struct ipw2100_bd)), - (u32) txq->drv[i].host_addr, - txq->drv[i].buf_length); - } - } -#endif - - switch (packet->type) { - case DATA: - if (txq->drv[txq->oldest].status.info.fields.txType != 0) - printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. " - "Expecting DATA TBD but pulled " - "something else: ids %d=%d.\n", - priv->net_dev->name, txq->oldest, packet->index); - - /* DATA packet; we have to unmap and free the SKB */ - for (i = 0; i < frag_num; i++) { - tbd = &txq->drv[(packet->index + 1 + i) % txq->entries]; - - IPW_DEBUG_TX("TX%d P=%08x L=%d\n", - (packet->index + 1 + i) % txq->entries, - tbd->host_addr, tbd->buf_length); - - pci_unmap_single(priv->pci_dev, - tbd->host_addr, - tbd->buf_length, PCI_DMA_TODEVICE); - } - - ieee80211_txb_free(packet->info.d_struct.txb); - packet->info.d_struct.txb = NULL; - - list_add_tail(element, &priv->tx_free_list); - INC_STAT(&priv->tx_free_stat); - - /* We have a free slot in the Tx queue, so wake up the - * transmit layer if it is stopped. */ - if (priv->status & STATUS_ASSOCIATED) - netif_wake_queue(priv->net_dev); - - /* A packet was processed by the hardware, so update the - * watchdog */ - priv->net_dev->trans_start = jiffies; - - break; - - case COMMAND: - if (txq->drv[txq->oldest].status.info.fields.txType != 1) - printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. " - "Expecting COMMAND TBD but pulled " - "something else: ids %d=%d.\n", - priv->net_dev->name, txq->oldest, packet->index); - -#ifdef CONFIG_IPW2100_DEBUG - if (packet->info.c_struct.cmd->host_command_reg < - ARRAY_SIZE(command_types)) - IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n", - command_types[packet->info.c_struct.cmd-> - host_command_reg], - packet->info.c_struct.cmd-> - host_command_reg, - packet->info.c_struct.cmd->cmd_status_reg); -#endif - - list_add_tail(element, &priv->msg_free_list); - INC_STAT(&priv->msg_free_stat); - break; - } - - /* advance oldest used TBD pointer to start of next entry */ - txq->oldest = (e + 1) % txq->entries; - /* increase available TBDs number */ - txq->available += descriptors_used; - SET_STAT(&priv->txq_stat, txq->available); - - IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n", - jiffies - packet->jiffy_start); - - return (!list_empty(&priv->fw_pend_list)); -} - -static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv) -{ - int i = 0; - - while (__ipw2100_tx_process(priv) && i < 200) - i++; - - if (i == 200) { - printk(KERN_WARNING DRV_NAME ": " - "%s: Driver is running slow (%d iters).\n", - priv->net_dev->name, i); - } -} - -static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) -{ - struct list_head *element; - struct ipw2100_tx_packet *packet; - struct ipw2100_bd_queue *txq = &priv->tx_queue; - struct ipw2100_bd *tbd; - int next = txq->next; - - while (!list_empty(&priv->msg_pend_list)) { - /* if there isn't enough space in TBD queue, then - * don't stuff a new one in. - * NOTE: 3 are needed as a command will take one, - * and there is a minimum of 2 that must be - * maintained between the r and w indexes - */ - if (txq->available <= 3) { - IPW_DEBUG_TX("no room in tx_queue\n"); - break; - } - - element = priv->msg_pend_list.next; - list_del(element); - DEC_STAT(&priv->msg_pend_stat); - - packet = list_entry(element, struct ipw2100_tx_packet, list); - - IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n", - &txq->drv[txq->next], - (void *)(txq->nic + txq->next * - sizeof(struct ipw2100_bd))); - - packet->index = txq->next; - - tbd = &txq->drv[txq->next]; - - /* initialize TBD */ - tbd->host_addr = packet->info.c_struct.cmd_phys; - tbd->buf_length = sizeof(struct ipw2100_cmd_header); - /* not marking number of fragments causes problems - * with f/w debug version */ - tbd->num_fragments = 1; - tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_COMMAND | - IPW_BD_STATUS_TX_INTERRUPT_ENABLE; - - /* update TBD queue counters */ - txq->next++; - txq->next %= txq->entries; - txq->available--; - DEC_STAT(&priv->txq_stat); - - list_add_tail(element, &priv->fw_pend_list); - INC_STAT(&priv->fw_pend_stat); - } - - if (txq->next != next) { - /* kick off the DMA by notifying firmware the - * write index has moved; make sure TBD stores are sync'd */ - wmb(); - write_register(priv->net_dev, - IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, - txq->next); - } -} - -/* - * ipw2100_tx_send_data - * - */ -static void ipw2100_tx_send_data(struct ipw2100_priv *priv) -{ - struct list_head *element; - struct ipw2100_tx_packet *packet; - struct ipw2100_bd_queue *txq = &priv->tx_queue; - struct ipw2100_bd *tbd; - int next = txq->next; - int i = 0; - struct ipw2100_data_header *ipw_hdr; - struct ieee80211_hdr_3addr *hdr; - - while (!list_empty(&priv->tx_pend_list)) { - /* if there isn't enough space in TBD queue, then - * don't stuff a new one in. - * NOTE: 4 are needed as a data will take two, - * and there is a minimum of 2 that must be - * maintained between the r and w indexes - */ - element = priv->tx_pend_list.next; - packet = list_entry(element, struct ipw2100_tx_packet, list); - - if (unlikely(1 + packet->info.d_struct.txb->nr_frags > - IPW_MAX_BDS)) { - /* TODO: Support merging buffers if more than - * IPW_MAX_BDS are used */ - IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. " - "Increase fragmentation level.\n", - priv->net_dev->name); - } - - if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) { - IPW_DEBUG_TX("no room in tx_queue\n"); - break; - } - - list_del(element); - DEC_STAT(&priv->tx_pend_stat); - - tbd = &txq->drv[txq->next]; - - packet->index = txq->next; - - ipw_hdr = packet->info.d_struct.data; - hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> - fragments[0]->data; - - if (priv->ieee->iw_mode == IW_MODE_INFRA) { - /* To DS: Addr1 = BSSID, Addr2 = SA, - Addr3 = DA */ - memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN); - memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN); - } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - /* not From/To DS: Addr1 = DA, Addr2 = SA, - Addr3 = BSSID */ - memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN); - memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN); - } - - ipw_hdr->host_command_reg = SEND; - ipw_hdr->host_command_reg1 = 0; - - /* For now we only support host based encryption */ - ipw_hdr->needs_encryption = 0; - ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted; - if (packet->info.d_struct.txb->nr_frags > 1) - ipw_hdr->fragment_size = - packet->info.d_struct.txb->frag_size - - IEEE80211_3ADDR_LEN; - else - ipw_hdr->fragment_size = 0; - - tbd->host_addr = packet->info.d_struct.data_phys; - tbd->buf_length = sizeof(struct ipw2100_data_header); - tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags; - tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_802_3 | - IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; - txq->next++; - txq->next %= txq->entries; - - IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n", - packet->index, tbd->host_addr, tbd->buf_length); -#ifdef CONFIG_IPW2100_DEBUG - if (packet->info.d_struct.txb->nr_frags > 1) - IPW_DEBUG_FRAG("fragment Tx: %d frames\n", - packet->info.d_struct.txb->nr_frags); -#endif - - for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) { - tbd = &txq->drv[txq->next]; - if (i == packet->info.d_struct.txb->nr_frags - 1) - tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_802_3 | - IPW_BD_STATUS_TX_INTERRUPT_ENABLE; - else - tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_802_3 | - IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; - - tbd->buf_length = packet->info.d_struct.txb-> - fragments[i]->len - IEEE80211_3ADDR_LEN; - - tbd->host_addr = pci_map_single(priv->pci_dev, - packet->info.d_struct. - txb->fragments[i]-> - data + - IEEE80211_3ADDR_LEN, - tbd->buf_length, - PCI_DMA_TODEVICE); - - IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n", - txq->next, tbd->host_addr, - tbd->buf_length); - - pci_dma_sync_single_for_device(priv->pci_dev, - tbd->host_addr, - tbd->buf_length, - PCI_DMA_TODEVICE); - - txq->next++; - txq->next %= txq->entries; - } - - txq->available -= 1 + packet->info.d_struct.txb->nr_frags; - SET_STAT(&priv->txq_stat, txq->available); - - list_add_tail(element, &priv->fw_pend_list); - INC_STAT(&priv->fw_pend_stat); - } - - if (txq->next != next) { - /* kick off the DMA by notifying firmware the - * write index has moved; make sure TBD stores are sync'd */ - write_register(priv->net_dev, - IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, - txq->next); - } - return; -} - -static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) -{ - struct net_device *dev = priv->net_dev; - unsigned long flags; - u32 inta, tmp; - - spin_lock_irqsave(&priv->low_lock, flags); - ipw2100_disable_interrupts(priv); - - read_register(dev, IPW_REG_INTA, &inta); - - IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n", - (unsigned long)inta & IPW_INTERRUPT_MASK); - - priv->in_isr++; - priv->interrupts++; - - /* We do not loop and keep polling for more interrupts as this - * is frowned upon and doesn't play nicely with other potentially - * chained IRQs */ - IPW_DEBUG_ISR("INTA: 0x%08lX\n", - (unsigned long)inta & IPW_INTERRUPT_MASK); - - if (inta & IPW2100_INTA_FATAL_ERROR) { - printk(KERN_WARNING DRV_NAME - ": Fatal interrupt. Scheduling firmware restart.\n"); - priv->inta_other++; - write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR); - - read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error); - IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n", - priv->net_dev->name, priv->fatal_error); - - read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp); - IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n", - priv->net_dev->name, tmp); - - /* Wake up any sleeping jobs */ - schedule_reset(priv); - } - - if (inta & IPW2100_INTA_PARITY_ERROR) { - printk(KERN_ERR DRV_NAME - ": ***** PARITY ERROR INTERRUPT !!!! \n"); - priv->inta_other++; - write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR); - } - - if (inta & IPW2100_INTA_RX_TRANSFER) { - IPW_DEBUG_ISR("RX interrupt\n"); - - priv->rx_interrupts++; - - write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER); - - __ipw2100_rx_process(priv); - __ipw2100_tx_complete(priv); - } - - if (inta & IPW2100_INTA_TX_TRANSFER) { - IPW_DEBUG_ISR("TX interrupt\n"); - - priv->tx_interrupts++; - - write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER); - - __ipw2100_tx_complete(priv); - ipw2100_tx_send_commands(priv); - ipw2100_tx_send_data(priv); - } - - if (inta & IPW2100_INTA_TX_COMPLETE) { - IPW_DEBUG_ISR("TX complete\n"); - priv->inta_other++; - write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE); - - __ipw2100_tx_complete(priv); - } - - if (inta & IPW2100_INTA_EVENT_INTERRUPT) { - /* ipw2100_handle_event(dev); */ - priv->inta_other++; - write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT); - } - - if (inta & IPW2100_INTA_FW_INIT_DONE) { - IPW_DEBUG_ISR("FW init done interrupt\n"); - priv->inta_other++; - - read_register(dev, IPW_REG_INTA, &tmp); - if (tmp & (IPW2100_INTA_FATAL_ERROR | - IPW2100_INTA_PARITY_ERROR)) { - write_register(dev, IPW_REG_INTA, - IPW2100_INTA_FATAL_ERROR | - IPW2100_INTA_PARITY_ERROR); - } - - write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE); - } - - if (inta & IPW2100_INTA_STATUS_CHANGE) { - IPW_DEBUG_ISR("Status change interrupt\n"); - priv->inta_other++; - write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE); - } - - if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) { - IPW_DEBUG_ISR("slave host mode interrupt\n"); - priv->inta_other++; - write_register(dev, IPW_REG_INTA, - IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE); - } - - priv->in_isr--; - ipw2100_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->low_lock, flags); - - IPW_DEBUG_ISR("exit\n"); -} - -static irqreturn_t ipw2100_interrupt(int irq, void *data) -{ - struct ipw2100_priv *priv = data; - u32 inta, inta_mask; - - if (!data) - return IRQ_NONE; - - spin_lock(&priv->low_lock); - - /* We check to see if we should be ignoring interrupts before - * we touch the hardware. During ucode load if we try and handle - * an interrupt we can cause keyboard problems as well as cause - * the ucode to fail to initialize */ - if (!(priv->status & STATUS_INT_ENABLED)) { - /* Shared IRQ */ - goto none; - } - - read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); - read_register(priv->net_dev, IPW_REG_INTA, &inta); - - if (inta == 0xFFFFFFFF) { - /* Hardware disappeared */ - printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n"); - goto none; - } - - inta &= IPW_INTERRUPT_MASK; - - if (!(inta & inta_mask)) { - /* Shared interrupt */ - goto none; - } - - /* We disable the hardware interrupt here just to prevent unneeded - * calls to be made. We disable this again within the actual - * work tasklet, so if another part of the code re-enables the - * interrupt, that is fine */ - ipw2100_disable_interrupts(priv); - - tasklet_schedule(&priv->irq_tasklet); - spin_unlock(&priv->low_lock); - - return IRQ_HANDLED; - none: - spin_unlock(&priv->low_lock); - return IRQ_NONE; -} - -static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, - int pri) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct list_head *element; - struct ipw2100_tx_packet *packet; - unsigned long flags; - - spin_lock_irqsave(&priv->low_lock, flags); - - if (!(priv->status & STATUS_ASSOCIATED)) { - IPW_DEBUG_INFO("Can not transmit when not connected.\n"); - priv->ieee->stats.tx_carrier_errors++; - netif_stop_queue(dev); - goto fail_unlock; - } - - if (list_empty(&priv->tx_free_list)) - goto fail_unlock; - - element = priv->tx_free_list.next; - packet = list_entry(element, struct ipw2100_tx_packet, list); - - packet->info.d_struct.txb = txb; - - IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len); - printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len); - - packet->jiffy_start = jiffies; - - list_del(element); - DEC_STAT(&priv->tx_free_stat); - - list_add_tail(element, &priv->tx_pend_list); - INC_STAT(&priv->tx_pend_stat); - - ipw2100_tx_send_data(priv); - - spin_unlock_irqrestore(&priv->low_lock, flags); - return 0; - - fail_unlock: - netif_stop_queue(dev); - spin_unlock_irqrestore(&priv->low_lock, flags); - return 1; -} - -static int ipw2100_msg_allocate(struct ipw2100_priv *priv) -{ - int i, j, err = -EINVAL; - void *v; - dma_addr_t p; - - priv->msg_buffers = - (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE * - sizeof(struct - ipw2100_tx_packet), - GFP_KERNEL); - if (!priv->msg_buffers) { - printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg " - "buffers.\n", priv->net_dev->name); - return -ENOMEM; - } - - for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - v = pci_alloc_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), &p); - if (!v) { - printk(KERN_ERR DRV_NAME ": " - "%s: PCI alloc failed for msg " - "buffers.\n", priv->net_dev->name); - err = -ENOMEM; - break; - } - - memset(v, 0, sizeof(struct ipw2100_cmd_header)); - - priv->msg_buffers[i].type = COMMAND; - priv->msg_buffers[i].info.c_struct.cmd = - (struct ipw2100_cmd_header *)v; - priv->msg_buffers[i].info.c_struct.cmd_phys = p; - } - - if (i == IPW_COMMAND_POOL_SIZE) - return 0; - - for (j = 0; j < i; j++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[j].info.c_struct.cmd, - priv->msg_buffers[j].info.c_struct. - cmd_phys); - } - - kfree(priv->msg_buffers); - priv->msg_buffers = NULL; - - return err; -} - -static int ipw2100_msg_initialize(struct ipw2100_priv *priv) -{ - int i; - - INIT_LIST_HEAD(&priv->msg_free_list); - INIT_LIST_HEAD(&priv->msg_pend_list); - - for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) - list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list); - SET_STAT(&priv->msg_free_stat, i); - - return 0; -} - -static void ipw2100_msg_free(struct ipw2100_priv *priv) -{ - int i; - - if (!priv->msg_buffers) - return; - - for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[i].info.c_struct.cmd, - priv->msg_buffers[i].info.c_struct. - cmd_phys); - } - - kfree(priv->msg_buffers); - priv->msg_buffers = NULL; -} - -static ssize_t show_pci(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev); - char *out = buf; - int i, j; - u32 val; - - for (i = 0; i < 16; i++) { - out += sprintf(out, "[%08X] ", i * 16); - for (j = 0; j < 16; j += 4) { - pci_read_config_dword(pci_dev, i * 16 + j, &val); - out += sprintf(out, "%08X ", val); - } - out += sprintf(out, "\n"); - } - - return out - buf; -} - -static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); - -static ssize_t show_cfg(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *p = d->driver_data; - return sprintf(buf, "0x%08x\n", (int)p->config); -} - -static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); - -static ssize_t show_status(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *p = d->driver_data; - return sprintf(buf, "0x%08x\n", (int)p->status); -} - -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); - -static ssize_t show_capability(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *p = d->driver_data; - return sprintf(buf, "0x%08x\n", (int)p->capability); -} - -static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL); - -#define IPW2100_REG(x) { IPW_ ##x, #x } -static const struct { - u32 addr; - const char *name; -} hw_data[] = { -IPW2100_REG(REG_GP_CNTRL), - IPW2100_REG(REG_GPIO), - IPW2100_REG(REG_INTA), - IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),}; -#define IPW2100_NIC(x, s) { x, #x, s } -static const struct { - u32 addr; - const char *name; - size_t size; -} nic_data[] = { -IPW2100_NIC(IPW2100_CONTROL_REG, 2), - IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),}; -#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d } -static const struct { - u8 index; - const char *name; - const char *desc; -} ord_data[] = { -IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), - IPW2100_ORD(STAT_TX_HOST_COMPLETE, - "successful Host Tx's (MSDU)"), - IPW2100_ORD(STAT_TX_DIR_DATA, - "successful Directed Tx's (MSDU)"), - IPW2100_ORD(STAT_TX_DIR_DATA1, - "successful Directed Tx's (MSDU) @ 1MB"), - IPW2100_ORD(STAT_TX_DIR_DATA2, - "successful Directed Tx's (MSDU) @ 2MB"), - IPW2100_ORD(STAT_TX_DIR_DATA5_5, - "successful Directed Tx's (MSDU) @ 5_5MB"), - IPW2100_ORD(STAT_TX_DIR_DATA11, - "successful Directed Tx's (MSDU) @ 11MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA1, - "successful Non_Directed Tx's (MSDU) @ 1MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA2, - "successful Non_Directed Tx's (MSDU) @ 2MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA5_5, - "successful Non_Directed Tx's (MSDU) @ 5.5MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA11, - "successful Non_Directed Tx's (MSDU) @ 11MB"), - IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"), - IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"), - IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"), - IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"), - IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"), - IPW2100_ORD(STAT_TX_ASSN_RESP, - "successful Association response Tx's"), - IPW2100_ORD(STAT_TX_REASSN, - "successful Reassociation Tx's"), - IPW2100_ORD(STAT_TX_REASSN_RESP, - "successful Reassociation response Tx's"), - IPW2100_ORD(STAT_TX_PROBE, - "probes successfully transmitted"), - IPW2100_ORD(STAT_TX_PROBE_RESP, - "probe responses successfully transmitted"), - IPW2100_ORD(STAT_TX_BEACON, "tx beacon"), - IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"), - IPW2100_ORD(STAT_TX_DISASSN, - "successful Disassociation TX"), - IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"), - IPW2100_ORD(STAT_TX_DEAUTH, - "successful Deauthentication TX"), - IPW2100_ORD(STAT_TX_TOTAL_BYTES, - "Total successful Tx data bytes"), - IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"), - IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"), - IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"), - IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"), - IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"), - IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"), - IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP, - "times max tries in a hop failed"), - IPW2100_ORD(STAT_TX_DISASSN_FAIL, - "times disassociation failed"), - IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"), - IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"), - IPW2100_ORD(STAT_RX_HOST, "packets passed to host"), - IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"), - IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"), - IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"), - IPW2100_ORD(STAT_RX_DIR_DATA5_5, - "directed packets at 5.5MB"), - IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"), - IPW2100_ORD(STAT_RX_NODIR_DATA1, - "nondirected packets at 1MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA2, - "nondirected packets at 2MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA5_5, - "nondirected packets at 5.5MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA11, - "nondirected packets at 11MB"), - IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"), - IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS, - "Rx CTS"), - IPW2100_ORD(STAT_RX_ACK, "Rx ACK"), - IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"), - IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"), - IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"), - IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"), - IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"), - IPW2100_ORD(STAT_RX_REASSN_RESP, - "Reassociation response Rx's"), - IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"), - IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"), - IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"), - IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"), - IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"), - IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"), - IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"), - IPW2100_ORD(STAT_RX_TOTAL_BYTES, - "Total rx data bytes received"), - IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"), - IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"), - IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"), - IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"), - IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"), - IPW2100_ORD(STAT_RX_DUPLICATE1, - "duplicate rx packets at 1MB"), - IPW2100_ORD(STAT_RX_DUPLICATE2, - "duplicate rx packets at 2MB"), - IPW2100_ORD(STAT_RX_DUPLICATE5_5, - "duplicate rx packets at 5.5MB"), - IPW2100_ORD(STAT_RX_DUPLICATE11, - "duplicate rx packets at 11MB"), - IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"), - IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"), - IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"), - IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"), - IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, - "rx frames with invalid protocol"), - IPW2100_ORD(SYS_BOOT_TIME, "Boot time"), - IPW2100_ORD(STAT_RX_NO_BUFFER, - "rx frames rejected due to no buffer"), - IPW2100_ORD(STAT_RX_MISSING_FRAG, - "rx frames dropped due to missing fragment"), - IPW2100_ORD(STAT_RX_ORPHAN_FRAG, - "rx frames dropped due to non-sequential fragment"), - IPW2100_ORD(STAT_RX_ORPHAN_FRAME, - "rx frames dropped due to unmatched 1st frame"), - IPW2100_ORD(STAT_RX_FRAG_AGEOUT, - "rx frames dropped due to uncompleted frame"), - IPW2100_ORD(STAT_RX_ICV_ERRORS, - "ICV errors during decryption"), - IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"), - IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"), - IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, - "poll response timeouts"), - IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, - "timeouts waiting for last {broad,multi}cast pkt"), - IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"), - IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"), - IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"), - IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"), - IPW2100_ORD(STAT_PERCENT_MISSED_BCNS, - "current calculation of % missed beacons"), - IPW2100_ORD(STAT_PERCENT_RETRIES, - "current calculation of % missed tx retries"), - IPW2100_ORD(ASSOCIATED_AP_PTR, - "0 if not associated, else pointer to AP table entry"), - IPW2100_ORD(AVAILABLE_AP_CNT, - "AP's decsribed in the AP table"), - IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"), - IPW2100_ORD(STAT_AP_ASSNS, "associations"), - IPW2100_ORD(STAT_ASSN_FAIL, "association failures"), - IPW2100_ORD(STAT_ASSN_RESP_FAIL, - "failures due to response fail"), - IPW2100_ORD(STAT_FULL_SCANS, "full scans"), - IPW2100_ORD(CARD_DISABLED, "Card Disabled"), - IPW2100_ORD(STAT_ROAM_INHIBIT, - "times roaming was inhibited due to activity"), - IPW2100_ORD(RSSI_AT_ASSN, - "RSSI of associated AP at time of association"), - IPW2100_ORD(STAT_ASSN_CAUSE1, - "reassociation: no probe response or TX on hop"), - IPW2100_ORD(STAT_ASSN_CAUSE2, - "reassociation: poor tx/rx quality"), - IPW2100_ORD(STAT_ASSN_CAUSE3, - "reassociation: tx/rx quality (excessive AP load"), - IPW2100_ORD(STAT_ASSN_CAUSE4, - "reassociation: AP RSSI level"), - IPW2100_ORD(STAT_ASSN_CAUSE5, - "reassociations due to load leveling"), - IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"), - IPW2100_ORD(STAT_AUTH_RESP_FAIL, - "times authentication response failed"), - IPW2100_ORD(STATION_TABLE_CNT, - "entries in association table"), - IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"), - IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"), - IPW2100_ORD(COUNTRY_CODE, - "IEEE country code as recv'd from beacon"), - IPW2100_ORD(COUNTRY_CHANNELS, - "channels suported by country"), - IPW2100_ORD(RESET_CNT, "adapter resets (warm)"), - IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"), - IPW2100_ORD(ANTENNA_DIVERSITY, - "TRUE if antenna diversity is disabled"), - IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"), - IPW2100_ORD(OUR_FREQ, - "current radio freq lower digits - channel ID"), - IPW2100_ORD(RTC_TIME, "current RTC time"), - IPW2100_ORD(PORT_TYPE, "operating mode"), - IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"), - IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"), - IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"), - IPW2100_ORD(BASIC_RATES, "basic tx rates"), - IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"), - IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"), - IPW2100_ORD(CAPABILITIES, - "Management frame capability field"), - IPW2100_ORD(AUTH_TYPE, "Type of authentication"), - IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"), - IPW2100_ORD(RTS_THRESHOLD, - "Min packet length for RTS handshaking"), - IPW2100_ORD(INT_MODE, "International mode"), - IPW2100_ORD(FRAGMENTATION_THRESHOLD, - "protocol frag threshold"), - IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, - "EEPROM offset in SRAM"), - IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, - "EEPROM size in SRAM"), - IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"), - IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, - "EEPROM IBSS 11b channel set"), - IPW2100_ORD(MAC_VERSION, "MAC Version"), - IPW2100_ORD(MAC_REVISION, "MAC Revision"), - IPW2100_ORD(RADIO_VERSION, "Radio Version"), - IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"), - IPW2100_ORD(UCODE_VERSION, "Ucode Version"),}; - -static ssize_t show_registers(struct device *d, struct device_attribute *attr, - char *buf) -{ - int i; - struct ipw2100_priv *priv = dev_get_drvdata(d); - struct net_device *dev = priv->net_dev; - char *out = buf; - u32 val = 0; - - out += sprintf(out, "%30s [Address ] : Hex\n", "Register"); - - for (i = 0; i < ARRAY_SIZE(hw_data); i++) { - read_register(dev, hw_data[i].addr, &val); - out += sprintf(out, "%30s [%08X] : %08X\n", - hw_data[i].name, hw_data[i].addr, val); - } - - return out - buf; -} - -static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); - -static ssize_t show_hardware(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - struct net_device *dev = priv->net_dev; - char *out = buf; - int i; - - out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry"); - - for (i = 0; i < ARRAY_SIZE(nic_data); i++) { - u8 tmp8; - u16 tmp16; - u32 tmp32; - - switch (nic_data[i].size) { - case 1: - read_nic_byte(dev, nic_data[i].addr, &tmp8); - out += sprintf(out, "%30s [%08X] : %02X\n", - nic_data[i].name, nic_data[i].addr, - tmp8); - break; - case 2: - read_nic_word(dev, nic_data[i].addr, &tmp16); - out += sprintf(out, "%30s [%08X] : %04X\n", - nic_data[i].name, nic_data[i].addr, - tmp16); - break; - case 4: - read_nic_dword(dev, nic_data[i].addr, &tmp32); - out += sprintf(out, "%30s [%08X] : %08X\n", - nic_data[i].name, nic_data[i].addr, - tmp32); - break; - } - } - return out - buf; -} - -static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL); - -static ssize_t show_memory(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - struct net_device *dev = priv->net_dev; - static unsigned long loop = 0; - int len = 0; - u32 buffer[4]; - int i; - char line[81]; - - if (loop >= 0x30000) - loop = 0; - - /* sysfs provides us PAGE_SIZE buffer */ - while (len < PAGE_SIZE - 128 && loop < 0x30000) { - - if (priv->snapshot[0]) - for (i = 0; i < 4; i++) - buffer[i] = - *(u32 *) SNAPSHOT_ADDR(loop + i * 4); - else - for (i = 0; i < 4; i++) - read_nic_dword(dev, loop + i * 4, &buffer[i]); - - if (priv->dump_raw) - len += sprintf(buf + len, - "%c%c%c%c" - "%c%c%c%c" - "%c%c%c%c" - "%c%c%c%c", - ((u8 *) buffer)[0x0], - ((u8 *) buffer)[0x1], - ((u8 *) buffer)[0x2], - ((u8 *) buffer)[0x3], - ((u8 *) buffer)[0x4], - ((u8 *) buffer)[0x5], - ((u8 *) buffer)[0x6], - ((u8 *) buffer)[0x7], - ((u8 *) buffer)[0x8], - ((u8 *) buffer)[0x9], - ((u8 *) buffer)[0xa], - ((u8 *) buffer)[0xb], - ((u8 *) buffer)[0xc], - ((u8 *) buffer)[0xd], - ((u8 *) buffer)[0xe], - ((u8 *) buffer)[0xf]); - else - len += sprintf(buf + len, "%s\n", - snprint_line(line, sizeof(line), - (u8 *) buffer, 16, loop)); - loop += 16; - } - - return len; -} - -static ssize_t store_memory(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - struct net_device *dev = priv->net_dev; - const char *p = buf; - - (void)dev; /* kill unused-var warning for debug-only code */ - - if (count < 1) - return count; - - if (p[0] == '1' || - (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) { - IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n", - dev->name); - priv->dump_raw = 1; - - } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' && - tolower(p[1]) == 'f')) { - IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n", - dev->name); - priv->dump_raw = 0; - - } else if (tolower(p[0]) == 'r') { - IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name); - ipw2100_snapshot_free(priv); - - } else - IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, " - "reset = clear memory snapshot\n", dev->name); - - return count; -} - -static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory); - -static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - u32 val = 0; - int len = 0; - u32 val_len; - static int loop = 0; - - if (priv->status & STATUS_RF_KILL_MASK) - return 0; - - if (loop >= ARRAY_SIZE(ord_data)) - loop = 0; - - /* sysfs provides us PAGE_SIZE buffer */ - while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) { - val_len = sizeof(u32); - - if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val, - &val_len)) - len += sprintf(buf + len, "[0x%02X] = ERROR %s\n", - ord_data[loop].index, - ord_data[loop].desc); - else - len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n", - ord_data[loop].index, val, - ord_data[loop].desc); - loop++; - } - - return len; -} - -static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL); - -static ssize_t show_stats(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - char *out = buf; - - out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n", - priv->interrupts, priv->tx_interrupts, - priv->rx_interrupts, priv->inta_other); - out += sprintf(out, "firmware resets: %d\n", priv->resets); - out += sprintf(out, "firmware hangs: %d\n", priv->hangs); -#ifdef CONFIG_IPW2100_DEBUG - out += sprintf(out, "packet mismatch image: %s\n", - priv->snapshot[0] ? "YES" : "NO"); -#endif - - return out - buf; -} - -static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); - -static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) -{ - int err; - - if (mode == priv->ieee->iw_mode) - return 0; - - err = ipw2100_disable_adapter(priv); - if (err) { - printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", - priv->net_dev->name, err); - return err; - } - - switch (mode) { - case IW_MODE_INFRA: - priv->net_dev->type = ARPHRD_ETHER; - break; - case IW_MODE_ADHOC: - priv->net_dev->type = ARPHRD_ETHER; - break; -#ifdef CONFIG_IPW2100_MONITOR - case IW_MODE_MONITOR: - priv->last_mode = priv->ieee->iw_mode; - priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; - break; -#endif /* CONFIG_IPW2100_MONITOR */ - } - - priv->ieee->iw_mode = mode; - -#ifdef CONFIG_PM - /* Indicate ipw2100_download_firmware download firmware - * from disk instead of memory. */ - ipw2100_firmware.version = 0; -#endif - - printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name); - priv->reset_backoff = 0; - schedule_reset(priv); - - return 0; -} - -static ssize_t show_internals(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - int len = 0; - -#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x) - - if (priv->status & STATUS_ASSOCIATED) - len += sprintf(buf + len, "connected: %lu\n", - get_seconds() - priv->connect_start); - else - len += sprintf(buf + len, "not connected\n"); - - DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p"); - DUMP_VAR(status, "08lx"); - DUMP_VAR(config, "08lx"); - DUMP_VAR(capability, "08lx"); - - len += - sprintf(buf + len, "last_rtc: %lu\n", - (unsigned long)priv->last_rtc); - - DUMP_VAR(fatal_error, "d"); - DUMP_VAR(stop_hang_check, "d"); - DUMP_VAR(stop_rf_kill, "d"); - DUMP_VAR(messages_sent, "d"); - - DUMP_VAR(tx_pend_stat.value, "d"); - DUMP_VAR(tx_pend_stat.hi, "d"); - - DUMP_VAR(tx_free_stat.value, "d"); - DUMP_VAR(tx_free_stat.lo, "d"); - - DUMP_VAR(msg_free_stat.value, "d"); - DUMP_VAR(msg_free_stat.lo, "d"); - - DUMP_VAR(msg_pend_stat.value, "d"); - DUMP_VAR(msg_pend_stat.hi, "d"); - - DUMP_VAR(fw_pend_stat.value, "d"); - DUMP_VAR(fw_pend_stat.hi, "d"); - - DUMP_VAR(txq_stat.value, "d"); - DUMP_VAR(txq_stat.lo, "d"); - - DUMP_VAR(ieee->scans, "d"); - DUMP_VAR(reset_backoff, "d"); - - return len; -} - -static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL); - -static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - char essid[IW_ESSID_MAX_SIZE + 1]; - u8 bssid[ETH_ALEN]; - u32 chan = 0; - char *out = buf; - int length; - int ret; - - if (priv->status & STATUS_RF_KILL_MASK) - return 0; - - memset(essid, 0, sizeof(essid)); - memset(bssid, 0, sizeof(bssid)); - - length = IW_ESSID_MAX_SIZE; - ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length); - if (ret) - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - - length = sizeof(bssid); - ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, - bssid, &length); - if (ret) - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - - length = sizeof(u32); - ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length); - if (ret) - IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); - - out += sprintf(out, "ESSID: %s\n", essid); - out += sprintf(out, "BSSID: %pM\n", bssid); - out += sprintf(out, "Channel: %d\n", chan); - - return out - buf; -} - -static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); - -#ifdef CONFIG_IPW2100_DEBUG -static ssize_t show_debug_level(struct device_driver *d, char *buf) -{ - return sprintf(buf, "0x%08X\n", ipw2100_debug_level); -} - -static ssize_t store_debug_level(struct device_driver *d, - const char *buf, size_t count) -{ - char *p = (char *)buf; - u32 val; - - if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { - p++; - if (p[0] == 'x' || p[0] == 'X') - p++; - val = simple_strtoul(p, &p, 16); - } else - val = simple_strtoul(p, &p, 10); - if (p == buf) - IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf); - else - ipw2100_debug_level = val; - - return strnlen(buf, count); -} - -static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, - store_debug_level); -#endif /* CONFIG_IPW2100_DEBUG */ - -static ssize_t show_fatal_error(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - char *out = buf; - int i; - - if (priv->fatal_error) - out += sprintf(out, "0x%08X\n", priv->fatal_error); - else - out += sprintf(out, "0\n"); - - for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) { - if (!priv->fatal_errors[(priv->fatal_index - i) % - IPW2100_ERROR_QUEUE]) - continue; - - out += sprintf(out, "%d. 0x%08X\n", i, - priv->fatal_errors[(priv->fatal_index - i) % - IPW2100_ERROR_QUEUE]); - } - - return out - buf; -} - -static ssize_t store_fatal_error(struct device *d, - struct device_attribute *attr, const char *buf, - size_t count) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - schedule_reset(priv); - return count; -} - -static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error, - store_fatal_error); - -static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%d\n", priv->ieee->scan_age); -} - -static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - struct net_device *dev = priv->net_dev; - char buffer[] = "00000000"; - unsigned long len = - (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; - unsigned long val; - char *p = buffer; - - (void)dev; /* kill unused-var warning for debug-only code */ - - IPW_DEBUG_INFO("enter\n"); - - strncpy(buffer, buf, len); - buffer[len] = 0; - - if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { - p++; - if (p[0] == 'x' || p[0] == 'X') - p++; - val = simple_strtoul(p, &p, 16); - } else - val = simple_strtoul(p, &p, 10); - if (p == buffer) { - IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); - } else { - priv->ieee->scan_age = val; - IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); - } - - IPW_DEBUG_INFO("exit\n"); - return len; -} - -static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); - -static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, - char *buf) -{ - /* 0 - RF kill not enabled - 1 - SW based RF kill active (sysfs) - 2 - HW based RF kill active - 3 - Both HW and SW baed RF kill active */ - struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data; - int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | - (rf_kill_active(priv) ? 0x2 : 0x0); - return sprintf(buf, "%i\n", val); -} - -static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) -{ - if ((disable_radio ? 1 : 0) == - (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) - return 0; - - IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", - disable_radio ? "OFF" : "ON"); - - mutex_lock(&priv->action_mutex); - - if (disable_radio) { - priv->status |= STATUS_RF_KILL_SW; - ipw2100_down(priv); - } else { - priv->status &= ~STATUS_RF_KILL_SW; - if (rf_kill_active(priv)) { - IPW_DEBUG_RF_KILL("Can not turn radio back on - " - "disabled by HW switch\n"); - /* Make sure the RF_KILL check timer is running */ - priv->stop_rf_kill = 0; - cancel_delayed_work(&priv->rf_kill); - queue_delayed_work(priv->workqueue, &priv->rf_kill, - round_jiffies_relative(HZ)); - } else - schedule_reset(priv); - } - - mutex_unlock(&priv->action_mutex); - return 1; -} - -static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw2100_priv *priv = dev_get_drvdata(d); - ipw_radio_kill_sw(priv, buf[0] == '1'); - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); - -static struct attribute *ipw2100_sysfs_entries[] = { - &dev_attr_hardware.attr, - &dev_attr_registers.attr, - &dev_attr_ordinals.attr, - &dev_attr_pci.attr, - &dev_attr_stats.attr, - &dev_attr_internals.attr, - &dev_attr_bssinfo.attr, - &dev_attr_memory.attr, - &dev_attr_scan_age.attr, - &dev_attr_fatal_error.attr, - &dev_attr_rf_kill.attr, - &dev_attr_cfg.attr, - &dev_attr_status.attr, - &dev_attr_capability.attr, - NULL, -}; - -static struct attribute_group ipw2100_attribute_group = { - .attrs = ipw2100_sysfs_entries, -}; - -static int status_queue_allocate(struct ipw2100_priv *priv, int entries) -{ - struct ipw2100_status_queue *q = &priv->status_queue; - - IPW_DEBUG_INFO("enter\n"); - - q->size = entries * sizeof(struct ipw2100_status); - q->drv = - (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev, - q->size, &q->nic); - if (!q->drv) { - IPW_DEBUG_WARNING("Can not allocate status queue.\n"); - return -ENOMEM; - } - - memset(q->drv, 0, q->size); - - IPW_DEBUG_INFO("exit\n"); - - return 0; -} - -static void status_queue_free(struct ipw2100_priv *priv) -{ - IPW_DEBUG_INFO("enter\n"); - - if (priv->status_queue.drv) { - pci_free_consistent(priv->pci_dev, priv->status_queue.size, - priv->status_queue.drv, - priv->status_queue.nic); - priv->status_queue.drv = NULL; - } - - IPW_DEBUG_INFO("exit\n"); -} - -static int bd_queue_allocate(struct ipw2100_priv *priv, - struct ipw2100_bd_queue *q, int entries) -{ - IPW_DEBUG_INFO("enter\n"); - - memset(q, 0, sizeof(struct ipw2100_bd_queue)); - - q->entries = entries; - q->size = entries * sizeof(struct ipw2100_bd); - q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic); - if (!q->drv) { - IPW_DEBUG_INFO - ("can't allocate shared memory for buffer descriptors\n"); - return -ENOMEM; - } - memset(q->drv, 0, q->size); - - IPW_DEBUG_INFO("exit\n"); - - return 0; -} - -static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q) -{ - IPW_DEBUG_INFO("enter\n"); - - if (!q) - return; - - if (q->drv) { - pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic); - q->drv = NULL; - } - - IPW_DEBUG_INFO("exit\n"); -} - -static void bd_queue_initialize(struct ipw2100_priv *priv, - struct ipw2100_bd_queue *q, u32 base, u32 size, - u32 r, u32 w) -{ - IPW_DEBUG_INFO("enter\n"); - - IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, - (u32) q->nic); - - write_register(priv->net_dev, base, q->nic); - write_register(priv->net_dev, size, q->entries); - write_register(priv->net_dev, r, q->oldest); - write_register(priv->net_dev, w, q->next); - - IPW_DEBUG_INFO("exit\n"); -} - -static void ipw2100_kill_workqueue(struct ipw2100_priv *priv) -{ - if (priv->workqueue) { - priv->stop_rf_kill = 1; - priv->stop_hang_check = 1; - cancel_delayed_work(&priv->reset_work); - cancel_delayed_work(&priv->security_work); - cancel_delayed_work(&priv->wx_event_work); - cancel_delayed_work(&priv->hang_check); - cancel_delayed_work(&priv->rf_kill); - cancel_delayed_work(&priv->scan_event_later); - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - } -} - -static int ipw2100_tx_allocate(struct ipw2100_priv *priv) -{ - int i, j, err = -EINVAL; - void *v; - dma_addr_t p; - - IPW_DEBUG_INFO("enter\n"); - - err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH); - if (err) { - IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n", - priv->net_dev->name); - return err; - } - - priv->tx_buffers = - (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH * - sizeof(struct - ipw2100_tx_packet), - GFP_ATOMIC); - if (!priv->tx_buffers) { - printk(KERN_ERR DRV_NAME - ": %s: alloc failed form tx buffers.\n", - priv->net_dev->name); - bd_queue_free(priv, &priv->tx_queue); - return -ENOMEM; - } - - for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { - v = pci_alloc_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - &p); - if (!v) { - printk(KERN_ERR DRV_NAME - ": %s: PCI alloc failed for tx " "buffers.\n", - priv->net_dev->name); - err = -ENOMEM; - break; - } - - priv->tx_buffers[i].type = DATA; - priv->tx_buffers[i].info.d_struct.data = - (struct ipw2100_data_header *)v; - priv->tx_buffers[i].info.d_struct.data_phys = p; - priv->tx_buffers[i].info.d_struct.txb = NULL; - } - - if (i == TX_PENDED_QUEUE_LENGTH) - return 0; - - for (j = 0; j < i; j++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[j].info.d_struct.data, - priv->tx_buffers[j].info.d_struct. - data_phys); - } - - kfree(priv->tx_buffers); - priv->tx_buffers = NULL; - - return err; -} - -static void ipw2100_tx_initialize(struct ipw2100_priv *priv) -{ - int i; - - IPW_DEBUG_INFO("enter\n"); - - /* - * reinitialize packet info lists - */ - INIT_LIST_HEAD(&priv->fw_pend_list); - INIT_STAT(&priv->fw_pend_stat); - - /* - * reinitialize lists - */ - INIT_LIST_HEAD(&priv->tx_pend_list); - INIT_LIST_HEAD(&priv->tx_free_list); - INIT_STAT(&priv->tx_pend_stat); - INIT_STAT(&priv->tx_free_stat); - - for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { - /* We simply drop any SKBs that have been queued for - * transmit */ - if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. - txb); - priv->tx_buffers[i].info.d_struct.txb = NULL; - } - - list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list); - } - - SET_STAT(&priv->tx_free_stat, i); - - priv->tx_queue.oldest = 0; - priv->tx_queue.available = priv->tx_queue.entries; - priv->tx_queue.next = 0; - INIT_STAT(&priv->txq_stat); - SET_STAT(&priv->txq_stat, priv->tx_queue.available); - - bd_queue_initialize(priv, &priv->tx_queue, - IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE, - IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE, - IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX, - IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX); - - IPW_DEBUG_INFO("exit\n"); - -} - -static void ipw2100_tx_free(struct ipw2100_priv *priv) -{ - int i; - - IPW_DEBUG_INFO("enter\n"); - - bd_queue_free(priv, &priv->tx_queue); - - if (!priv->tx_buffers) - return; - - for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { - if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. - txb); - priv->tx_buffers[i].info.d_struct.txb = NULL; - } - if (priv->tx_buffers[i].info.d_struct.data) - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[i].info.d_struct. - data, - priv->tx_buffers[i].info.d_struct. - data_phys); - } - - kfree(priv->tx_buffers); - priv->tx_buffers = NULL; - - IPW_DEBUG_INFO("exit\n"); -} - -static int ipw2100_rx_allocate(struct ipw2100_priv *priv) -{ - int i, j, err = -EINVAL; - - IPW_DEBUG_INFO("enter\n"); - - err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH); - if (err) { - IPW_DEBUG_INFO("failed bd_queue_allocate\n"); - return err; - } - - err = status_queue_allocate(priv, RX_QUEUE_LENGTH); - if (err) { - IPW_DEBUG_INFO("failed status_queue_allocate\n"); - bd_queue_free(priv, &priv->rx_queue); - return err; - } - - /* - * allocate packets - */ - priv->rx_buffers = (struct ipw2100_rx_packet *) - kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet), - GFP_KERNEL); - if (!priv->rx_buffers) { - IPW_DEBUG_INFO("can't allocate rx packet buffer table\n"); - - bd_queue_free(priv, &priv->rx_queue); - - status_queue_free(priv); - - return -ENOMEM; - } - - for (i = 0; i < RX_QUEUE_LENGTH; i++) { - struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; - - err = ipw2100_alloc_skb(priv, packet); - if (unlikely(err)) { - err = -ENOMEM; - break; - } - - /* The BD holds the cache aligned address */ - priv->rx_queue.drv[i].host_addr = packet->dma_addr; - priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH; - priv->status_queue.drv[i].status_fields = 0; - } - - if (i == RX_QUEUE_LENGTH) - return 0; - - for (j = 0; j < i; j++) { - pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr, - sizeof(struct ipw2100_rx_packet), - PCI_DMA_FROMDEVICE); - dev_kfree_skb(priv->rx_buffers[j].skb); - } - - kfree(priv->rx_buffers); - priv->rx_buffers = NULL; - - bd_queue_free(priv, &priv->rx_queue); - - status_queue_free(priv); - - return err; -} - -static void ipw2100_rx_initialize(struct ipw2100_priv *priv) -{ - IPW_DEBUG_INFO("enter\n"); - - priv->rx_queue.oldest = 0; - priv->rx_queue.available = priv->rx_queue.entries - 1; - priv->rx_queue.next = priv->rx_queue.entries - 1; - - INIT_STAT(&priv->rxq_stat); - SET_STAT(&priv->rxq_stat, priv->rx_queue.available); - - bd_queue_initialize(priv, &priv->rx_queue, - IPW_MEM_HOST_SHARED_RX_BD_BASE, - IPW_MEM_HOST_SHARED_RX_BD_SIZE, - IPW_MEM_HOST_SHARED_RX_READ_INDEX, - IPW_MEM_HOST_SHARED_RX_WRITE_INDEX); - - /* set up the status queue */ - write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE, - priv->status_queue.nic); - - IPW_DEBUG_INFO("exit\n"); -} - -static void ipw2100_rx_free(struct ipw2100_priv *priv) -{ - int i; - - IPW_DEBUG_INFO("enter\n"); - - bd_queue_free(priv, &priv->rx_queue); - status_queue_free(priv); - - if (!priv->rx_buffers) - return; - - for (i = 0; i < RX_QUEUE_LENGTH; i++) { - if (priv->rx_buffers[i].rxp) { - pci_unmap_single(priv->pci_dev, - priv->rx_buffers[i].dma_addr, - sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); - dev_kfree_skb(priv->rx_buffers[i].skb); - } - } - - kfree(priv->rx_buffers); - priv->rx_buffers = NULL; - - IPW_DEBUG_INFO("exit\n"); -} - -static int ipw2100_read_mac_address(struct ipw2100_priv *priv) -{ - u32 length = ETH_ALEN; - u8 addr[ETH_ALEN]; - - int err; - - err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length); - if (err) { - IPW_DEBUG_INFO("MAC address read failed\n"); - return -EIO; - } - - memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); - IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr); - - return 0; -} - -/******************************************************************** - * - * Firmware Commands - * - ********************************************************************/ - -static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode) -{ - struct host_command cmd = { - .host_command = ADAPTER_ADDRESS, - .host_command_sequence = 0, - .host_command_length = ETH_ALEN - }; - int err; - - IPW_DEBUG_HC("SET_MAC_ADDRESS\n"); - - IPW_DEBUG_INFO("enter\n"); - - if (priv->config & CFG_CUSTOM_MAC) { - memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN); - memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - } else - memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr, - ETH_ALEN); - - err = ipw2100_hw_send_command(priv, &cmd); - - IPW_DEBUG_INFO("exit\n"); - return err; -} - -static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type, - int batch_mode) -{ - struct host_command cmd = { - .host_command = PORT_TYPE, - .host_command_sequence = 0, - .host_command_length = sizeof(u32) - }; - int err; - - switch (port_type) { - case IW_MODE_INFRA: - cmd.host_command_parameters[0] = IPW_BSS; - break; - case IW_MODE_ADHOC: - cmd.host_command_parameters[0] = IPW_IBSS; - break; - } - - IPW_DEBUG_HC("PORT_TYPE: %s\n", - port_type == IPW_IBSS ? "Ad-Hoc" : "Managed"); - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) { - printk(KERN_ERR DRV_NAME - ": %s: Could not disable adapter %d\n", - priv->net_dev->name, err); - return err; - } - } - - /* send cmd to firmware */ - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) - ipw2100_enable_adapter(priv); - - return err; -} - -static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel, - int batch_mode) -{ - struct host_command cmd = { - .host_command = CHANNEL, - .host_command_sequence = 0, - .host_command_length = sizeof(u32) - }; - int err; - - cmd.host_command_parameters[0] = channel; - - IPW_DEBUG_HC("CHANNEL: %d\n", channel); - - /* If BSS then we don't support channel selection */ - if (priv->ieee->iw_mode == IW_MODE_INFRA) - return 0; - - if ((channel != 0) && - ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL))) - return -EINVAL; - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) { - IPW_DEBUG_INFO("Failed to set channel to %d", channel); - return err; - } - - if (channel) - priv->config |= CFG_STATIC_CHANNEL; - else - priv->config &= ~CFG_STATIC_CHANNEL; - - priv->channel = channel; - - if (!batch_mode) { - err = ipw2100_enable_adapter(priv); - if (err) - return err; - } - - return 0; -} - -static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode) -{ - struct host_command cmd = { - .host_command = SYSTEM_CONFIG, - .host_command_sequence = 0, - .host_command_length = 12, - }; - u32 ibss_mask, len = sizeof(u32); - int err; - - /* Set system configuration */ - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) - cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START; - - cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK | - IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE; - - if (!(priv->config & CFG_LONG_PREAMBLE)) - cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO; - - err = ipw2100_get_ordinal(priv, - IPW_ORD_EEPROM_IBSS_11B_CHANNELS, - &ibss_mask, &len); - if (err) - ibss_mask = IPW_IBSS_11B_DEFAULT_MASK; - - cmd.host_command_parameters[1] = REG_CHANNEL_MASK; - cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask; - - /* 11b only */ - /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */ - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - -/* If IPv6 is configured in the kernel then we don't want to filter out all - * of the multicast packets as IPv6 needs some. */ -#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) - cmd.host_command = ADD_MULTICAST; - cmd.host_command_sequence = 0; - cmd.host_command_length = 0; - - ipw2100_hw_send_command(priv, &cmd); -#endif - if (!batch_mode) { - err = ipw2100_enable_adapter(priv); - if (err) - return err; - } - - return 0; -} - -static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate, - int batch_mode) -{ - struct host_command cmd = { - .host_command = BASIC_TX_RATES, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - cmd.host_command_parameters[0] = rate & TX_RATE_MASK; - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - /* Set BASIC TX Rate first */ - ipw2100_hw_send_command(priv, &cmd); - - /* Set TX Rate */ - cmd.host_command = TX_RATES; - ipw2100_hw_send_command(priv, &cmd); - - /* Set MSDU TX Rate */ - cmd.host_command = MSDU_TX_RATES; - ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) { - err = ipw2100_enable_adapter(priv); - if (err) - return err; - } - - priv->tx_rates = rate; - - return 0; -} - -static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level) -{ - struct host_command cmd = { - .host_command = POWER_MODE, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - cmd.host_command_parameters[0] = power_level; - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - - if (power_level == IPW_POWER_MODE_CAM) - priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); - else - priv->power_mode = IPW_POWER_ENABLED | power_level; - -#ifdef IPW2100_TX_POWER - if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) { - /* Set beacon interval */ - cmd.host_command = TX_POWER_INDEX; - cmd.host_command_parameters[0] = (u32) priv->adhoc_power; - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - } -#endif - - return 0; -} - -static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold) -{ - struct host_command cmd = { - .host_command = RTS_THRESHOLD, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - if (threshold & RTS_DISABLED) - cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD; - else - cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED; - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - - priv->rts_threshold = threshold; - - return 0; -} - -#if 0 -int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv, - u32 threshold, int batch_mode) -{ - struct host_command cmd = { - .host_command = FRAG_THRESHOLD, - .host_command_sequence = 0, - .host_command_length = 4, - .host_command_parameters[0] = 0, - }; - int err; - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - if (threshold == 0) - threshold = DEFAULT_FRAG_THRESHOLD; - else { - threshold = max(threshold, MIN_FRAG_THRESHOLD); - threshold = min(threshold, MAX_FRAG_THRESHOLD); - } - - cmd.host_command_parameters[0] = threshold; - - IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold); - - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) - ipw2100_enable_adapter(priv); - - if (!err) - priv->frag_threshold = threshold; - - return err; -} -#endif - -static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry) -{ - struct host_command cmd = { - .host_command = SHORT_RETRY_LIMIT, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - cmd.host_command_parameters[0] = retry; - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - - priv->short_retry_limit = retry; - - return 0; -} - -static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry) -{ - struct host_command cmd = { - .host_command = LONG_RETRY_LIMIT, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - cmd.host_command_parameters[0] = retry; - - err = ipw2100_hw_send_command(priv, &cmd); - if (err) - return err; - - priv->long_retry_limit = retry; - - return 0; -} - -static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, - int batch_mode) -{ - struct host_command cmd = { - .host_command = MANDATORY_BSSID, - .host_command_sequence = 0, - .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN - }; - int err; - -#ifdef CONFIG_IPW2100_DEBUG - if (bssid != NULL) - IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid); - else - IPW_DEBUG_HC("MANDATORY_BSSID: \n"); -#endif - /* if BSSID is empty then we disable mandatory bssid mode */ - if (bssid != NULL) - memcpy(cmd.host_command_parameters, bssid, ETH_ALEN); - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) - ipw2100_enable_adapter(priv); - - return err; -} - -static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv) -{ - struct host_command cmd = { - .host_command = DISASSOCIATION_BSSID, - .host_command_sequence = 0, - .host_command_length = ETH_ALEN - }; - int err; - int len; - - IPW_DEBUG_HC("DISASSOCIATION_BSSID\n"); - - len = ETH_ALEN; - /* The Firmware currently ignores the BSSID and just disassociates from - * the currently associated AP -- but in the off chance that a future - * firmware does use the BSSID provided here, we go ahead and try and - * set it to the currently associated AP's BSSID */ - memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN); - - err = ipw2100_hw_send_command(priv, &cmd); - - return err; -} - -static int ipw2100_set_wpa_ie(struct ipw2100_priv *, - struct ipw2100_wpa_assoc_frame *, int) - __attribute__ ((unused)); - -static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv, - struct ipw2100_wpa_assoc_frame *wpa_frame, - int batch_mode) -{ - struct host_command cmd = { - .host_command = SET_WPA_IE, - .host_command_sequence = 0, - .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame), - }; - int err; - - IPW_DEBUG_HC("SET_WPA_IE\n"); - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - memcpy(cmd.host_command_parameters, wpa_frame, - sizeof(struct ipw2100_wpa_assoc_frame)); - - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) { - if (ipw2100_enable_adapter(priv)) - err = -EIO; - } - - return err; -} - -struct security_info_params { - u32 allowed_ciphers; - u16 version; - u8 auth_mode; - u8 replay_counters_number; - u8 unicast_using_group; -} __attribute__ ((packed)); - -static int ipw2100_set_security_information(struct ipw2100_priv *priv, - int auth_mode, - int security_level, - int unicast_using_group, - int batch_mode) -{ - struct host_command cmd = { - .host_command = SET_SECURITY_INFORMATION, - .host_command_sequence = 0, - .host_command_length = sizeof(struct security_info_params) - }; - struct security_info_params *security = - (struct security_info_params *)&cmd.host_command_parameters; - int err; - memset(security, 0, sizeof(*security)); - - /* If shared key AP authentication is turned on, then we need to - * configure the firmware to try and use it. - * - * Actual data encryption/decryption is handled by the host. */ - security->auth_mode = auth_mode; - security->unicast_using_group = unicast_using_group; - - switch (security_level) { - default: - case SEC_LEVEL_0: - security->allowed_ciphers = IPW_NONE_CIPHER; - break; - case SEC_LEVEL_1: - security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER; - break; - case SEC_LEVEL_2: - security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER | IPW_TKIP_CIPHER; - break; - case SEC_LEVEL_2_CKIP: - security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER | IPW_CKIP_CIPHER; - break; - case SEC_LEVEL_3: - security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER; - break; - } - - IPW_DEBUG_HC - ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n", - security->auth_mode, security->allowed_ciphers, security_level); - - security->replay_counters_number = 0; - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) - ipw2100_enable_adapter(priv); - - return err; -} - -static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power) -{ - struct host_command cmd = { - .host_command = TX_POWER_INDEX, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err = 0; - u32 tmp = tx_power; - - if (tx_power != IPW_TX_POWER_DEFAULT) - tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 / - (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); - - cmd.host_command_parameters[0] = tmp; - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) - err = ipw2100_hw_send_command(priv, &cmd); - if (!err) - priv->tx_power = tx_power; - - return 0; -} - -static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, - u32 interval, int batch_mode) -{ - struct host_command cmd = { - .host_command = BEACON_INTERVAL, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - cmd.host_command_parameters[0] = interval; - - IPW_DEBUG_INFO("enter\n"); - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) { - err = ipw2100_enable_adapter(priv); - if (err) - return err; - } - } - - IPW_DEBUG_INFO("exit\n"); - - return 0; -} - -void ipw2100_queues_initialize(struct ipw2100_priv *priv) -{ - ipw2100_tx_initialize(priv); - ipw2100_rx_initialize(priv); - ipw2100_msg_initialize(priv); -} - -void ipw2100_queues_free(struct ipw2100_priv *priv) -{ - ipw2100_tx_free(priv); - ipw2100_rx_free(priv); - ipw2100_msg_free(priv); -} - -int ipw2100_queues_allocate(struct ipw2100_priv *priv) -{ - if (ipw2100_tx_allocate(priv) || - ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv)) - goto fail; - - return 0; - - fail: - ipw2100_tx_free(priv); - ipw2100_rx_free(priv); - ipw2100_msg_free(priv); - return -ENOMEM; -} - -#define IPW_PRIVACY_CAPABLE 0x0008 - -static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags, - int batch_mode) -{ - struct host_command cmd = { - .host_command = WEP_FLAGS, - .host_command_sequence = 0, - .host_command_length = 4 - }; - int err; - - cmd.host_command_parameters[0] = flags; - - IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags); - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) { - printk(KERN_ERR DRV_NAME - ": %s: Could not disable adapter %d\n", - priv->net_dev->name, err); - return err; - } - } - - /* send cmd to firmware */ - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) - ipw2100_enable_adapter(priv); - - return err; -} - -struct ipw2100_wep_key { - u8 idx; - u8 len; - u8 key[13]; -}; - -/* Macros to ease up priting WEP keys */ -#define WEP_FMT_64 "%02X%02X%02X%02X-%02X" -#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X" -#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4] -#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10] - -/** - * Set a the wep key - * - * @priv: struct to work on - * @idx: index of the key we want to set - * @key: ptr to the key data to set - * @len: length of the buffer at @key - * @batch_mode: FIXME perform the operation in batch mode, not - * disabling the device. - * - * @returns 0 if OK, < 0 errno code on error. - * - * Fill out a command structure with the new wep key, length an - * index and send it down the wire. - */ -static int ipw2100_set_key(struct ipw2100_priv *priv, - int idx, char *key, int len, int batch_mode) -{ - int keylen = len ? (len <= 5 ? 5 : 13) : 0; - struct host_command cmd = { - .host_command = WEP_KEY_INFO, - .host_command_sequence = 0, - .host_command_length = sizeof(struct ipw2100_wep_key), - }; - struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters; - int err; - - IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n", - idx, keylen, len); - - /* NOTE: We don't check cached values in case the firmware was reset - * or some other problem is occurring. If the user is setting the key, - * then we push the change */ - - wep_key->idx = idx; - wep_key->len = keylen; - - if (keylen) { - memcpy(wep_key->key, key, len); - memset(wep_key->key + len, 0, keylen - len); - } - - /* Will be optimized out on debug not being configured in */ - if (keylen == 0) - IPW_DEBUG_WEP("%s: Clearing key %d\n", - priv->net_dev->name, wep_key->idx); - else if (keylen == 5) - IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n", - priv->net_dev->name, wep_key->idx, wep_key->len, - WEP_STR_64(wep_key->key)); - else - IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128 - "\n", - priv->net_dev->name, wep_key->idx, wep_key->len, - WEP_STR_128(wep_key->key)); - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */ - if (err) { - printk(KERN_ERR DRV_NAME - ": %s: Could not disable adapter %d\n", - priv->net_dev->name, err); - return err; - } - } - - /* send cmd to firmware */ - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) { - int err2 = ipw2100_enable_adapter(priv); - if (err == 0) - err = err2; - } - return err; -} - -static int ipw2100_set_key_index(struct ipw2100_priv *priv, - int idx, int batch_mode) -{ - struct host_command cmd = { - .host_command = WEP_KEY_INDEX, - .host_command_sequence = 0, - .host_command_length = 4, - .host_command_parameters = {idx}, - }; - int err; - - IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx); - - if (idx < 0 || idx > 3) - return -EINVAL; - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) { - printk(KERN_ERR DRV_NAME - ": %s: Could not disable adapter %d\n", - priv->net_dev->name, err); - return err; - } - } - - /* send cmd to firmware */ - err = ipw2100_hw_send_command(priv, &cmd); - - if (!batch_mode) - ipw2100_enable_adapter(priv); - - return err; -} - -static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) -{ - int i, err, auth_mode, sec_level, use_group; - - if (!(priv->status & STATUS_RUNNING)) - return 0; - - if (!batch_mode) { - err = ipw2100_disable_adapter(priv); - if (err) - return err; - } - - if (!priv->ieee->sec.enabled) { - err = - ipw2100_set_security_information(priv, IPW_AUTH_OPEN, - SEC_LEVEL_0, 0, 1); - } else { - auth_mode = IPW_AUTH_OPEN; - if (priv->ieee->sec.flags & SEC_AUTH_MODE) { - if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY) - auth_mode = IPW_AUTH_SHARED; - else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP) - auth_mode = IPW_AUTH_LEAP_CISCO_ID; - } - - sec_level = SEC_LEVEL_0; - if (priv->ieee->sec.flags & SEC_LEVEL) - sec_level = priv->ieee->sec.level; - - use_group = 0; - if (priv->ieee->sec.flags & SEC_UNICAST_GROUP) - use_group = priv->ieee->sec.unicast_uses_group; - - err = - ipw2100_set_security_information(priv, auth_mode, sec_level, - use_group, 1); - } - - if (err) - goto exit; - - if (priv->ieee->sec.enabled) { - for (i = 0; i < 4; i++) { - if (!(priv->ieee->sec.flags & (1 << i))) { - memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN); - priv->ieee->sec.key_sizes[i] = 0; - } else { - err = ipw2100_set_key(priv, i, - priv->ieee->sec.keys[i], - priv->ieee->sec. - key_sizes[i], 1); - if (err) - goto exit; - } - } - - ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1); - } - - /* Always enable privacy so the Host can filter WEP packets if - * encrypted data is sent up */ - err = - ipw2100_set_wep_flags(priv, - priv->ieee->sec. - enabled ? IPW_PRIVACY_CAPABLE : 0, 1); - if (err) - goto exit; - - priv->status &= ~STATUS_SECURITY_UPDATED; - - exit: - if (!batch_mode) - ipw2100_enable_adapter(priv); - - return err; -} - -static void ipw2100_security_work(struct work_struct *work) -{ - struct ipw2100_priv *priv = - container_of(work, struct ipw2100_priv, security_work.work); - - /* If we happen to have reconnected before we get a chance to - * process this, then update the security settings--which causes - * a disassociation to occur */ - if (!(priv->status & STATUS_ASSOCIATED) && - priv->status & STATUS_SECURITY_UPDATED) - ipw2100_configure_security(priv, 0); -} - -static void shim__set_security(struct net_device *dev, - struct ieee80211_security *sec) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int i, force_update = 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) - goto done; - - for (i = 0; i < 4; i++) { - if (sec->flags & (1 << i)) { - priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; - if (sec->key_sizes[i] == 0) - priv->ieee->sec.flags &= ~(1 << i); - else - memcpy(priv->ieee->sec.keys[i], sec->keys[i], - sec->key_sizes[i]); - if (sec->level == SEC_LEVEL_1) { - priv->ieee->sec.flags |= (1 << i); - priv->status |= STATUS_SECURITY_UPDATED; - } else - priv->ieee->sec.flags &= ~(1 << i); - } - } - - if ((sec->flags & SEC_ACTIVE_KEY) && - priv->ieee->sec.active_key != sec->active_key) { - if (sec->active_key <= 3) { - priv->ieee->sec.active_key = sec->active_key; - priv->ieee->sec.flags |= SEC_ACTIVE_KEY; - } else - priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; - - priv->status |= STATUS_SECURITY_UPDATED; - } - - if ((sec->flags & SEC_AUTH_MODE) && - (priv->ieee->sec.auth_mode != sec->auth_mode)) { - priv->ieee->sec.auth_mode = sec->auth_mode; - priv->ieee->sec.flags |= SEC_AUTH_MODE; - priv->status |= STATUS_SECURITY_UPDATED; - } - - if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) { - priv->ieee->sec.flags |= SEC_ENABLED; - priv->ieee->sec.enabled = sec->enabled; - priv->status |= STATUS_SECURITY_UPDATED; - force_update = 1; - } - - if (sec->flags & SEC_ENCRYPT) - priv->ieee->sec.encrypt = sec->encrypt; - - if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { - priv->ieee->sec.level = sec->level; - priv->ieee->sec.flags |= SEC_LEVEL; - priv->status |= STATUS_SECURITY_UPDATED; - } - - IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n", - priv->ieee->sec.flags & (1 << 8) ? '1' : '0', - priv->ieee->sec.flags & (1 << 7) ? '1' : '0', - priv->ieee->sec.flags & (1 << 6) ? '1' : '0', - priv->ieee->sec.flags & (1 << 5) ? '1' : '0', - priv->ieee->sec.flags & (1 << 4) ? '1' : '0', - priv->ieee->sec.flags & (1 << 3) ? '1' : '0', - priv->ieee->sec.flags & (1 << 2) ? '1' : '0', - priv->ieee->sec.flags & (1 << 1) ? '1' : '0', - priv->ieee->sec.flags & (1 << 0) ? '1' : '0'); - -/* As a temporary work around to enable WPA until we figure out why - * wpa_supplicant toggles the security capability of the driver, which - * forces a disassocation with force_update... - * - * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/ - if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) - ipw2100_configure_security(priv, 0); - done: - mutex_unlock(&priv->action_mutex); -} - -static int ipw2100_adapter_setup(struct ipw2100_priv *priv) -{ - int err; - int batch_mode = 1; - u8 *bssid; - - IPW_DEBUG_INFO("enter\n"); - - err = ipw2100_disable_adapter(priv); - if (err) - return err; -#ifdef CONFIG_IPW2100_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - err = ipw2100_set_channel(priv, priv->channel, batch_mode); - if (err) - return err; - - IPW_DEBUG_INFO("exit\n"); - - return 0; - } -#endif /* CONFIG_IPW2100_MONITOR */ - - err = ipw2100_read_mac_address(priv); - if (err) - return -EIO; - - err = ipw2100_set_mac_address(priv, batch_mode); - if (err) - return err; - - err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode); - if (err) - return err; - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - err = ipw2100_set_channel(priv, priv->channel, batch_mode); - if (err) - return err; - } - - err = ipw2100_system_config(priv, batch_mode); - if (err) - return err; - - err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode); - if (err) - return err; - - /* Default to power mode OFF */ - err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM); - if (err) - return err; - - err = ipw2100_set_rts_threshold(priv, priv->rts_threshold); - if (err) - return err; - - if (priv->config & CFG_STATIC_BSSID) - bssid = priv->bssid; - else - bssid = NULL; - err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode); - if (err) - return err; - - if (priv->config & CFG_STATIC_ESSID) - err = ipw2100_set_essid(priv, priv->essid, priv->essid_len, - batch_mode); - else - err = ipw2100_set_essid(priv, NULL, 0, batch_mode); - if (err) - return err; - - err = ipw2100_configure_security(priv, batch_mode); - if (err) - return err; - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - err = - ipw2100_set_ibss_beacon_interval(priv, - priv->beacon_interval, - batch_mode); - if (err) - return err; - - err = ipw2100_set_tx_power(priv, priv->tx_power); - if (err) - return err; - } - - /* - err = ipw2100_set_fragmentation_threshold( - priv, priv->frag_threshold, batch_mode); - if (err) - return err; - */ - - IPW_DEBUG_INFO("exit\n"); - - return 0; -} - -/************************************************************************* - * - * EXTERNALLY CALLED METHODS - * - *************************************************************************/ - -/* This method is called by the network layer -- not to be confused with - * ipw2100_set_mac_address() declared above called by this driver (and this - * method as well) to talk to the firmware */ -static int ipw2100_set_address(struct net_device *dev, void *p) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct sockaddr *addr = p; - int err = 0; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - mutex_lock(&priv->action_mutex); - - priv->config |= CFG_CUSTOM_MAC; - memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - - err = ipw2100_set_mac_address(priv, 0); - if (err) - goto done; - - priv->reset_backoff = 0; - mutex_unlock(&priv->action_mutex); - ipw2100_reset_adapter(&priv->reset_work.work); - return 0; - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_open(struct net_device *dev) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - unsigned long flags; - IPW_DEBUG_INFO("dev->open\n"); - - spin_lock_irqsave(&priv->low_lock, flags); - if (priv->status & STATUS_ASSOCIATED) { - netif_carrier_on(dev); - netif_start_queue(dev); - } - spin_unlock_irqrestore(&priv->low_lock, flags); - - return 0; -} - -static int ipw2100_close(struct net_device *dev) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - unsigned long flags; - struct list_head *element; - struct ipw2100_tx_packet *packet; - - IPW_DEBUG_INFO("enter\n"); - - spin_lock_irqsave(&priv->low_lock, flags); - - if (priv->status & STATUS_ASSOCIATED) - netif_carrier_off(dev); - netif_stop_queue(dev); - - /* Flush the TX queue ... */ - while (!list_empty(&priv->tx_pend_list)) { - element = priv->tx_pend_list.next; - packet = list_entry(element, struct ipw2100_tx_packet, list); - - list_del(element); - DEC_STAT(&priv->tx_pend_stat); - - ieee80211_txb_free(packet->info.d_struct.txb); - packet->info.d_struct.txb = NULL; - - list_add_tail(element, &priv->tx_free_list); - INC_STAT(&priv->tx_free_stat); - } - spin_unlock_irqrestore(&priv->low_lock, flags); - - IPW_DEBUG_INFO("exit\n"); - - return 0; -} - -/* - * TODO: Fix this function... its just wrong - */ -static void ipw2100_tx_timeout(struct net_device *dev) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - - priv->ieee->stats.tx_errors++; - -#ifdef CONFIG_IPW2100_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) - return; -#endif - - IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n", - dev->name); - schedule_reset(priv); -} - -static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) -{ - /* This is called when wpa_supplicant loads and closes the driver - * interface. */ - priv->ieee->wpa_enabled = value; - return 0; -} - -static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) -{ - - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { - .flags = SEC_AUTH_MODE, - }; - int ret = 0; - - if (value & IW_AUTH_ALG_SHARED_KEY) { - sec.auth_mode = WLAN_AUTH_SHARED_KEY; - ieee->open_wep = 0; - } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { - sec.auth_mode = WLAN_AUTH_OPEN; - ieee->open_wep = 1; - } else if (value & IW_AUTH_ALG_LEAP) { - sec.auth_mode = WLAN_AUTH_LEAP; - ieee->open_wep = 1; - } else - return -EINVAL; - - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - else - ret = -EOPNOTSUPP; - - return ret; -} - -static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, - char *wpa_ie, int wpa_ie_len) -{ - - struct ipw2100_wpa_assoc_frame frame; - - frame.fixed_ie_mask = 0; - - /* copy WPA IE */ - memcpy(frame.var_ie, wpa_ie, wpa_ie_len); - frame.var_ie_len = wpa_ie_len; - - /* make sure WPA is enabled */ - ipw2100_wpa_enable(priv, 1); - ipw2100_set_wpa_ie(priv, &frame, 0); -} - -static void ipw_ethtool_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - char fw_ver[64], ucode_ver[64]; - - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - - ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver)); - ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver)); - - snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s", - fw_ver, priv->eeprom_version, ucode_ver); - - strcpy(info->bus_info, pci_name(priv->pci_dev)); -} - -static u32 ipw2100_ethtool_get_link(struct net_device *dev) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; -} - -static const struct ethtool_ops ipw2100_ethtool_ops = { - .get_link = ipw2100_ethtool_get_link, - .get_drvinfo = ipw_ethtool_get_drvinfo, -}; - -static void ipw2100_hang_check(struct work_struct *work) -{ - struct ipw2100_priv *priv = - container_of(work, struct ipw2100_priv, hang_check.work); - unsigned long flags; - u32 rtc = 0xa5a5a5a5; - u32 len = sizeof(rtc); - int restart = 0; - - spin_lock_irqsave(&priv->low_lock, flags); - - if (priv->fatal_error != 0) { - /* If fatal_error is set then we need to restart */ - IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n", - priv->net_dev->name); - - restart = 1; - } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) || - (rtc == priv->last_rtc)) { - /* Check if firmware is hung */ - IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n", - priv->net_dev->name); - - restart = 1; - } - - if (restart) { - /* Kill timer */ - priv->stop_hang_check = 1; - priv->hangs++; - - /* Restart the NIC */ - schedule_reset(priv); - } - - priv->last_rtc = rtc; - - if (!priv->stop_hang_check) - queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); - - spin_unlock_irqrestore(&priv->low_lock, flags); -} - -static void ipw2100_rf_kill(struct work_struct *work) -{ - struct ipw2100_priv *priv = - container_of(work, struct ipw2100_priv, rf_kill.work); - unsigned long flags; - - spin_lock_irqsave(&priv->low_lock, flags); - - if (rf_kill_active(priv)) { - IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); - if (!priv->stop_rf_kill) - queue_delayed_work(priv->workqueue, &priv->rf_kill, - round_jiffies_relative(HZ)); - goto exit_unlock; - } - - /* RF Kill is now disabled, so bring the device back up */ - - if (!(priv->status & STATUS_RF_KILL_MASK)) { - IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting " - "device\n"); - schedule_reset(priv); - } else - IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " - "enabled\n"); - - exit_unlock: - spin_unlock_irqrestore(&priv->low_lock, flags); -} - -static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); - -/* Look into using netdev destructor to shutdown ieee80211? */ - -static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, - void __iomem * base_addr, - unsigned long mem_start, - unsigned long mem_len) -{ - struct ipw2100_priv *priv; - struct net_device *dev; - - dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); - if (!dev) - return NULL; - priv = ieee80211_priv(dev); - priv->ieee = netdev_priv(dev); - priv->pci_dev = pci_dev; - priv->net_dev = dev; - - priv->ieee->hard_start_xmit = ipw2100_tx; - priv->ieee->set_security = shim__set_security; - - priv->ieee->perfect_rssi = -20; - priv->ieee->worst_rssi = -85; - - dev->open = ipw2100_open; - dev->stop = ipw2100_close; - dev->init = ipw2100_net_init; - dev->ethtool_ops = &ipw2100_ethtool_ops; - dev->tx_timeout = ipw2100_tx_timeout; - dev->wireless_handlers = &ipw2100_wx_handler_def; - priv->wireless_data.ieee80211 = priv->ieee; - dev->wireless_data = &priv->wireless_data; - dev->set_mac_address = ipw2100_set_address; - dev->watchdog_timeo = 3 * HZ; - dev->irq = 0; - - dev->base_addr = (unsigned long)base_addr; - dev->mem_start = mem_start; - dev->mem_end = dev->mem_start + mem_len - 1; - - /* NOTE: We don't use the wireless_handlers hook - * in dev as the system will start throwing WX requests - * to us before we're actually initialized and it just - * ends up causing problems. So, we just handle - * the WX extensions through the ipw2100_ioctl interface */ - - /* memset() puts everything to 0, so we only have explicitly set - * those values that need to be something else */ - - /* If power management is turned on, default to AUTO mode */ - priv->power_mode = IPW_POWER_AUTO; - -#ifdef CONFIG_IPW2100_MONITOR - priv->config |= CFG_CRC_CHECK; -#endif - priv->ieee->wpa_enabled = 0; - priv->ieee->drop_unencrypted = 0; - priv->ieee->privacy_invoked = 0; - priv->ieee->ieee802_1x = 1; - - /* Set module parameters */ - switch (mode) { - case 1: - priv->ieee->iw_mode = IW_MODE_ADHOC; - break; -#ifdef CONFIG_IPW2100_MONITOR - case 2: - priv->ieee->iw_mode = IW_MODE_MONITOR; - break; -#endif - default: - case 0: - priv->ieee->iw_mode = IW_MODE_INFRA; - break; - } - - if (disable == 1) - priv->status |= STATUS_RF_KILL_SW; - - if (channel != 0 && - ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) { - priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - } - - if (associate) - priv->config |= CFG_ASSOCIATE; - - priv->beacon_interval = DEFAULT_BEACON_INTERVAL; - priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; - priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; - priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED; - priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED; - priv->tx_power = IPW_TX_POWER_DEFAULT; - priv->tx_rates = DEFAULT_TX_RATES; - - strcpy(priv->nick, "ipw2100"); - - spin_lock_init(&priv->low_lock); - mutex_init(&priv->action_mutex); - mutex_init(&priv->adapter_mutex); - - init_waitqueue_head(&priv->wait_command_queue); - - netif_carrier_off(dev); - - INIT_LIST_HEAD(&priv->msg_free_list); - INIT_LIST_HEAD(&priv->msg_pend_list); - INIT_STAT(&priv->msg_free_stat); - INIT_STAT(&priv->msg_pend_stat); - - INIT_LIST_HEAD(&priv->tx_free_list); - INIT_LIST_HEAD(&priv->tx_pend_list); - INIT_STAT(&priv->tx_free_stat); - INIT_STAT(&priv->tx_pend_stat); - - INIT_LIST_HEAD(&priv->fw_pend_list); - INIT_STAT(&priv->fw_pend_stat); - - priv->workqueue = create_workqueue(DRV_NAME); - - INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter); - INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work); - INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work); - INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check); - INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill); - INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now); - INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later); - - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - ipw2100_irq_tasklet, (unsigned long)priv); - - /* NOTE: We do not start the deferred work for status checks yet */ - priv->stop_rf_kill = 1; - priv->stop_hang_check = 1; - - return dev; -} - -static int ipw2100_pci_init_one(struct pci_dev *pci_dev, - const struct pci_device_id *ent) -{ - unsigned long mem_start, mem_len, mem_flags; - void __iomem *base_addr = NULL; - struct net_device *dev = NULL; - struct ipw2100_priv *priv = NULL; - int err = 0; - int registered = 0; - u32 val; - - IPW_DEBUG_INFO("enter\n"); - - mem_start = pci_resource_start(pci_dev, 0); - mem_len = pci_resource_len(pci_dev, 0); - mem_flags = pci_resource_flags(pci_dev, 0); - - if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) { - IPW_DEBUG_INFO("weird - resource type is not memory\n"); - err = -ENODEV; - goto fail; - } - - base_addr = ioremap_nocache(mem_start, mem_len); - if (!base_addr) { - printk(KERN_WARNING DRV_NAME - "Error calling ioremap_nocache.\n"); - err = -EIO; - goto fail; - } - - /* allocate and initialize our net_device */ - dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len); - if (!dev) { - printk(KERN_WARNING DRV_NAME - "Error calling ipw2100_alloc_device.\n"); - err = -ENOMEM; - goto fail; - } - - /* set up PCI mappings for device */ - err = pci_enable_device(pci_dev); - if (err) { - printk(KERN_WARNING DRV_NAME - "Error calling pci_enable_device.\n"); - return err; - } - - priv = ieee80211_priv(dev); - - pci_set_master(pci_dev); - pci_set_drvdata(pci_dev, priv); - - err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); - if (err) { - printk(KERN_WARNING DRV_NAME - "Error calling pci_set_dma_mask.\n"); - pci_disable_device(pci_dev); - return err; - } - - err = pci_request_regions(pci_dev, DRV_NAME); - if (err) { - printk(KERN_WARNING DRV_NAME - "Error calling pci_request_regions.\n"); - pci_disable_device(pci_dev); - return err; - } - - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_read_config_dword(pci_dev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); - - pci_set_power_state(pci_dev, PCI_D0); - - if (!ipw2100_hw_is_adapter_in_system(dev)) { - printk(KERN_WARNING DRV_NAME - "Device not found via register read.\n"); - err = -ENODEV; - goto fail; - } - - SET_NETDEV_DEV(dev, &pci_dev->dev); - - /* Force interrupts to be shut off on the device */ - priv->status |= STATUS_INT_ENABLED; - ipw2100_disable_interrupts(priv); - - /* Allocate and initialize the Tx/Rx queues and lists */ - if (ipw2100_queues_allocate(priv)) { - printk(KERN_WARNING DRV_NAME - "Error calling ipw2100_queues_allocate.\n"); - err = -ENOMEM; - goto fail; - } - ipw2100_queues_initialize(priv); - - err = request_irq(pci_dev->irq, - ipw2100_interrupt, IRQF_SHARED, dev->name, priv); - if (err) { - printk(KERN_WARNING DRV_NAME - "Error calling request_irq: %d.\n", pci_dev->irq); - goto fail; - } - dev->irq = pci_dev->irq; - - IPW_DEBUG_INFO("Attempting to register device...\n"); - - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2100 Network Connection\n"); - - /* Bring up the interface. Pre 0.46, after we registered the - * network device we would call ipw2100_up. This introduced a race - * condition with newer hotplug configurations (network was coming - * up and making calls before the device was initialized). - * - * If we called ipw2100_up before we registered the device, then the - * device name wasn't registered. So, we instead use the net_dev->init - * member to call a function that then just turns and calls ipw2100_up. - * net_dev->init is called after name allocation but before the - * notifier chain is called */ - err = register_netdev(dev); - if (err) { - printk(KERN_WARNING DRV_NAME - "Error calling register_netdev.\n"); - goto fail; - } - - mutex_lock(&priv->action_mutex); - registered = 1; - - IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev)); - - /* perform this after register_netdev so that dev->name is set */ - err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); - if (err) - goto fail_unlock; - - /* If the RF Kill switch is disabled, go ahead and complete the - * startup sequence */ - if (!(priv->status & STATUS_RF_KILL_MASK)) { - /* Enable the adapter - sends HOST_COMPLETE */ - if (ipw2100_enable_adapter(priv)) { - printk(KERN_WARNING DRV_NAME - ": %s: failed in call to enable adapter.\n", - priv->net_dev->name); - ipw2100_hw_stop_adapter(priv); - err = -EIO; - goto fail_unlock; - } - - /* Start a scan . . . */ - ipw2100_set_scan_options(priv); - ipw2100_start_scan(priv); - } - - IPW_DEBUG_INFO("exit\n"); - - priv->status |= STATUS_INITIALIZED; - - mutex_unlock(&priv->action_mutex); - - return 0; - - fail_unlock: - mutex_unlock(&priv->action_mutex); - - fail: - if (dev) { - if (registered) - unregister_netdev(dev); - - ipw2100_hw_stop_adapter(priv); - - ipw2100_disable_interrupts(priv); - - if (dev->irq) - free_irq(dev->irq, priv); - - ipw2100_kill_workqueue(priv); - - /* These are safe to call even if they weren't allocated */ - ipw2100_queues_free(priv); - sysfs_remove_group(&pci_dev->dev.kobj, - &ipw2100_attribute_group); - - free_ieee80211(dev); - pci_set_drvdata(pci_dev, NULL); - } - - if (base_addr) - iounmap(base_addr); - - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); - - return err; -} - -static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) -{ - struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); - struct net_device *dev; - - if (priv) { - mutex_lock(&priv->action_mutex); - - priv->status &= ~STATUS_INITIALIZED; - - dev = priv->net_dev; - sysfs_remove_group(&pci_dev->dev.kobj, - &ipw2100_attribute_group); - -#ifdef CONFIG_PM - if (ipw2100_firmware.version) - ipw2100_release_firmware(priv, &ipw2100_firmware); -#endif - /* Take down the hardware */ - ipw2100_down(priv); - - /* Release the mutex so that the network subsystem can - * complete any needed calls into the driver... */ - mutex_unlock(&priv->action_mutex); - - /* Unregister the device first - this results in close() - * being called if the device is open. If we free storage - * first, then close() will crash. */ - unregister_netdev(dev); - - /* ipw2100_down will ensure that there is no more pending work - * in the workqueue's, so we can safely remove them now. */ - ipw2100_kill_workqueue(priv); - - ipw2100_queues_free(priv); - - /* Free potential debugging firmware snapshot */ - ipw2100_snapshot_free(priv); - - if (dev->irq) - free_irq(dev->irq, priv); - - if (dev->base_addr) - iounmap((void __iomem *)dev->base_addr); - - free_ieee80211(dev); - } - - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); - - IPW_DEBUG_INFO("exit\n"); -} - -#ifdef CONFIG_PM -static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) -{ - struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); - struct net_device *dev = priv->net_dev; - - IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name); - - mutex_lock(&priv->action_mutex); - if (priv->status & STATUS_INITIALIZED) { - /* Take down the device; powers it off, etc. */ - ipw2100_down(priv); - } - - /* Remove the PRESENT state of the device */ - netif_device_detach(dev); - - pci_save_state(pci_dev); - pci_disable_device(pci_dev); - pci_set_power_state(pci_dev, PCI_D3hot); - - mutex_unlock(&priv->action_mutex); - - return 0; -} - -static int ipw2100_resume(struct pci_dev *pci_dev) -{ - struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); - struct net_device *dev = priv->net_dev; - int err; - u32 val; - - if (IPW2100_PM_DISABLED) - return 0; - - mutex_lock(&priv->action_mutex); - - IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name); - - pci_set_power_state(pci_dev, PCI_D0); - err = pci_enable_device(pci_dev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - mutex_unlock(&priv->action_mutex); - return err; - } - pci_restore_state(pci_dev); - - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries - * from interfering with C3 CPU state. pci_restore_state won't help - * here since it only restores the first 64 bytes pci config header. - */ - pci_read_config_dword(pci_dev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); - - /* Set the device back into the PRESENT state; this will also wake - * the queue of needed */ - netif_device_attach(dev); - - /* Bring the device back up */ - if (!(priv->status & STATUS_RF_KILL_SW)) - ipw2100_up(priv, 0); - - mutex_unlock(&priv->action_mutex); - - return 0; -} -#endif - -#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } - -static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { - IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */ - IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */ - IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */ - IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */ - - IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */ - - IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */ - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table); - -static struct pci_driver ipw2100_pci_driver = { - .name = DRV_NAME, - .id_table = ipw2100_pci_id_table, - .probe = ipw2100_pci_init_one, - .remove = __devexit_p(ipw2100_pci_remove_one), -#ifdef CONFIG_PM - .suspend = ipw2100_suspend, - .resume = ipw2100_resume, -#endif -}; - -/** - * Initialize the ipw2100 driver/module - * - * @returns 0 if ok, < 0 errno node con error. - * - * Note: we cannot init the /proc stuff until the PCI driver is there, - * or we risk an unlikely race condition on someone accessing - * uninitialized data in the PCI dev struct through /proc. - */ -static int __init ipw2100_init(void) -{ - int ret; - - printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); - printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); - - ret = pci_register_driver(&ipw2100_pci_driver); - if (ret) - goto out; - - pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", - PM_QOS_DEFAULT_VALUE); -#ifdef CONFIG_IPW2100_DEBUG - ipw2100_debug_level = debug; - ret = driver_create_file(&ipw2100_pci_driver.driver, - &driver_attr_debug_level); -#endif - -out: - return ret; -} - -/** - * Cleanup ipw2100 driver registration - */ -static void __exit ipw2100_exit(void) -{ - /* FIXME: IPG: check that we have no instances of the devices open */ -#ifdef CONFIG_IPW2100_DEBUG - driver_remove_file(&ipw2100_pci_driver.driver, - &driver_attr_debug_level); -#endif - pci_unregister_driver(&ipw2100_pci_driver); - pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100"); -} - -module_init(ipw2100_init); -module_exit(ipw2100_exit); - -#define WEXT_USECHANNELS 1 - -static const long ipw2100_frequencies[] = { - 2412, 2417, 2422, 2427, - 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, - 2472, 2484 -}; - -#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies) - -static const long ipw2100_rates_11b[] = { - 1000000, - 2000000, - 5500000, - 11000000 -}; - -#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b) - -static int ipw2100_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - if (!(priv->status & STATUS_ASSOCIATED)) - strcpy(wrqu->name, "unassociated"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); - - IPW_DEBUG_WX("Name: %s\n", wrqu->name); - return 0; -} - -static int ipw2100_wx_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct iw_freq *fwrq = &wrqu->freq; - int err = 0; - - if (priv->ieee->iw_mode == IW_MODE_INFRA) - return -EOPNOTSUPP; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - /* if setting by freq convert to channel */ - if (fwrq->e == 1) { - if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) { - int f = fwrq->m / 100000; - int c = 0; - - while ((c < REG_MAX_CHANNEL) && - (f != ipw2100_frequencies[c])) - c++; - - /* hack to fall through */ - fwrq->e = 0; - fwrq->m = c + 1; - } - } - - if (fwrq->e > 0 || fwrq->m > 1000) { - err = -EOPNOTSUPP; - goto done; - } else { /* Set the channel */ - IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); - err = ipw2100_set_channel(priv, fwrq->m, 0); - } - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - wrqu->freq.e = 0; - - /* If we are associated, trying to associate, or have a statically - * configured CHANNEL then return that; otherwise return ANY */ - if (priv->config & CFG_STATIC_CHANNEL || - priv->status & STATUS_ASSOCIATED) - wrqu->freq.m = priv->channel; - else - wrqu->freq.m = 0; - - IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); - return 0; - -} - -static int ipw2100_wx_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0; - - IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode); - - if (wrqu->mode == priv->ieee->iw_mode) - return 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - switch (wrqu->mode) { -#ifdef CONFIG_IPW2100_MONITOR - case IW_MODE_MONITOR: - err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); - break; -#endif /* CONFIG_IPW2100_MONITOR */ - case IW_MODE_ADHOC: - err = ipw2100_switch_mode(priv, IW_MODE_ADHOC); - break; - case IW_MODE_INFRA: - case IW_MODE_AUTO: - default: - err = ipw2100_switch_mode(priv, IW_MODE_INFRA); - break; - } - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - wrqu->mode = priv->ieee->iw_mode; - IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode); - - return 0; -} - -#define POWER_MODES 5 - -/* Values are in microsecond */ -static const s32 timeout_duration[POWER_MODES] = { - 350000, - 250000, - 75000, - 37000, - 25000, -}; - -static const s32 period_duration[POWER_MODES] = { - 400000, - 700000, - 1000000, - 1000000, - 1000000 -}; - -static int ipw2100_wx_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct iw_range *range = (struct iw_range *)extra; - u16 val; - int i, level; - - wrqu->data.length = sizeof(*range); - memset(range, 0, sizeof(*range)); - - /* Let's try to keep this struct in the same order as in - * linux/include/wireless.h - */ - - /* TODO: See what values we can set, and remove the ones we can't - * set, or fill them with some default data. - */ - - /* ~5 Mb/s real (802.11b) */ - range->throughput = 5 * 1000 * 1000; - -// range->sensitivity; /* signal level threshold range */ - - range->max_qual.qual = 100; - /* TODO: Find real max RSSI and stick here */ - range->max_qual.level = 0; - range->max_qual.noise = 0; - range->max_qual.updated = 7; /* Updated all three */ - - range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ - /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ - range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM; - range->avg_qual.noise = 0; - range->avg_qual.updated = 7; /* Updated all three */ - - range->num_bitrates = RATE_COUNT; - - for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { - range->bitrate[i] = ipw2100_rates_11b[i]; - } - - range->min_rts = MIN_RTS_THRESHOLD; - range->max_rts = MAX_RTS_THRESHOLD; - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - - range->min_pmp = period_duration[0]; /* Minimal PM period */ - range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */ - range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */ - range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */ - - /* How to decode max/min PM period */ - range->pmp_flags = IW_POWER_PERIOD; - /* How to decode max/min PM period */ - range->pmt_flags = IW_POWER_TIMEOUT; - /* What PM options are supported */ - range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; /* Different token sizes */ - range->num_encoding_sizes = 2; /* Number of entry in the list */ - range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */ -// range->encoding_login_index; /* token index for login token */ - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - range->txpower_capa = IW_TXPOW_DBM; - range->num_txpower = IW_MAX_TXPOWER; - for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); - i < IW_MAX_TXPOWER; - i++, level -= - ((IPW_TX_POWER_MAX_DBM - - IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1)) - range->txpower[i] = level / 16; - } else { - range->txpower_capa = 0; - range->num_txpower = 0; - } - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 18; - -// range->retry_capa; /* What retry options are supported */ -// range->retry_flags; /* How to decode max/min retry limit */ -// range->r_time_flags; /* How to decode max/min retry life */ -// range->min_retry; /* Minimal number of retries */ -// range->max_retry; /* Maximal number of retries */ -// range->min_r_time; /* Minimal retry lifetime */ -// range->max_r_time; /* Maximal retry lifetime */ - - range->num_channels = FREQ_COUNT; - - val = 0; - for (i = 0; i < FREQ_COUNT; i++) { - // TODO: Include only legal frequencies for some countries -// if (local->channel_mask & (1 << i)) { - range->freq[val].i = i + 1; - range->freq[val].m = ipw2100_frequencies[i] * 100000; - range->freq[val].e = 1; - val++; -// } - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWAP)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - IPW_DEBUG_WX("GET Range\n"); - - return 0; -} - -static int ipw2100_wx_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0; - - static const unsigned char any[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - static const unsigned char off[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - // sanity checks - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) - return -EINVAL; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || - !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { - /* we disable mandatory BSSID association */ - IPW_DEBUG_WX("exit - disable mandatory BSSID\n"); - priv->config &= ~CFG_STATIC_BSSID; - err = ipw2100_set_mandatory_bssid(priv, NULL, 0); - goto done; - } - - priv->config |= CFG_STATIC_BSSID; - memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN); - - err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); - - IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data); - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - /* If we are associated, trying to associate, or have a statically - * configured BSSID then return that; otherwise return ANY */ - if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) { - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); - } else - memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - - IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data); - return 0; -} - -static int ipw2100_wx_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - char *essid = ""; /* ANY */ - int length = 0; - int err = 0; - DECLARE_SSID_BUF(ssid); - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (wrqu->essid.flags && wrqu->essid.length) { - length = wrqu->essid.length; - essid = extra; - } - - if (length == 0) { - IPW_DEBUG_WX("Setting ESSID to ANY\n"); - priv->config &= ~CFG_STATIC_ESSID; - err = ipw2100_set_essid(priv, NULL, 0, 0); - goto done; - } - - length = min(length, IW_ESSID_MAX_SIZE); - - priv->config |= CFG_STATIC_ESSID; - - if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { - IPW_DEBUG_WX("ESSID set to current ESSID.\n"); - err = 0; - goto done; - } - - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", - print_ssid(ssid, essid, length), length); - - priv->essid_len = length; - memcpy(priv->essid, essid, priv->essid_len); - - err = ipw2100_set_essid(priv, essid, length, 0); - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - DECLARE_SSID_BUF(ssid); - - /* If we are associated, trying to associate, or have a statically - * configured ESSID then return that; otherwise return ANY */ - if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { - IPW_DEBUG_WX("Getting essid: '%s'\n", - print_ssid(ssid, priv->essid, priv->essid_len)); - memcpy(extra, priv->essid, priv->essid_len); - wrqu->essid.length = priv->essid_len; - wrqu->essid.flags = 1; /* active */ - } else { - IPW_DEBUG_WX("Getting essid: ANY\n"); - wrqu->essid.length = 0; - wrqu->essid.flags = 0; /* active */ - } - - return 0; -} - -static int ipw2100_wx_set_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - if (wrqu->data.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); - memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, extra, wrqu->data.length); - - IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick); - - return 0; -} - -static int ipw2100_wx_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - wrqu->data.length = strlen(priv->nick); - memcpy(extra, priv->nick, wrqu->data.length); - wrqu->data.flags = 1; /* active */ - - IPW_DEBUG_WX("GET Nickname -> %s \n", extra); - - return 0; -} - -static int ipw2100_wx_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - u32 target_rate = wrqu->bitrate.value; - u32 rate; - int err = 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - rate = 0; - - if (target_rate == 1000000 || - (!wrqu->bitrate.fixed && target_rate > 1000000)) - rate |= TX_RATE_1_MBIT; - if (target_rate == 2000000 || - (!wrqu->bitrate.fixed && target_rate > 2000000)) - rate |= TX_RATE_2_MBIT; - if (target_rate == 5500000 || - (!wrqu->bitrate.fixed && target_rate > 5500000)) - rate |= TX_RATE_5_5_MBIT; - if (target_rate == 11000000 || - (!wrqu->bitrate.fixed && target_rate > 11000000)) - rate |= TX_RATE_11_MBIT; - if (rate == 0) - rate = DEFAULT_TX_RATES; - - err = ipw2100_set_tx_rates(priv, rate, 0); - - IPW_DEBUG_WX("SET Rate -> %04X \n", rate); - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int val; - int len = sizeof(val); - int err = 0; - - if (!(priv->status & STATUS_ENABLED) || - priv->status & STATUS_RF_KILL_MASK || - !(priv->status & STATUS_ASSOCIATED)) { - wrqu->bitrate.value = 0; - return 0; - } - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len); - if (err) { - IPW_DEBUG_WX("failed querying ordinals.\n"); - goto done; - } - - switch (val & TX_RATE_MASK) { - case TX_RATE_1_MBIT: - wrqu->bitrate.value = 1000000; - break; - case TX_RATE_2_MBIT: - wrqu->bitrate.value = 2000000; - break; - case TX_RATE_5_5_MBIT: - wrqu->bitrate.value = 5500000; - break; - case TX_RATE_11_MBIT: - wrqu->bitrate.value = 11000000; - break; - default: - wrqu->bitrate.value = 0; - } - - IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int value, err; - - /* Auto RTS not yet supported */ - if (wrqu->rts.fixed == 0) - return -EINVAL; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (wrqu->rts.disabled) - value = priv->rts_threshold | RTS_DISABLED; - else { - if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) { - err = -EINVAL; - goto done; - } - value = wrqu->rts.value; - } - - err = ipw2100_set_rts_threshold(priv, value); - - IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value); - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED; - wrqu->rts.fixed = 1; /* no auto select */ - - /* If RTS is set to the default value, then it is disabled */ - wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0; - - IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value); - - return 0; -} - -static int ipw2100_wx_set_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0, value; - - if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled)) - return -EINPROGRESS; - - if (priv->ieee->iw_mode != IW_MODE_ADHOC) - return 0; - - if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) - return -EINVAL; - - if (wrqu->txpower.fixed == 0) - value = IPW_TX_POWER_DEFAULT; - else { - if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM || - wrqu->txpower.value > IPW_TX_POWER_MAX_DBM) - return -EINVAL; - - value = wrqu->txpower.value; - } - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - err = ipw2100_set_tx_power(priv, value); - - IPW_DEBUG_WX("SET TX Power -> %d \n", value); - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; - - if (priv->tx_power == IPW_TX_POWER_DEFAULT) { - wrqu->txpower.fixed = 0; - wrqu->txpower.value = IPW_TX_POWER_MAX_DBM; - } else { - wrqu->txpower.fixed = 1; - wrqu->txpower.value = priv->tx_power; - } - - wrqu->txpower.flags = IW_TXPOW_DBM; - - IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value); - - return 0; -} - -static int ipw2100_wx_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - if (!wrqu->frag.fixed) - return -EINVAL; - - if (wrqu->frag.disabled) { - priv->frag_threshold |= FRAG_DISABLED; - priv->ieee->fts = DEFAULT_FTS; - } else { - if (wrqu->frag.value < MIN_FRAG_THRESHOLD || - wrqu->frag.value > MAX_FRAG_THRESHOLD) - return -EINVAL; - - priv->ieee->fts = wrqu->frag.value & ~0x1; - priv->frag_threshold = priv->ieee->fts; - } - - IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts); - - return 0; -} - -static int ipw2100_wx_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED; - wrqu->frag.fixed = 0; /* no auto select */ - wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0; - - IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); - - return 0; -} - -static int ipw2100_wx_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0; - - if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) - return -EINVAL; - - if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) - return 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (wrqu->retry.flags & IW_RETRY_SHORT) { - err = ipw2100_set_short_retry(priv, wrqu->retry.value); - IPW_DEBUG_WX("SET Short Retry Limit -> %d \n", - wrqu->retry.value); - goto done; - } - - if (wrqu->retry.flags & IW_RETRY_LONG) { - err = ipw2100_set_long_retry(priv, wrqu->retry.value); - IPW_DEBUG_WX("SET Long Retry Limit -> %d \n", - wrqu->retry.value); - goto done; - } - - err = ipw2100_set_short_retry(priv, wrqu->retry.value); - if (!err) - err = ipw2100_set_long_retry(priv, wrqu->retry.value); - - IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value); - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - wrqu->retry.disabled = 0; /* can't be disabled */ - - if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) - return -EINVAL; - - if (wrqu->retry.flags & IW_RETRY_LONG) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - wrqu->retry.value = priv->long_retry_limit; - } else { - wrqu->retry.flags = - (priv->short_retry_limit != - priv->long_retry_limit) ? - IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT; - - wrqu->retry.value = priv->short_retry_limit; - } - - IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value); - - return 0; -} - -static int ipw2100_wx_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - IPW_DEBUG_WX("Initiating scan...\n"); - - priv->user_requested_scan = 1; - if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) { - IPW_DEBUG_WX("Start scan failed.\n"); - - /* TODO: Mark a scan as pending so when hardware initialized - * a scan starts */ - } - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); -} - -/* - * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c - */ -static int ipw2100_wx_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - /* - * No check of STATUS_INITIALIZED required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); -} - -static int ipw2100_wx_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); -} - -static int ipw2100_wx_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (wrqu->power.disabled) { - priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); - err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM); - IPW_DEBUG_WX("SET Power Management Mode -> off\n"); - goto done; - } - - switch (wrqu->power.flags & IW_POWER_MODE) { - case IW_POWER_ON: /* If not specified */ - case IW_POWER_MODE: /* If set all mask */ - case IW_POWER_ALL_R: /* If explicitly state all */ - break; - default: /* Otherwise we don't support it */ - IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", - wrqu->power.flags); - err = -EOPNOTSUPP; - goto done; - } - - /* If the user hasn't specified a power management mode yet, default - * to BATTERY */ - priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; - err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); - - IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); - - done: - mutex_unlock(&priv->action_mutex); - return err; - -} - -static int ipw2100_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - if (!(priv->power_mode & IPW_POWER_ENABLED)) - wrqu->power.disabled = 1; - else { - wrqu->power.disabled = 0; - wrqu->power.flags = 0; - } - - IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); - - return 0; -} - -/* - * WE-18 WPA support - */ - -/* SIOCSIWGENIE */ -static int ipw2100_wx_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - u8 *buf; - - if (!ieee->wpa_enabled) - return -EOPNOTSUPP; - - if (wrqu->data.length > MAX_WPA_IE_LEN || - (wrqu->data.length && extra == NULL)) - return -EINVAL; - - if (wrqu->data.length) { - buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = wrqu->data.length; - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - } - - ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); - - return 0; -} - -/* SIOCGIWGENIE */ -static int ipw2100_wx_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - - if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { - wrqu->data.length = 0; - return 0; - } - - if (wrqu->data.length < ieee->wpa_ie_len) - return -E2BIG; - - wrqu->data.length = ieee->wpa_ie_len; - memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); - - return 0; -} - -/* SIOCSIWAUTH */ -static int ipw2100_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - struct iw_param *param = &wrqu->param; - struct lib80211_crypt_data *crypt; - unsigned long flags; - int ret = 0; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * ipw2200 does not use these parameters - */ - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) - break; - - flags = crypt->ops->get_flags(crypt->priv); - - if (param->value) - flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - else - flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - - crypt->ops->set_flags(flags, crypt->priv); - - break; - - case IW_AUTH_DROP_UNENCRYPTED:{ - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - struct ieee80211_security sec = { - .flags = SEC_ENABLED, - .enabled = param->value, - }; - priv->ieee->drop_unencrypted = param->value; - /* We only change SEC_LEVEL for open mode. Others - * are set by ipw_wpa_set_encryption. - */ - if (!param->value) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_0; - } else { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } - if (priv->ieee->set_security) - priv->ieee->set_security(priv->ieee->dev, &sec); - break; - } - - case IW_AUTH_80211_AUTH_ALG: - ret = ipw2100_wpa_set_auth_algs(priv, param->value); - break; - - case IW_AUTH_WPA_ENABLED: - ret = ipw2100_wpa_enable(priv, param->value); - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ieee->ieee802_1x = param->value; - break; - - //case IW_AUTH_ROAMING_CONTROL: - case IW_AUTH_PRIVACY_INVOKED: - ieee->privacy_invoked = param->value; - break; - - default: - return -EOPNOTSUPP; - } - return ret; -} - -/* SIOCGIWAUTH */ -static int ipw2100_wx_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - struct lib80211_crypt_data *crypt; - struct iw_param *param = &wrqu->param; - int ret = 0; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * wpa_supplicant will control these internally - */ - ret = -EOPNOTSUPP; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; - if (!crypt || !crypt->ops->get_flags) { - IPW_DEBUG_WARNING("Can't get TKIP countermeasures: " - "crypt not set!\n"); - break; - } - - param->value = (crypt->ops->get_flags(crypt->priv) & - IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; - - break; - - case IW_AUTH_DROP_UNENCRYPTED: - param->value = ieee->drop_unencrypted; - break; - - case IW_AUTH_80211_AUTH_ALG: - param->value = priv->ieee->sec.auth_mode; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = ieee->wpa_enabled; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - param->value = ieee->ieee802_1x; - break; - - case IW_AUTH_ROAMING_CONTROL: - case IW_AUTH_PRIVACY_INVOKED: - param->value = ieee->privacy_invoked; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -/* SIOCSIWENCODEEXT */ -static int ipw2100_wx_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); -} - -/* SIOCGIWENCODEEXT */ -static int ipw2100_wx_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); -} - -/* SIOCSIWMLME */ -static int ipw2100_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - __le16 reason; - - reason = cpu_to_le16(mlme->reason_code); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - // silently ignore - break; - - case IW_MLME_DISASSOC: - ipw2100_disassociate_bssid(priv); - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -/* - * - * IWPRIV handlers - * - */ -#ifdef CONFIG_IPW2100_MONITOR -static int ipw2100_wx_set_promisc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int *parms = (int *)extra; - int enable = (parms[0] > 0); - int err = 0; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (enable) { - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - err = ipw2100_set_channel(priv, parms[1], 0); - goto done; - } - priv->channel = parms[1]; - err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); - } else { - if (priv->ieee->iw_mode == IW_MODE_MONITOR) - err = ipw2100_switch_mode(priv, priv->last_mode); - } - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - if (priv->status & STATUS_INITIALIZED) - schedule_reset(priv); - return 0; -} - -#endif - -static int ipw2100_wx_set_powermode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err = 0, mode = *(int *)extra; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if ((mode < 0) || (mode > POWER_MODES)) - mode = IPW_POWER_AUTO; - - if (IPW_POWER_LEVEL(priv->power_mode) != mode) - err = ipw2100_set_power_mode(priv, mode); - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -#define MAX_POWER_STRING 80 -static int ipw2100_wx_get_powermode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - int level = IPW_POWER_LEVEL(priv->power_mode); - s32 timeout, period; - - if (!(priv->power_mode & IPW_POWER_ENABLED)) { - snprintf(extra, MAX_POWER_STRING, - "Power save level: %d (Off)", level); - } else { - switch (level) { - case IPW_POWER_MODE_CAM: - snprintf(extra, MAX_POWER_STRING, - "Power save level: %d (None)", level); - break; - case IPW_POWER_AUTO: - snprintf(extra, MAX_POWER_STRING, - "Power save level: %d (Auto)", level); - break; - default: - timeout = timeout_duration[level - 1] / 1000; - period = period_duration[level - 1] / 1000; - snprintf(extra, MAX_POWER_STRING, - "Power save level: %d " - "(Timeout %dms, Period %dms)", - level, timeout, period); - } - } - - wrqu->data.length = strlen(extra) + 1; - - return 0; -} - -static int ipw2100_wx_set_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err, mode = *(int *)extra; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (mode == 1) - priv->config |= CFG_LONG_PREAMBLE; - else if (mode == 0) - priv->config &= ~CFG_LONG_PREAMBLE; - else { - err = -EINVAL; - goto done; - } - - err = ipw2100_system_config(priv, 0); - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - if (priv->config & CFG_LONG_PREAMBLE) - snprintf(wrqu->name, IFNAMSIZ, "long (1)"); - else - snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); - - return 0; -} - -#ifdef CONFIG_IPW2100_MONITOR -static int ipw2100_wx_set_crc_check(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - int err, mode = *(int *)extra; - - mutex_lock(&priv->action_mutex); - if (!(priv->status & STATUS_INITIALIZED)) { - err = -EIO; - goto done; - } - - if (mode == 1) - priv->config |= CFG_CRC_CHECK; - else if (mode == 0) - priv->config &= ~CFG_CRC_CHECK; - else { - err = -EINVAL; - goto done; - } - err = 0; - - done: - mutex_unlock(&priv->action_mutex); - return err; -} - -static int ipw2100_wx_get_crc_check(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * This can be called at any time. No action lock required - */ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - - if (priv->config & CFG_CRC_CHECK) - snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)"); - else - snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)"); - - return 0; -} -#endif /* CONFIG_IPW2100_MONITOR */ - -static iw_handler ipw2100_wx_handlers[] = { - NULL, /* SIOCSIWCOMMIT */ - ipw2100_wx_get_name, /* SIOCGIWNAME */ - NULL, /* SIOCSIWNWID */ - NULL, /* SIOCGIWNWID */ - ipw2100_wx_set_freq, /* SIOCSIWFREQ */ - ipw2100_wx_get_freq, /* SIOCGIWFREQ */ - ipw2100_wx_set_mode, /* SIOCSIWMODE */ - ipw2100_wx_get_mode, /* SIOCGIWMODE */ - NULL, /* SIOCSIWSENS */ - NULL, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - ipw2100_wx_get_range, /* SIOCGIWRANGE */ - NULL, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ - NULL, /* SIOCSIWSPY */ - NULL, /* SIOCGIWSPY */ - NULL, /* SIOCGIWTHRSPY */ - NULL, /* SIOCWIWTHRSPY */ - ipw2100_wx_set_wap, /* SIOCSIWAP */ - ipw2100_wx_get_wap, /* SIOCGIWAP */ - ipw2100_wx_set_mlme, /* SIOCSIWMLME */ - NULL, /* SIOCGIWAPLIST -- deprecated */ - ipw2100_wx_set_scan, /* SIOCSIWSCAN */ - ipw2100_wx_get_scan, /* SIOCGIWSCAN */ - ipw2100_wx_set_essid, /* SIOCSIWESSID */ - ipw2100_wx_get_essid, /* SIOCGIWESSID */ - ipw2100_wx_set_nick, /* SIOCSIWNICKN */ - ipw2100_wx_get_nick, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - ipw2100_wx_set_rate, /* SIOCSIWRATE */ - ipw2100_wx_get_rate, /* SIOCGIWRATE */ - ipw2100_wx_set_rts, /* SIOCSIWRTS */ - ipw2100_wx_get_rts, /* SIOCGIWRTS */ - ipw2100_wx_set_frag, /* SIOCSIWFRAG */ - ipw2100_wx_get_frag, /* SIOCGIWFRAG */ - ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */ - ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */ - ipw2100_wx_set_retry, /* SIOCSIWRETRY */ - ipw2100_wx_get_retry, /* SIOCGIWRETRY */ - ipw2100_wx_set_encode, /* SIOCSIWENCODE */ - ipw2100_wx_get_encode, /* SIOCGIWENCODE */ - ipw2100_wx_set_power, /* SIOCSIWPOWER */ - ipw2100_wx_get_power, /* SIOCGIWPOWER */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - ipw2100_wx_set_genie, /* SIOCSIWGENIE */ - ipw2100_wx_get_genie, /* SIOCGIWGENIE */ - ipw2100_wx_set_auth, /* SIOCSIWAUTH */ - ipw2100_wx_get_auth, /* SIOCGIWAUTH */ - ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */ - ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */ - NULL, /* SIOCSIWPMKSA */ -}; - -#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV -#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1 -#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2 -#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3 -#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4 -#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5 -#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6 -#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7 - -static const struct iw_priv_args ipw2100_private_args[] = { - -#ifdef CONFIG_IPW2100_MONITOR - { - IPW2100_PRIV_SET_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, - { - IPW2100_PRIV_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, -#endif /* CONFIG_IPW2100_MONITOR */ - - { - IPW2100_PRIV_SET_POWER, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"}, - { - IPW2100_PRIV_GET_POWER, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, - "get_power"}, - { - IPW2100_PRIV_SET_LONGPREAMBLE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"}, - { - IPW2100_PRIV_GET_LONGPREAMBLE, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"}, -#ifdef CONFIG_IPW2100_MONITOR - { - IPW2100_PRIV_SET_CRC_CHECK, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"}, - { - IPW2100_PRIV_GET_CRC_CHECK, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"}, -#endif /* CONFIG_IPW2100_MONITOR */ -}; - -static iw_handler ipw2100_private_handler[] = { -#ifdef CONFIG_IPW2100_MONITOR - ipw2100_wx_set_promisc, - ipw2100_wx_reset, -#else /* CONFIG_IPW2100_MONITOR */ - NULL, - NULL, -#endif /* CONFIG_IPW2100_MONITOR */ - ipw2100_wx_set_powermode, - ipw2100_wx_get_powermode, - ipw2100_wx_set_preamble, - ipw2100_wx_get_preamble, -#ifdef CONFIG_IPW2100_MONITOR - ipw2100_wx_set_crc_check, - ipw2100_wx_get_crc_check, -#else /* CONFIG_IPW2100_MONITOR */ - NULL, - NULL, -#endif /* CONFIG_IPW2100_MONITOR */ -}; - -/* - * Get wireless statistics. - * Called by /proc/net/wireless - * Also called by SIOCGIWSTATS - */ -static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) -{ - enum { - POOR = 30, - FAIR = 60, - GOOD = 80, - VERY_GOOD = 90, - EXCELLENT = 95, - PERFECT = 100 - }; - int rssi_qual; - int tx_qual; - int beacon_qual; - - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct iw_statistics *wstats; - u32 rssi, quality, tx_retries, missed_beacons, tx_failures; - u32 ord_len = sizeof(u32); - - if (!priv) - return (struct iw_statistics *)NULL; - - wstats = &priv->wstats; - - /* if hw is disabled, then ipw2100_get_ordinal() can't be called. - * ipw2100_wx_wireless_stats seems to be called before fw is - * initialized. STATUS_ASSOCIATED will only be set if the hw is up - * and associated; if not associcated, the values are all meaningless - * anyway, so set them all to NULL and INVALID */ - if (!(priv->status & STATUS_ASSOCIATED)) { - wstats->miss.beacon = 0; - wstats->discard.retries = 0; - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = 7; - wstats->qual.updated |= IW_QUAL_NOISE_INVALID | - IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; - return wstats; - } - - if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS, - &missed_beacons, &ord_len)) - goto fail_get_ordinal; - - /* If we don't have a connection the quality and level is 0 */ - if (!(priv->status & STATUS_ASSOCIATED)) { - wstats->qual.qual = 0; - wstats->qual.level = 0; - } else { - if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR, - &rssi, &ord_len)) - goto fail_get_ordinal; - wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM; - if (rssi < 10) - rssi_qual = rssi * POOR / 10; - else if (rssi < 15) - rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR; - else if (rssi < 20) - rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR; - else if (rssi < 30) - rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) / - 10 + GOOD; - else - rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) / - 10 + VERY_GOOD; - - if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES, - &tx_retries, &ord_len)) - goto fail_get_ordinal; - - if (tx_retries > 75) - tx_qual = (90 - tx_retries) * POOR / 15; - else if (tx_retries > 70) - tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; - else if (tx_retries > 65) - tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; - else if (tx_retries > 50) - tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / - 15 + GOOD; - else - tx_qual = (50 - tx_retries) * - (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; - - if (missed_beacons > 50) - beacon_qual = (60 - missed_beacons) * POOR / 10; - else if (missed_beacons > 40) - beacon_qual = (50 - missed_beacons) * (FAIR - POOR) / - 10 + POOR; - else if (missed_beacons > 32) - beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) / - 18 + FAIR; - else if (missed_beacons > 20) - beacon_qual = (32 - missed_beacons) * - (VERY_GOOD - GOOD) / 20 + GOOD; - else - beacon_qual = (20 - missed_beacons) * - (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; - - quality = min(beacon_qual, min(tx_qual, rssi_qual)); - -#ifdef CONFIG_IPW2100_DEBUG - if (beacon_qual == quality) - IPW_DEBUG_WX("Quality clamped by Missed Beacons\n"); - else if (tx_qual == quality) - IPW_DEBUG_WX("Quality clamped by Tx Retries\n"); - else if (quality != 100) - IPW_DEBUG_WX("Quality clamped by Signal Strength\n"); - else - IPW_DEBUG_WX("Quality not clamped.\n"); -#endif - - wstats->qual.qual = quality; - wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM; - } - - wstats->qual.noise = 0; - wstats->qual.updated = 7; - wstats->qual.updated |= IW_QUAL_NOISE_INVALID; - - /* FIXME: this is percent and not a # */ - wstats->miss.beacon = missed_beacons; - - if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES, - &tx_failures, &ord_len)) - goto fail_get_ordinal; - wstats->discard.retries = tx_failures; - - return wstats; - - fail_get_ordinal: - IPW_DEBUG_WX("failed querying ordinals.\n"); - - return (struct iw_statistics *)NULL; -} - -static struct iw_handler_def ipw2100_wx_handler_def = { - .standard = ipw2100_wx_handlers, - .num_standard = ARRAY_SIZE(ipw2100_wx_handlers), - .num_private = ARRAY_SIZE(ipw2100_private_handler), - .num_private_args = ARRAY_SIZE(ipw2100_private_args), - .private = (iw_handler *) ipw2100_private_handler, - .private_args = (struct iw_priv_args *)ipw2100_private_args, - .get_wireless_stats = ipw2100_wx_wireless_stats, -}; - -static void ipw2100_wx_event_work(struct work_struct *work) -{ - struct ipw2100_priv *priv = - container_of(work, struct ipw2100_priv, wx_event_work.work); - union iwreq_data wrqu; - int len = ETH_ALEN; - - if (priv->status & STATUS_STOPPING) - return; - - mutex_lock(&priv->action_mutex); - - IPW_DEBUG_WX("enter\n"); - - mutex_unlock(&priv->action_mutex); - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - - /* Fetch BSSID from the hardware */ - if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) || - priv->status & STATUS_RF_KILL_MASK || - ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, - &priv->bssid, &len)) { - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); - } else { - /* We now have the BSSID, so can finish setting to the full - * associated state */ - memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); - memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN); - priv->status &= ~STATUS_ASSOCIATING; - priv->status |= STATUS_ASSOCIATED; - netif_carrier_on(priv->net_dev); - netif_wake_queue(priv->net_dev); - } - - if (!(priv->status & STATUS_ASSOCIATED)) { - IPW_DEBUG_WX("Configuring ESSID\n"); - mutex_lock(&priv->action_mutex); - /* This is a disassociation event, so kick the firmware to - * look for another AP */ - if (priv->config & CFG_STATIC_ESSID) - ipw2100_set_essid(priv, priv->essid, priv->essid_len, - 0); - else - ipw2100_set_essid(priv, NULL, 0, 0); - mutex_unlock(&priv->action_mutex); - } - - wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); -} - -#define IPW2100_FW_MAJOR_VERSION 1 -#define IPW2100_FW_MINOR_VERSION 3 - -#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8) -#define IPW2100_FW_MAJOR(x) (x & 0xff) - -#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \ - IPW2100_FW_MAJOR_VERSION) - -#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \ -"." __stringify(IPW2100_FW_MINOR_VERSION) - -#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw" - -/* - -BINARY FIRMWARE HEADER FORMAT - -offset length desc -0 2 version -2 2 mode == 0:BSS,1:IBSS,2:MONITOR -4 4 fw_len -8 4 uc_len -C fw_len firmware data -12 + fw_len uc_len microcode data - -*/ - -struct ipw2100_fw_header { - short version; - short mode; - unsigned int fw_size; - unsigned int uc_size; -} __attribute__ ((packed)); - -static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) -{ - struct ipw2100_fw_header *h = - (struct ipw2100_fw_header *)fw->fw_entry->data; - - if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) { - printk(KERN_WARNING DRV_NAME ": Firmware image not compatible " - "(detected version id of %u). " - "See Documentation/networking/README.ipw2100\n", - h->version); - return 1; - } - - fw->version = h->version; - fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header); - fw->fw.size = h->fw_size; - fw->uc.data = fw->fw.data + h->fw_size; - fw->uc.size = h->uc_size; - - return 0; -} - -static int ipw2100_get_firmware(struct ipw2100_priv *priv, - struct ipw2100_fw *fw) -{ - char *fw_name; - int rc; - - IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n", - priv->net_dev->name); - - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - fw_name = IPW2100_FW_NAME("-i"); - break; -#ifdef CONFIG_IPW2100_MONITOR - case IW_MODE_MONITOR: - fw_name = IPW2100_FW_NAME("-p"); - break; -#endif - case IW_MODE_INFRA: - default: - fw_name = IPW2100_FW_NAME(""); - break; - } - - rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev); - - if (rc < 0) { - printk(KERN_ERR DRV_NAME ": " - "%s: Firmware '%s' not available or load failed.\n", - priv->net_dev->name, fw_name); - return rc; - } - IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data, - fw->fw_entry->size); - - ipw2100_mod_firmware_load(fw); - - return 0; -} - -static void ipw2100_release_firmware(struct ipw2100_priv *priv, - struct ipw2100_fw *fw) -{ - fw->version = 0; - if (fw->fw_entry) - release_firmware(fw->fw_entry); - fw->fw_entry = NULL; -} - -static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, - size_t max) -{ - char ver[MAX_FW_VERSION_LEN]; - u32 len = MAX_FW_VERSION_LEN; - u32 tmp; - int i; - /* firmware version is an ascii string (max len of 14) */ - if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len)) - return -EIO; - tmp = max; - if (len >= max) - len = max - 1; - for (i = 0; i < len; i++) - buf[i] = ver[i]; - buf[i] = '\0'; - return tmp; -} - -static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, - size_t max) -{ - u32 ver; - u32 len = sizeof(ver); - /* microcode version is a 32 bit integer */ - if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len)) - return -EIO; - return snprintf(buf, max, "%08X", ver); -} - -/* - * On exit, the firmware will have been freed from the fw list - */ -static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw) -{ - /* firmware is constructed of N contiguous entries, each entry is - * structured as: - * - * offset sie desc - * 0 4 address to write to - * 4 2 length of data run - * 6 length data - */ - unsigned int addr; - unsigned short len; - - const unsigned char *firmware_data = fw->fw.data; - unsigned int firmware_data_left = fw->fw.size; - - while (firmware_data_left > 0) { - addr = *(u32 *) (firmware_data); - firmware_data += 4; - firmware_data_left -= 4; - - len = *(u16 *) (firmware_data); - firmware_data += 2; - firmware_data_left -= 2; - - if (len > 32) { - printk(KERN_ERR DRV_NAME ": " - "Invalid firmware run-length of %d bytes\n", - len); - return -EINVAL; - } - - write_nic_memory(priv->net_dev, addr, len, firmware_data); - firmware_data += len; - firmware_data_left -= len; - } - - return 0; -} - -struct symbol_alive_response { - u8 cmd_id; - u8 seq_num; - u8 ucode_rev; - u8 eeprom_valid; - u16 valid_flags; - u8 IEEE_addr[6]; - u16 flags; - u16 pcb_rev; - u16 clock_settle_time; // 1us LSB - u16 powerup_settle_time; // 1us LSB - u16 hop_settle_time; // 1us LSB - u8 date[3]; // month, day, year - u8 time[2]; // hours, minutes - u8 ucode_valid; -}; - -static int ipw2100_ucode_download(struct ipw2100_priv *priv, - struct ipw2100_fw *fw) -{ - struct net_device *dev = priv->net_dev; - const unsigned char *microcode_data = fw->uc.data; - unsigned int microcode_data_left = fw->uc.size; - void __iomem *reg = (void __iomem *)dev->base_addr; - - struct symbol_alive_response response; - int i, j; - u8 data; - - /* Symbol control */ - write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); - readl(reg); - write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); - readl(reg); - - /* HW config */ - write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ - readl(reg); - write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ - readl(reg); - - /* EN_CS_ACCESS bit to reset control store pointer */ - write_nic_byte(dev, 0x210000, 0x40); - readl(reg); - write_nic_byte(dev, 0x210000, 0x0); - readl(reg); - write_nic_byte(dev, 0x210000, 0x40); - readl(reg); - - /* copy microcode from buffer into Symbol */ - - while (microcode_data_left > 0) { - write_nic_byte(dev, 0x210010, *microcode_data++); - write_nic_byte(dev, 0x210010, *microcode_data++); - microcode_data_left -= 2; - } - - /* EN_CS_ACCESS bit to reset the control store pointer */ - write_nic_byte(dev, 0x210000, 0x0); - readl(reg); - - /* Enable System (Reg 0) - * first enable causes garbage in RX FIFO */ - write_nic_byte(dev, 0x210000, 0x0); - readl(reg); - write_nic_byte(dev, 0x210000, 0x80); - readl(reg); - - /* Reset External Baseband Reg */ - write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); - readl(reg); - write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); - readl(reg); - - /* HW Config (Reg 5) */ - write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 - readl(reg); - write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 - readl(reg); - - /* Enable System (Reg 0) - * second enable should be OK */ - write_nic_byte(dev, 0x210000, 0x00); // clear enable system - readl(reg); - write_nic_byte(dev, 0x210000, 0x80); // set enable system - - /* check Symbol is enabled - upped this from 5 as it wasn't always - * catching the update */ - for (i = 0; i < 10; i++) { - udelay(10); - - /* check Dino is enabled bit */ - read_nic_byte(dev, 0x210000, &data); - if (data & 0x1) - break; - } - - if (i == 10) { - printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n", - dev->name); - return -EIO; - } - - /* Get Symbol alive response */ - for (i = 0; i < 30; i++) { - /* Read alive response structure */ - for (j = 0; - j < (sizeof(struct symbol_alive_response) >> 1); j++) - read_nic_word(dev, 0x210004, ((u16 *) & response) + j); - - if ((response.cmd_id == 1) && (response.ucode_valid == 0x1)) - break; - udelay(10); - } - - if (i == 30) { - printk(KERN_ERR DRV_NAME - ": %s: No response from Symbol - hw not alive\n", - dev->name); - printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response)); - return -EIO; - } - - return 0; -} diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h deleted file mode 100644 index bbf1ddc..0000000 --- a/drivers/net/wireless/ipw2100.h +++ /dev/null @@ -1,1162 +0,0 @@ -/****************************************************************************** - - Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - 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; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - James P. Ketrenos - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -******************************************************************************/ -#ifndef _IPW2100_H -#define _IPW2100_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // new driver API - -#include - -#ifdef CONFIG_IPW2100_MONITOR -#include -#endif - -#include -#include - -struct ipw2100_priv; -struct ipw2100_tx_packet; -struct ipw2100_rx_packet; - -#define IPW_DL_UNINIT 0x80000000 -#define IPW_DL_NONE 0x00000000 -#define IPW_DL_ALL 0x7FFFFFFF - -/* - * To use the debug system; - * - * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: - * - * #define IPW_DL_xxxx VALUE - * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) - * - * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your - * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want - * to send output to that classification. - * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/ipw2100/debug_level - * - * you simply need to add your entry to the ipw2100_debug_levels array. - * - * If you do not see debug_level in /proc/net/ipw2100 then you do not have - * CONFIG_IPW2100_DEBUG defined in your kernel configuration - * - */ - -#define IPW_DL_ERROR (1<<0) -#define IPW_DL_WARNING (1<<1) -#define IPW_DL_INFO (1<<2) -#define IPW_DL_WX (1<<3) -#define IPW_DL_HC (1<<5) -#define IPW_DL_STATE (1<<6) - -#define IPW_DL_NOTIF (1<<10) -#define IPW_DL_SCAN (1<<11) -#define IPW_DL_ASSOC (1<<12) -#define IPW_DL_DROP (1<<13) - -#define IPW_DL_IOCTL (1<<14) -#define IPW_DL_RF_KILL (1<<17) - -#define IPW_DL_MANAGE (1<<15) -#define IPW_DL_FW (1<<16) - -#define IPW_DL_FRAG (1<<21) -#define IPW_DL_WEP (1<<22) -#define IPW_DL_TX (1<<23) -#define IPW_DL_RX (1<<24) -#define IPW_DL_ISR (1<<25) -#define IPW_DL_IO (1<<26) -#define IPW_DL_TRACE (1<<28) - -#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) -#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) -#define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f) -#define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f) -#define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f) -#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f) -#define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f) -#define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f) -#define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f) -#define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f) -#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f) -#define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f) -#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f) -#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f) -#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f) -#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f) -#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f) -#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f) -#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f) -#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) -#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) - -enum { - IPW_HW_STATE_DISABLED = 1, - IPW_HW_STATE_ENABLED = 0 -}; - -struct ssid_context { - char ssid[IW_ESSID_MAX_SIZE + 1]; - int ssid_len; - unsigned char bssid[ETH_ALEN]; - int port_type; - int channel; - -}; - -extern const char *port_type_str[]; -extern const char *band_str[]; - -#define NUMBER_OF_BD_PER_COMMAND_PACKET 1 -#define NUMBER_OF_BD_PER_DATA_PACKET 2 - -#define IPW_MAX_BDS 6 -#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2 -#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1 - -#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \ - (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET) - -struct bd_status { - union { - struct { - u8 nlf:1, txType:2, intEnabled:1, reserved:4; - } fields; - u8 field; - } info; -} __attribute__ ((packed)); - -struct ipw2100_bd { - u32 host_addr; - u32 buf_length; - struct bd_status status; - /* number of fragments for frame (should be set only for - * 1st TBD) */ - u8 num_fragments; - u8 reserved[6]; -} __attribute__ ((packed)); - -#define IPW_BD_QUEUE_LENGTH(n) (1<value = (x)->hi = 0; \ - (x)->lo = 0x7fffffff; \ -} while (0) -#define SET_STAT(x,y) do { \ - (x)->value = y; \ - if ((x)->value > (x)->hi) (x)->hi = (x)->value; \ - if ((x)->value < (x)->lo) (x)->lo = (x)->value; \ -} while (0) -#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \ -while (0) -#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \ -while (0) - -#define IPW2100_ERROR_QUEUE 5 - -/* Power management code: enable or disable? */ -enum { -#ifdef CONFIG_PM - IPW2100_PM_DISABLED = 0, - PM_STATE_SIZE = 16, -#else - IPW2100_PM_DISABLED = 1, - PM_STATE_SIZE = 0, -#endif -}; - -#define STATUS_POWERED (1<<0) -#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */ -#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */ -#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */ -#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */ -#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */ -#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */ -#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */ -#define STATUS_INT_ENABLED (1<<11) -#define STATUS_RF_KILL_HW (1<<12) -#define STATUS_RF_KILL_SW (1<<13) -#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW) -#define STATUS_EXIT_PENDING (1<<14) - -#define STATUS_SCAN_PENDING (1<<23) -#define STATUS_SCANNING (1<<24) -#define STATUS_SCAN_ABORTING (1<<25) -#define STATUS_SCAN_COMPLETE (1<<26) -#define STATUS_WX_EVENT_PENDING (1<<27) -#define STATUS_RESET_PENDING (1<<29) -#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */ - -/* Internal NIC states */ -#define IPW_STATE_INITIALIZED (1<<0) -#define IPW_STATE_COUNTRY_FOUND (1<<1) -#define IPW_STATE_ASSOCIATED (1<<2) -#define IPW_STATE_ASSN_LOST (1<<3) -#define IPW_STATE_ASSN_CHANGED (1<<4) -#define IPW_STATE_SCAN_COMPLETE (1<<5) -#define IPW_STATE_ENTERED_PSP (1<<6) -#define IPW_STATE_LEFT_PSP (1<<7) -#define IPW_STATE_RF_KILL (1<<8) -#define IPW_STATE_DISABLED (1<<9) -#define IPW_STATE_POWER_DOWN (1<<10) -#define IPW_STATE_SCANNING (1<<11) - -#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ -#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ -#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ -#define CFG_CUSTOM_MAC (1<<3) -#define CFG_LONG_PREAMBLE (1<<4) -#define CFG_ASSOCIATE (1<<6) -#define CFG_FIXED_RATE (1<<7) -#define CFG_ADHOC_CREATE (1<<8) -#define CFG_PASSIVE_SCAN (1<<10) -#ifdef CONFIG_IPW2100_MONITOR -#define CFG_CRC_CHECK (1<<11) -#endif - -#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ -#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ - -struct ipw2100_priv { - - int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ - int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ - - struct ieee80211_device *ieee; - unsigned long status; - unsigned long config; - unsigned long capability; - - /* Statistics */ - int resets; - int reset_backoff; - - /* Context */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; - u8 bssid[ETH_ALEN]; - u8 channel; - int last_mode; - - unsigned long connect_start; - unsigned long last_reset; - - u32 channel_mask; - u32 fatal_error; - u32 fatal_errors[IPW2100_ERROR_QUEUE]; - u32 fatal_index; - int eeprom_version; - int firmware_version; - unsigned long hw_features; - int hangs; - u32 last_rtc; - int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */ - u8 *snapshot[0x30]; - - u8 mandatory_bssid_mac[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; - - int power_mode; - - int messages_sent; - - int short_retry_limit; - int long_retry_limit; - - u32 rts_threshold; - u32 frag_threshold; - - int in_isr; - - u32 tx_rates; - int tx_power; - u32 beacon_interval; - - char nick[IW_ESSID_MAX_SIZE + 1]; - - struct ipw2100_status_queue status_queue; - - struct statistic txq_stat; - struct statistic rxq_stat; - struct ipw2100_bd_queue rx_queue; - struct ipw2100_bd_queue tx_queue; - struct ipw2100_rx_packet *rx_buffers; - - struct statistic fw_pend_stat; - struct list_head fw_pend_list; - - struct statistic msg_free_stat; - struct statistic msg_pend_stat; - struct list_head msg_free_list; - struct list_head msg_pend_list; - struct ipw2100_tx_packet *msg_buffers; - - struct statistic tx_free_stat; - struct statistic tx_pend_stat; - struct list_head tx_free_list; - struct list_head tx_pend_list; - struct ipw2100_tx_packet *tx_buffers; - - struct ipw2100_ordinals ordinals; - - struct pci_dev *pci_dev; - - struct proc_dir_entry *dir_dev; - - struct net_device *net_dev; - struct iw_statistics wstats; - - struct iw_public_data wireless_data; - - struct tasklet_struct irq_tasklet; - - struct workqueue_struct *workqueue; - struct delayed_work reset_work; - struct delayed_work security_work; - struct delayed_work wx_event_work; - struct delayed_work hang_check; - struct delayed_work rf_kill; - struct work_struct scan_event_now; - struct delayed_work scan_event_later; - - int user_requested_scan; - - u32 interrupts; - int tx_interrupts; - int rx_interrupts; - int inta_other; - - spinlock_t low_lock; - struct mutex action_mutex; - struct mutex adapter_mutex; - - wait_queue_head_t wait_command_queue; -}; - -/********************************************************* - * Host Command -> From Driver to FW - *********************************************************/ - -/** - * Host command identifiers - */ -#define HOST_COMPLETE 2 -#define SYSTEM_CONFIG 6 -#define SSID 8 -#define MANDATORY_BSSID 9 -#define AUTHENTICATION_TYPE 10 -#define ADAPTER_ADDRESS 11 -#define PORT_TYPE 12 -#define INTERNATIONAL_MODE 13 -#define CHANNEL 14 -#define RTS_THRESHOLD 15 -#define FRAG_THRESHOLD 16 -#define POWER_MODE 17 -#define TX_RATES 18 -#define BASIC_TX_RATES 19 -#define WEP_KEY_INFO 20 -#define WEP_KEY_INDEX 25 -#define WEP_FLAGS 26 -#define ADD_MULTICAST 27 -#define CLEAR_ALL_MULTICAST 28 -#define BEACON_INTERVAL 29 -#define ATIM_WINDOW 30 -#define CLEAR_STATISTICS 31 -#define SEND 33 -#define TX_POWER_INDEX 36 -#define BROADCAST_SCAN 43 -#define CARD_DISABLE 44 -#define PREFERRED_BSSID 45 -#define SET_SCAN_OPTIONS 46 -#define SCAN_DWELL_TIME 47 -#define SWEEP_TABLE 48 -#define AP_OR_STATION_TABLE 49 -#define GROUP_ORDINALS 50 -#define SHORT_RETRY_LIMIT 51 -#define LONG_RETRY_LIMIT 52 - -#define HOST_PRE_POWER_DOWN 58 -#define CARD_DISABLE_PHY_OFF 61 -#define MSDU_TX_RATES 62 - -/* Rogue AP Detection */ -#define SET_STATION_STAT_BITS 64 -#define CLEAR_STATIONS_STAT_BITS 65 -#define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP -#define SET_SECURITY_INFORMATION 67 -#define DISASSOCIATION_BSSID 68 -#define SET_WPA_IE 69 - -/* system configuration bit mask: */ -#define IPW_CFG_MONITOR 0x00004 -#define IPW_CFG_PREAMBLE_AUTO 0x00010 -#define IPW_CFG_IBSS_AUTO_START 0x00020 -#define IPW_CFG_LOOPBACK 0x00100 -#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800 -#define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000 -#define IPW_CFG_802_1x_ENABLE 0x04000 -#define IPW_CFG_BSS_MASK 0x08000 -#define IPW_CFG_IBSS_MASK 0x10000 - -#define IPW_SCAN_NOASSOCIATE (1<<0) -#define IPW_SCAN_MIXED_CELL (1<<1) -/* RESERVED (1<<2) */ -#define IPW_SCAN_PASSIVE (1<<3) - -#define IPW_NIC_FATAL_ERROR 0x2A7F0 -#define IPW_ERROR_ADDR(x) (x & 0x3FFFF) -#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24) -#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24) -#define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24) -#define IPW2100_ERR_FW_LOAD (0x12 << 24) - -#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200 -#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80 - -#define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40) -#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44) -#define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48) -#define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0) - -#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00) -#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04) -#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80) - -#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \ - (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20) - -#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \ - (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND) - -#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180) -#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184) - -#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB) -#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1 -#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2 -#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3 -#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4 -#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5 -#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16 -#define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24 -#define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25 -#define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30 -#define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB) - -#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001) -#define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002) -#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004) -#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008) -#define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080) -#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100) -#define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200) - -#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB) -#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1 -#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2 -#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10 -#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9 -#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10 -#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29 -#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30 -#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB) - -#define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C -#define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0 -#define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008 -#define IPW_BIT_GPIO_RF_KILL 0x00010000 - -#define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1 - -#define IPW_REG_DOMAIN_0_OFFSET 0x0000 -#define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND - -#define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008 -#define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C -#define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010 -#define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014 -#define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018 -#define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C -#define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020 -#define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024 -#define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030 -#define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188 -#define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C -#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 - -#define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC - -#define IPW_INTERRUPT_MASK 0xC1010013 - -#define IPW2100_CONTROL_REG 0x220000 -#define IPW2100_CONTROL_PHY_OFF 0x8 - -#define IPW2100_COMMAND 0x00300004 -#define IPW2100_COMMAND_PHY_ON 0x0 -#define IPW2100_COMMAND_PHY_OFF 0x1 - -/* in DEBUG_AREA, values of memory always 0xd55555d5 */ -#define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090 -#define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF -#define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5 - -#define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0 - -#define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds -#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds -#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds - -// BD ring queue read/write difference -#define IPW_BD_QUEUE_W_R_MIN_SPARE 2 - -#define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80 - -#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli -#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli - -#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr) -#define IPW_MAX_80211_PAYLOAD_SIZE 2304U -#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312 -#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536 -#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60 -#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \ - (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \ - sizeof(struct ethhdr)) - -#define IPW_802_11_FCS_LENGTH 4 -#define IPW_RX_NIC_BUFFER_LENGTH \ - (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \ - IPW_802_11_FCS_LENGTH) - -#define IPW_802_11_PAYLOAD_OFFSET \ - (sizeof(struct ieee80211_hdr_3addr) + \ - sizeof(struct ieee80211_snap_hdr)) - -struct ipw2100_rx { - union { - unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; - struct ieee80211_hdr_4addr header; - u32 status; - struct ipw2100_notification notification; - struct ipw2100_cmd_header command; - } rx_data; -} __attribute__ ((packed)); - -/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */ -#define TX_RATE_1_MBIT 0x0001 -#define TX_RATE_2_MBIT 0x0002 -#define TX_RATE_5_5_MBIT 0x0004 -#define TX_RATE_11_MBIT 0x0008 -#define TX_RATE_MASK 0x000F -#define DEFAULT_TX_RATES 0x000F - -#define IPW_POWER_MODE_CAM 0x00 //(always on) -#define IPW_POWER_INDEX_1 0x01 -#define IPW_POWER_INDEX_2 0x02 -#define IPW_POWER_INDEX_3 0x03 -#define IPW_POWER_INDEX_4 0x04 -#define IPW_POWER_INDEX_5 0x05 -#define IPW_POWER_AUTO 0x06 -#define IPW_POWER_MASK 0x0F -#define IPW_POWER_ENABLED 0x10 -#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK) - -#define IPW_TX_POWER_AUTO 0 -#define IPW_TX_POWER_ENHANCED 1 - -#define IPW_TX_POWER_DEFAULT 32 -#define IPW_TX_POWER_MIN 0 -#define IPW_TX_POWER_MAX 16 -#define IPW_TX_POWER_MIN_DBM (-12) -#define IPW_TX_POWER_MAX_DBM 16 - -#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan -#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan - -#define REG_MIN_CHANNEL 0 -#define REG_MAX_CHANNEL 14 - -#define REG_CHANNEL_MASK 0x00003FFF -#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff - -#define DIVERSITY_EITHER 0 // Use both antennas -#define DIVERSITY_ANTENNA_A 1 // Use antenna A -#define DIVERSITY_ANTENNA_B 2 // Use antenna B - -#define HOST_COMMAND_WAIT 0 -#define HOST_COMMAND_NO_WAIT 1 - -#define LOCK_NONE 0 -#define LOCK_DRIVER 1 -#define LOCK_FW 2 - -#define TYPE_SWEEP_ORD 0x000D -#define TYPE_IBSS_STTN_ORD 0x000E -#define TYPE_BSS_AP_ORD 0x000F -#define TYPE_RAW_BEACON_ENTRY 0x0010 -#define TYPE_CALIBRATION_DATA 0x0011 -#define TYPE_ROGUE_AP_DATA 0x0012 -#define TYPE_ASSOCIATION_REQUEST 0x0013 -#define TYPE_REASSOCIATION_REQUEST 0x0014 - -#define HW_FEATURE_RFKILL 0x0001 -#define RF_KILLSWITCH_OFF 1 -#define RF_KILLSWITCH_ON 0 - -#define IPW_COMMAND_POOL_SIZE 40 - -#define IPW_START_ORD_TAB_1 1 -#define IPW_START_ORD_TAB_2 1000 - -#define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32) - -#define IS_ORDINAL_TABLE_ONE(mgr,id) \ - ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size)) -#define IS_ORDINAL_TABLE_TWO(mgr,id) \ - ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2))) - -#define BSS_ID_LENGTH 6 - -// Fixed size data: Ordinal Table 1 -typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW -// Transmit statistics - IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU) - IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU) - IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU) - - IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB - IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB - IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB - IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB - IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB - - IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB - IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB - IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB - IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB - - IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's - IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS - IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS - IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK - IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's - IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's - IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's - IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's - IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted - IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted - IPW_ORD_STAT_TX_BEACON, // # of tx beacon - IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM - IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX - IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx - IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX - - IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes - IPW_ORD_STAT_TX_RETRIES, // # of Tx retries - IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS - IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS - IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS - IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS - - IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures - IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time - IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed - IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup - IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted - IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed - IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames - IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent - IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks - - // Receive statistics - IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host - IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets - IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB - IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB - IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB - IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB - IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB - - IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets - IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB - IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB - IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB - IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB - - IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's - IPW_ORD_STAT_RX_POLL, //NS // # of poll rx - IPW_ORD_STAT_RX_RTS, // # of Rx RTS - IPW_ORD_STAT_RX_CTS, // # of Rx CTS - IPW_ORD_STAT_RX_ACK, // # of Rx ACK - IPW_ORD_STAT_RX_CFEND, // # of Rx CF End - IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack - IPW_ORD_STAT_RX_ASSN, // # of Association Rx's - IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's - IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's - IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's - IPW_ORD_STAT_RX_PROBE, // # of probe Rx's - IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's - IPW_ORD_STAT_RX_BEACON, // # of Rx beacon - IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM - IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx - IPW_ORD_STAT_RX_AUTH, // # of authentication Rx - IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx - - IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received - IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error - IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB - IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB - IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB - IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB - - IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB - IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB - IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB - IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB - IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets - - IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db - IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db - IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db - IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol - IPW_ORD_SYS_BOOT_TIME, // # Boot time - IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer - IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late - IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop - IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment - IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment - IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame - IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame - IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused) - IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption - -// PSP Statistics - IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended - IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout - IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts - IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt - IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received - IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received - IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID - -// Association and roaming - IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association - IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons - IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries - IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated - // AP table entry. set to 0 if not associated - IPW_ORD_AVAILABLE_AP_CNT, // # of AP's decsribed in the AP table - IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs - IPW_ORD_STAT_AP_ASSNS, // # of associations - IPW_ORD_STAT_ASSN_FAIL, // # of association failures - IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail - IPW_ORD_STAT_FULL_SCANS, // # of full scans - - IPW_ORD_CARD_DISABLED, // # Card Disabled - IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity - IPW_FILLER_40, - IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association - IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N - // hops or no prob_ responses in last 3 minutes - IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality - IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive - // load at the AP - IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below - // eligible group - IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling - IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap - IPW_FILLER_41, - IPW_FILLER_42, - IPW_FILLER_43, - IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed - IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed - IPW_ORD_STATION_TABLE_CNT, // # of entries in association table - -// Other statistics - IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI - IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word - IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word - IPW_ORD_SELF_TEST_STATUS, //NS // - IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP - IPW_ORD_POWER_MGMT_INDEX, //NS // - IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon - IPW_ORD_COUNTRY_CHANNELS, // channels suported by country -// IPW_ORD_COUNTRY_CHANNELS: -// For 11b the lower 2-byte are used for channels from 1-14 -// and the higher 2-byte are not used. - IPW_ORD_RESET_CNT, // # of adapter resets (warm) - IPW_ORD_BEACON_INTERVAL, // Beacon interval - - IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version - IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled - IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed) - IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated - IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs - IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID - - IPW_ORD_RTC_TIME = 190, // current RTC time - IPW_ORD_PORT_TYPE, // operating mode - IPW_ORD_CURRENT_TX_RATE, // current tx rate - IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates - IPW_ORD_ATIM_WINDOW, // current ATIM Window - IPW_ORD_BASIC_RATES, // bitmap of basic tx rates - IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates - IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates - IPW_ORD_CAPABILITIES, // Management frame capability field - IPW_ORD_AUTH_TYPE, // Type of authentication - IPW_ORD_RADIO_TYPE, // Adapter card platform type - IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used - IPW_ORD_INT_MODE, // International mode - IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold - IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM - IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM - IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 = - IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set - - IPW_ORD_MAC_VERSION = 209, // MAC Version - IPW_ORD_MAC_REVISION, // MAC Revision - IPW_ORD_RADIO_VERSION, // Radio Version - IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP - IPW_ORD_UCODE_VERSION, // Ucode Version - IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State -} ORDINALTABLE1; - -// ordinal table 2 -// Variable length data: -#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001 - -typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW - IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs - IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address - IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP - IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP - IPW_FILL_1, //NS // - IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code - IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String - IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans) - IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans) - IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log - IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log - IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures - IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011") - IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002") - IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP - IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes: - IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII - IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date - IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018, -} ORDINALTABLE2; // NS - means Not Supported by FW - -#define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018 - -#ifndef WIRELESS_SPY -#define WIRELESS_SPY // enable iwspy support -#endif - -#define IPW_HOST_FW_SHARED_AREA0 0x0002f200 -#define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes - -#define IPW_HOST_FW_SHARED_AREA1 0x0002f610 -#define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes - -#define IPW_HOST_FW_SHARED_AREA2 0x0002fa00 -#define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes - -#define IPW_HOST_FW_SHARED_AREA3 0x0002fc00 -#define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes - -#define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80 -#define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes - -struct ipw2100_fw_chunk { - unsigned char *buf; - long len; - long pos; - struct list_head list; -}; - -struct ipw2100_fw_chunk_set { - const void *data; - unsigned long size; -}; - -struct ipw2100_fw { - int version; - struct ipw2100_fw_chunk_set fw; - struct ipw2100_fw_chunk_set uc; - const struct firmware *fw_entry; -}; - -#define MAX_FW_VERSION_LEN 14 - -#endif /* _IPW2100_H */ diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c deleted file mode 100644 index d2a2b75..0000000 --- a/drivers/net/wireless/ipw2200.c +++ /dev/null @@ -1,11984 +0,0 @@ -/****************************************************************************** - - Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - - 802.11 status code portion of this file from ethereal-0.10.6: - Copyright 2000, Axis Communications AB - Ethereal - Network traffic analyzer - By Gerald Combs - Copyright 1998 Gerald Combs - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - 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; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - James P. Ketrenos - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -******************************************************************************/ - -#include "ipw2200.h" - - -#ifndef KBUILD_EXTMOD -#define VK "k" -#else -#define VK -#endif - -#ifdef CONFIG_IPW2200_DEBUG -#define VD "d" -#else -#define VD -#endif - -#ifdef CONFIG_IPW2200_MONITOR -#define VM "m" -#else -#define VM -#endif - -#ifdef CONFIG_IPW2200_PROMISCUOUS -#define VP "p" -#else -#define VP -#endif - -#ifdef CONFIG_IPW2200_RADIOTAP -#define VR "r" -#else -#define VR -#endif - -#ifdef CONFIG_IPW2200_QOS -#define VQ "q" -#else -#define VQ -#endif - -#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ -#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" -#define DRV_VERSION IPW2200_VERSION - -#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1) - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL"); - -static int cmdlog = 0; -static int debug = 0; -static int channel = 0; -static int mode = 0; - -static u32 ipw_debug_level; -static int associate; -static int auto_create = 1; -static int led = 0; -static int disable = 0; -static int bt_coexist = 0; -static int hwcrypto = 0; -static int roaming = 1; -static const char ipw_modes[] = { - 'a', 'b', 'g', '?' -}; -static int antenna = CFG_SYS_ANTENNA_BOTH; - -#ifdef CONFIG_IPW2200_PROMISCUOUS -static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ -#endif - - -#ifdef CONFIG_IPW2200_QOS -static int qos_enable = 0; -static int qos_burst_enable = 0; -static int qos_no_ack_mask = 0; -static int burst_duration_CCK = 0; -static int burst_duration_OFDM = 0; - -static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { - {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM, - QOS_TX3_CW_MIN_OFDM}, - {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM, - QOS_TX3_CW_MAX_OFDM}, - {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, - {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, - {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM, - QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM} -}; - -static struct ieee80211_qos_parameters def_qos_parameters_CCK = { - {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK, - QOS_TX3_CW_MIN_CCK}, - {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK, - QOS_TX3_CW_MAX_CCK}, - {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, - {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, - {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK, - QOS_TX3_TXOP_LIMIT_CCK} -}; - -static struct ieee80211_qos_parameters def_parameters_OFDM = { - {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM, - DEF_TX3_CW_MIN_OFDM}, - {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM, - DEF_TX3_CW_MAX_OFDM}, - {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, - {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, - {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM, - DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM} -}; - -static struct ieee80211_qos_parameters def_parameters_CCK = { - {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK, - DEF_TX3_CW_MIN_CCK}, - {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK, - DEF_TX3_CW_MAX_CCK}, - {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, - {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, - {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK, - DEF_TX3_TXOP_LIMIT_CCK} -}; - -static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; - -static int from_priority_to_tx_queue[] = { - IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1, - IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4 -}; - -static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv); - -static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters - *qos_param); -static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element - *qos_param); -#endif /* CONFIG_IPW2200_QOS */ - -static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev); -static void ipw_remove_current_network(struct ipw_priv *priv); -static void ipw_rx(struct ipw_priv *priv); -static int ipw_queue_tx_reclaim(struct ipw_priv *priv, - struct clx2_tx_queue *txq, int qindex); -static int ipw_queue_reset(struct ipw_priv *priv); - -static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, - int len, int sync); - -static void ipw_tx_queue_free(struct ipw_priv *); - -static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); -static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); -static void ipw_rx_queue_replenish(void *); -static int ipw_up(struct ipw_priv *); -static void ipw_bg_up(struct work_struct *work); -static void ipw_down(struct ipw_priv *); -static void ipw_bg_down(struct work_struct *work); -static int ipw_config(struct ipw_priv *); -static int init_supported_rates(struct ipw_priv *priv, - struct ipw_supported_rates *prates); -static void ipw_set_hwcrypto_keys(struct ipw_priv *); -static void ipw_send_wep_keys(struct ipw_priv *, int); - -static int snprint_line(char *buf, size_t count, - const u8 * data, u32 len, u32 ofs) -{ - int out, i, j, l; - char c; - - out = snprintf(buf, count, "%08X", ofs); - - for (l = 0, i = 0; i < 2; i++) { - out += snprintf(buf + out, count - out, " "); - for (j = 0; j < 8 && l < len; j++, l++) - out += snprintf(buf + out, count - out, "%02X ", - data[(i * 8 + j)]); - for (; j < 8; j++) - out += snprintf(buf + out, count - out, " "); - } - - out += snprintf(buf + out, count - out, " "); - for (l = 0, i = 0; i < 2; i++) { - out += snprintf(buf + out, count - out, " "); - for (j = 0; j < 8 && l < len; j++, l++) { - c = data[(i * 8 + j)]; - if (!isascii(c) || !isprint(c)) - c = '.'; - - out += snprintf(buf + out, count - out, "%c", c); - } - - for (; j < 8; j++) - out += snprintf(buf + out, count - out, " "); - } - - return out; -} - -static void printk_buf(int level, const u8 * data, u32 len) -{ - char line[81]; - u32 ofs = 0; - if (!(ipw_debug_level & level)) - return; - - while (len) { - snprint_line(line, sizeof(line), &data[ofs], - min(len, 16U), ofs); - printk(KERN_DEBUG "%s\n", line); - ofs += 16; - len -= min(len, 16U); - } -} - -static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len) -{ - size_t out = size; - u32 ofs = 0; - int total = 0; - - while (size && len) { - out = snprint_line(output, size, &data[ofs], - min_t(size_t, len, 16U), ofs); - - ofs += 16; - output += out; - size -= out; - len -= min_t(size_t, len, 16U); - total += out; - } - return total; -} - -/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ -static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); -#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) - -/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ -static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg); -#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b) - -/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ -static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value); -static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) -{ - IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__, - __LINE__, (u32) (b), (u32) (c)); - _ipw_write_reg8(a, b, c); -} - -/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ -static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value); -static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) -{ - IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__, - __LINE__, (u32) (b), (u32) (c)); - _ipw_write_reg16(a, b, c); -} - -/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ -static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value); -static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) -{ - IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__, - __LINE__, (u32) (b), (u32) (c)); - _ipw_write_reg32(a, b, c); -} - -/* 8-bit direct write (low 4K) */ -#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) - -/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ -#define ipw_write8(ipw, ofs, val) do { \ - IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ - _ipw_write8(ipw, ofs, val); \ - } while (0) - -/* 16-bit direct write (low 4K) */ -#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) - -/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ -#define ipw_write16(ipw, ofs, val) \ - IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ - _ipw_write16(ipw, ofs, val) - -/* 32-bit direct write (low 4K) */ -#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) - -/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ -#define ipw_write32(ipw, ofs, val) \ - IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ - _ipw_write32(ipw, ofs, val) - -/* 8-bit direct read (low 4K) */ -#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) - -/* 8-bit direct read (low 4K), with debug wrapper */ -static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) -{ - IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs)); - return _ipw_read8(ipw, ofs); -} - -/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ -#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) - -/* 16-bit direct read (low 4K) */ -#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) - -/* 16-bit direct read (low 4K), with debug wrapper */ -static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) -{ - IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs)); - return _ipw_read16(ipw, ofs); -} - -/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ -#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) - -/* 32-bit direct read (low 4K) */ -#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) - -/* 32-bit direct read (low 4K), with debug wrapper */ -static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) -{ - IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs)); - return _ipw_read32(ipw, ofs); -} - -/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ -#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) - -/* multi-byte read (above 4K), with debug wrapper */ -static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); -static inline void __ipw_read_indirect(const char *f, int l, - struct ipw_priv *a, u32 b, u8 * c, int d) -{ - IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b), - d); - _ipw_read_indirect(a, b, c, d); -} - -/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ -#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d) - -/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ -static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, - int num); -#define ipw_write_indirect(a, b, c, d) \ - IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ - _ipw_write_indirect(a, b, c, d) - -/* 32-bit indirect write (above 4K) */ -static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) -{ - IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); - _ipw_write32(priv, IPW_INDIRECT_DATA, value); -} - -/* 8-bit indirect write (above 4K) */ -static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) -{ - u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ - u32 dif_len = reg - aligned_addr; - - IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value); -} - -/* 16-bit indirect write (above 4K) */ -static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) -{ - u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ - u32 dif_len = (reg - aligned_addr) & (~0x1ul); - - IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value); -} - -/* 8-bit indirect read (above 4K) */ -static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) -{ - u32 word; - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); - IPW_DEBUG_IO(" reg = 0x%8X : \n", reg); - word = _ipw_read32(priv, IPW_INDIRECT_DATA); - return (word >> ((reg & 0x3) * 8)) & 0xff; -} - -/* 32-bit indirect read (above 4K) */ -static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) -{ - u32 value; - - IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg); - - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); - value = _ipw_read32(priv, IPW_INDIRECT_DATA); - IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value); - return value; -} - -/* General purpose, no alignment requirement, iterative (multi-byte) read, */ -/* for area above 1st 4K of SRAM/reg space */ -static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, - int num) -{ - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ - u32 dif_len = addr - aligned_addr; - u32 i; - - IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); - - if (num <= 0) { - return; - } - - /* Read the first dword (or portion) byte by byte */ - if (unlikely(dif_len)) { - _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - /* Start reading at aligned_addr + dif_len */ - for (i = dif_len; ((i < 4) && (num > 0)); i++, num--) - *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i); - aligned_addr += 4; - } - - /* Read all of the middle dwords as dwords, with auto-increment */ - _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); - for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) - *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA); - - /* Read the last dword (or portion) byte by byte */ - if (unlikely(num)) { - _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - for (i = 0; num > 0; i++, num--) - *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i); - } -} - -/* General purpose, no alignment requirement, iterative (multi-byte) write, */ -/* for area above 1st 4K of SRAM/reg space */ -static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, - int num) -{ - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ - u32 dif_len = addr - aligned_addr; - u32 i; - - IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); - - if (num <= 0) { - return; - } - - /* Write the first dword (or portion) byte by byte */ - if (unlikely(dif_len)) { - _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - /* Start writing at aligned_addr + dif_len */ - for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) - _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); - aligned_addr += 4; - } - - /* Write all of the middle dwords as dwords, with auto-increment */ - _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); - for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) - _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf); - - /* Write the last dword (or portion) byte by byte */ - if (unlikely(num)) { - _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - for (i = 0; num > 0; i++, num--, buf++) - _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); - } -} - -/* General purpose, no alignment requirement, iterative (multi-byte) write, */ -/* for 1st 4K of SRAM/regs space */ -static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, - int num) -{ - memcpy_toio((priv->hw_base + addr), buf, num); -} - -/* Set bit(s) in low 4K of SRAM/regs */ -static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask) -{ - ipw_write32(priv, reg, ipw_read32(priv, reg) | mask); -} - -/* Clear bit(s) in low 4K of SRAM/regs */ -static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) -{ - ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); -} - -static inline void __ipw_enable_interrupts(struct ipw_priv *priv) -{ - if (priv->status & STATUS_INT_ENABLED) - return; - priv->status |= STATUS_INT_ENABLED; - ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); -} - -static inline void __ipw_disable_interrupts(struct ipw_priv *priv) -{ - if (!(priv->status & STATUS_INT_ENABLED)) - return; - priv->status &= ~STATUS_INT_ENABLED; - ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); -} - -static inline void ipw_enable_interrupts(struct ipw_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->irq_lock, flags); - __ipw_enable_interrupts(priv); - spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void ipw_disable_interrupts(struct ipw_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->irq_lock, flags); - __ipw_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static char *ipw_error_desc(u32 val) -{ - switch (val) { - case IPW_FW_ERROR_OK: - return "ERROR_OK"; - case IPW_FW_ERROR_FAIL: - return "ERROR_FAIL"; - case IPW_FW_ERROR_MEMORY_UNDERFLOW: - return "MEMORY_UNDERFLOW"; - case IPW_FW_ERROR_MEMORY_OVERFLOW: - return "MEMORY_OVERFLOW"; - case IPW_FW_ERROR_BAD_PARAM: - return "BAD_PARAM"; - case IPW_FW_ERROR_BAD_CHECKSUM: - return "BAD_CHECKSUM"; - case IPW_FW_ERROR_NMI_INTERRUPT: - return "NMI_INTERRUPT"; - case IPW_FW_ERROR_BAD_DATABASE: - return "BAD_DATABASE"; - case IPW_FW_ERROR_ALLOC_FAIL: - return "ALLOC_FAIL"; - case IPW_FW_ERROR_DMA_UNDERRUN: - return "DMA_UNDERRUN"; - case IPW_FW_ERROR_DMA_STATUS: - return "DMA_STATUS"; - case IPW_FW_ERROR_DINO_ERROR: - return "DINO_ERROR"; - case IPW_FW_ERROR_EEPROM_ERROR: - return "EEPROM_ERROR"; - case IPW_FW_ERROR_SYSASSERT: - return "SYSASSERT"; - case IPW_FW_ERROR_FATAL_ERROR: - return "FATAL_ERROR"; - default: - return "UNKNOWN_ERROR"; - } -} - -static void ipw_dump_error_log(struct ipw_priv *priv, - struct ipw_fw_error *error) -{ - u32 i; - - if (!error) { - IPW_ERROR("Error allocating and capturing error log. " - "Nothing to dump.\n"); - return; - } - - IPW_ERROR("Start IPW Error Log Dump:\n"); - IPW_ERROR("Status: 0x%08X, Config: %08X\n", - error->status, error->config); - - for (i = 0; i < error->elem_len; i++) - IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", - ipw_error_desc(error->elem[i].desc), - error->elem[i].time, - error->elem[i].blink1, - error->elem[i].blink2, - error->elem[i].link1, - error->elem[i].link2, error->elem[i].data); - for (i = 0; i < error->log_len; i++) - IPW_ERROR("%i\t0x%08x\t%i\n", - error->log[i].time, - error->log[i].data, error->log[i].event); -} - -static inline int ipw_is_init(struct ipw_priv *priv) -{ - return (priv->status & STATUS_INIT) ? 1 : 0; -} - -static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len) -{ - u32 addr, field_info, field_len, field_count, total_len; - - IPW_DEBUG_ORD("ordinal = %i\n", ord); - - if (!priv || !val || !len) { - IPW_DEBUG_ORD("Invalid argument\n"); - return -EINVAL; - } - - /* verify device ordinal tables have been initialized */ - if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) { - IPW_DEBUG_ORD("Access ordinals before initialization\n"); - return -EINVAL; - } - - switch (IPW_ORD_TABLE_ID_MASK & ord) { - case IPW_ORD_TABLE_0_MASK: - /* - * TABLE 0: Direct access to a table of 32 bit values - * - * This is a very simple table with the data directly - * read from the table - */ - - /* remove the table id from the ordinal */ - ord &= IPW_ORD_TABLE_VALUE_MASK; - - /* boundary check */ - if (ord > priv->table0_len) { - IPW_DEBUG_ORD("ordinal value (%i) longer then " - "max (%i)\n", ord, priv->table0_len); - return -EINVAL; - } - - /* verify we have enough room to store the value */ - if (*len < sizeof(u32)) { - IPW_DEBUG_ORD("ordinal buffer length too small, " - "need %zd\n", sizeof(u32)); - return -EINVAL; - } - - IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n", - ord, priv->table0_addr + (ord << 2)); - - *len = sizeof(u32); - ord <<= 2; - *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord); - break; - - case IPW_ORD_TABLE_1_MASK: - /* - * TABLE 1: Indirect access to a table of 32 bit values - * - * This is a fairly large table of u32 values each - * representing starting addr for the data (which is - * also a u32) - */ - - /* remove the table id from the ordinal */ - ord &= IPW_ORD_TABLE_VALUE_MASK; - - /* boundary check */ - if (ord > priv->table1_len) { - IPW_DEBUG_ORD("ordinal value too long\n"); - return -EINVAL; - } - - /* verify we have enough room to store the value */ - if (*len < sizeof(u32)) { - IPW_DEBUG_ORD("ordinal buffer length too small, " - "need %zd\n", sizeof(u32)); - return -EINVAL; - } - - *((u32 *) val) = - ipw_read_reg32(priv, (priv->table1_addr + (ord << 2))); - *len = sizeof(u32); - break; - - case IPW_ORD_TABLE_2_MASK: - /* - * TABLE 2: Indirect access to a table of variable sized values - * - * This table consist of six values, each containing - * - dword containing the starting offset of the data - * - dword containing the lengh in the first 16bits - * and the count in the second 16bits - */ - - /* remove the table id from the ordinal */ - ord &= IPW_ORD_TABLE_VALUE_MASK; - - /* boundary check */ - if (ord > priv->table2_len) { - IPW_DEBUG_ORD("ordinal value too long\n"); - return -EINVAL; - } - - /* get the address of statistic */ - addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3)); - - /* get the second DW of statistics ; - * two 16-bit words - first is length, second is count */ - field_info = - ipw_read_reg32(priv, - priv->table2_addr + (ord << 3) + - sizeof(u32)); - - /* get each entry length */ - field_len = *((u16 *) & field_info); - - /* get number of entries */ - field_count = *(((u16 *) & field_info) + 1); - - /* abort if not enought memory */ - total_len = field_len * field_count; - if (total_len > *len) { - *len = total_len; - return -EINVAL; - } - - *len = total_len; - if (!total_len) - return 0; - - IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, " - "field_info = 0x%08x\n", - addr, total_len, field_info); - ipw_read_indirect(priv, addr, val, total_len); - break; - - default: - IPW_DEBUG_ORD("Invalid ordinal!\n"); - return -EINVAL; - - } - - return 0; -} - -static void ipw_init_ordinals(struct ipw_priv *priv) -{ - priv->table0_addr = IPW_ORDINALS_TABLE_LOWER; - priv->table0_len = ipw_read32(priv, priv->table0_addr); - - IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n", - priv->table0_addr, priv->table0_len); - - priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1); - priv->table1_len = ipw_read_reg32(priv, priv->table1_addr); - - IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n", - priv->table1_addr, priv->table1_len); - - priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2); - priv->table2_len = ipw_read_reg32(priv, priv->table2_addr); - priv->table2_len &= 0x0000ffff; /* use first two bytes */ - - IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n", - priv->table2_addr, priv->table2_len); - -} - -static u32 ipw_register_toggle(u32 reg) -{ - reg &= ~IPW_START_STANDBY; - if (reg & IPW_GATE_ODMA) - reg &= ~IPW_GATE_ODMA; - if (reg & IPW_GATE_IDMA) - reg &= ~IPW_GATE_IDMA; - if (reg & IPW_GATE_ADMA) - reg &= ~IPW_GATE_ADMA; - return reg; -} - -/* - * LED behavior: - * - On radio ON, turn on any LEDs that require to be on during start - * - On initialization, start unassociated blink - * - On association, disable unassociated blink - * - On disassociation, start unassociated blink - * - On radio OFF, turn off any LEDs started during radio on - * - */ -#define LD_TIME_LINK_ON msecs_to_jiffies(300) -#define LD_TIME_LINK_OFF msecs_to_jiffies(2700) -#define LD_TIME_ACT_ON msecs_to_jiffies(250) - -static void ipw_led_link_on(struct ipw_priv *priv) -{ - unsigned long flags; - u32 led; - - /* If configured to not use LEDs, or nic_type is 1, - * then we don't toggle a LINK led */ - if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) - return; - - spin_lock_irqsave(&priv->lock, flags); - - if (!(priv->status & STATUS_RF_KILL_MASK) && - !(priv->status & STATUS_LED_LINK_ON)) { - IPW_DEBUG_LED("Link LED On\n"); - led = ipw_read_reg32(priv, IPW_EVENT_REG); - led |= priv->led_association_on; - - led = ipw_register_toggle(led); - - IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, IPW_EVENT_REG, led); - - priv->status |= STATUS_LED_LINK_ON; - - /* If we aren't associated, schedule turning the LED off */ - if (!(priv->status & STATUS_ASSOCIATED)) - queue_delayed_work(priv->workqueue, - &priv->led_link_off, - LD_TIME_LINK_ON); - } - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void ipw_bg_led_link_on(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, led_link_on.work); - mutex_lock(&priv->mutex); - ipw_led_link_on(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_led_link_off(struct ipw_priv *priv) -{ - unsigned long flags; - u32 led; - - /* If configured not to use LEDs, or nic type is 1, - * then we don't goggle the LINK led. */ - if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) - return; - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->status & STATUS_LED_LINK_ON) { - led = ipw_read_reg32(priv, IPW_EVENT_REG); - led &= priv->led_association_off; - led = ipw_register_toggle(led); - - IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, IPW_EVENT_REG, led); - - IPW_DEBUG_LED("Link LED Off\n"); - - priv->status &= ~STATUS_LED_LINK_ON; - - /* If we aren't associated and the radio is on, schedule - * turning the LED on (blink while unassociated) */ - if (!(priv->status & STATUS_RF_KILL_MASK) && - !(priv->status & STATUS_ASSOCIATED)) - queue_delayed_work(priv->workqueue, &priv->led_link_on, - LD_TIME_LINK_OFF); - - } - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void ipw_bg_led_link_off(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, led_link_off.work); - mutex_lock(&priv->mutex); - ipw_led_link_off(priv); - mutex_unlock(&priv->mutex); -} - -static void __ipw_led_activity_on(struct ipw_priv *priv) -{ - u32 led; - - if (priv->config & CFG_NO_LED) - return; - - if (priv->status & STATUS_RF_KILL_MASK) - return; - - if (!(priv->status & STATUS_LED_ACT_ON)) { - led = ipw_read_reg32(priv, IPW_EVENT_REG); - led |= priv->led_activity_on; - - led = ipw_register_toggle(led); - - IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, IPW_EVENT_REG, led); - - IPW_DEBUG_LED("Activity LED On\n"); - - priv->status |= STATUS_LED_ACT_ON; - - cancel_delayed_work(&priv->led_act_off); - queue_delayed_work(priv->workqueue, &priv->led_act_off, - LD_TIME_ACT_ON); - } else { - /* Reschedule LED off for full time period */ - cancel_delayed_work(&priv->led_act_off); - queue_delayed_work(priv->workqueue, &priv->led_act_off, - LD_TIME_ACT_ON); - } -} - -#if 0 -void ipw_led_activity_on(struct ipw_priv *priv) -{ - unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - __ipw_led_activity_on(priv); - spin_unlock_irqrestore(&priv->lock, flags); -} -#endif /* 0 */ - -static void ipw_led_activity_off(struct ipw_priv *priv) -{ - unsigned long flags; - u32 led; - - if (priv->config & CFG_NO_LED) - return; - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->status & STATUS_LED_ACT_ON) { - led = ipw_read_reg32(priv, IPW_EVENT_REG); - led &= priv->led_activity_off; - - led = ipw_register_toggle(led); - - IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, IPW_EVENT_REG, led); - - IPW_DEBUG_LED("Activity LED Off\n"); - - priv->status &= ~STATUS_LED_ACT_ON; - } - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void ipw_bg_led_activity_off(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, led_act_off.work); - mutex_lock(&priv->mutex); - ipw_led_activity_off(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_led_band_on(struct ipw_priv *priv) -{ - unsigned long flags; - u32 led; - - /* Only nic type 1 supports mode LEDs */ - if (priv->config & CFG_NO_LED || - priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network) - return; - - spin_lock_irqsave(&priv->lock, flags); - - led = ipw_read_reg32(priv, IPW_EVENT_REG); - if (priv->assoc_network->mode == IEEE_A) { - led |= priv->led_ofdm_on; - led &= priv->led_association_off; - IPW_DEBUG_LED("Mode LED On: 802.11a\n"); - } else if (priv->assoc_network->mode == IEEE_G) { - led |= priv->led_ofdm_on; - led |= priv->led_association_on; - IPW_DEBUG_LED("Mode LED On: 802.11g\n"); - } else { - led &= priv->led_ofdm_off; - led |= priv->led_association_on; - IPW_DEBUG_LED("Mode LED On: 802.11b\n"); - } - - led = ipw_register_toggle(led); - - IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, IPW_EVENT_REG, led); - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void ipw_led_band_off(struct ipw_priv *priv) -{ - unsigned long flags; - u32 led; - - /* Only nic type 1 supports mode LEDs */ - if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) - return; - - spin_lock_irqsave(&priv->lock, flags); - - led = ipw_read_reg32(priv, IPW_EVENT_REG); - led &= priv->led_ofdm_off; - led &= priv->led_association_off; - - led = ipw_register_toggle(led); - - IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, IPW_EVENT_REG, led); - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void ipw_led_radio_on(struct ipw_priv *priv) -{ - ipw_led_link_on(priv); -} - -static void ipw_led_radio_off(struct ipw_priv *priv) -{ - ipw_led_activity_off(priv); - ipw_led_link_off(priv); -} - -static void ipw_led_link_up(struct ipw_priv *priv) -{ - /* Set the Link Led on for all nic types */ - ipw_led_link_on(priv); -} - -static void ipw_led_link_down(struct ipw_priv *priv) -{ - ipw_led_activity_off(priv); - ipw_led_link_off(priv); - - if (priv->status & STATUS_RF_KILL_MASK) - ipw_led_radio_off(priv); -} - -static void ipw_led_init(struct ipw_priv *priv) -{ - priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; - - /* Set the default PINs for the link and activity leds */ - priv->led_activity_on = IPW_ACTIVITY_LED; - priv->led_activity_off = ~(IPW_ACTIVITY_LED); - - priv->led_association_on = IPW_ASSOCIATED_LED; - priv->led_association_off = ~(IPW_ASSOCIATED_LED); - - /* Set the default PINs for the OFDM leds */ - priv->led_ofdm_on = IPW_OFDM_LED; - priv->led_ofdm_off = ~(IPW_OFDM_LED); - - switch (priv->nic_type) { - case EEPROM_NIC_TYPE_1: - /* In this NIC type, the LEDs are reversed.... */ - priv->led_activity_on = IPW_ASSOCIATED_LED; - priv->led_activity_off = ~(IPW_ASSOCIATED_LED); - priv->led_association_on = IPW_ACTIVITY_LED; - priv->led_association_off = ~(IPW_ACTIVITY_LED); - - if (!(priv->config & CFG_NO_LED)) - ipw_led_band_on(priv); - - /* And we don't blink link LEDs for this nic, so - * just return here */ - return; - - case EEPROM_NIC_TYPE_3: - case EEPROM_NIC_TYPE_2: - case EEPROM_NIC_TYPE_4: - case EEPROM_NIC_TYPE_0: - break; - - default: - IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n", - priv->nic_type); - priv->nic_type = EEPROM_NIC_TYPE_0; - break; - } - - if (!(priv->config & CFG_NO_LED)) { - if (priv->status & STATUS_ASSOCIATED) - ipw_led_link_on(priv); - else - ipw_led_link_off(priv); - } -} - -static void ipw_led_shutdown(struct ipw_priv *priv) -{ - ipw_led_activity_off(priv); - ipw_led_link_off(priv); - ipw_led_band_off(priv); - cancel_delayed_work(&priv->led_link_on); - cancel_delayed_work(&priv->led_link_off); - cancel_delayed_work(&priv->led_act_off); -} - -/* - * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) - * used for controling the debug level. - * - * See the level definitions in ipw for details. - */ -static ssize_t show_debug_level(struct device_driver *d, char *buf) -{ - return sprintf(buf, "0x%08X\n", ipw_debug_level); -} - -static ssize_t store_debug_level(struct device_driver *d, const char *buf, - size_t count) -{ - char *p = (char *)buf; - u32 val; - - if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { - p++; - if (p[0] == 'x' || p[0] == 'X') - p++; - val = simple_strtoul(p, &p, 16); - } else - val = simple_strtoul(p, &p, 10); - if (p == buf) - printk(KERN_INFO DRV_NAME - ": %s is not in hex or decimal form.\n", buf); - else - ipw_debug_level = val; - - return strnlen(buf, count); -} - -static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); - -static inline u32 ipw_get_event_log_len(struct ipw_priv *priv) -{ - /* length = 1st dword in log */ - return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG)); -} - -static void ipw_capture_event_log(struct ipw_priv *priv, - u32 log_len, struct ipw_event *log) -{ - u32 base; - - if (log_len) { - base = ipw_read32(priv, IPW_EVENT_LOG); - ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32), - (u8 *) log, sizeof(*log) * log_len); - } -} - -static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv) -{ - struct ipw_fw_error *error; - u32 log_len = ipw_get_event_log_len(priv); - u32 base = ipw_read32(priv, IPW_ERROR_LOG); - u32 elem_len = ipw_read_reg32(priv, base); - - error = kmalloc(sizeof(*error) + - sizeof(*error->elem) * elem_len + - sizeof(*error->log) * log_len, GFP_ATOMIC); - if (!error) { - IPW_ERROR("Memory allocation for firmware error log " - "failed.\n"); - return NULL; - } - error->jiffies = jiffies; - error->status = priv->status; - error->config = priv->config; - error->elem_len = elem_len; - error->log_len = log_len; - error->elem = (struct ipw_error_elem *)error->payload; - error->log = (struct ipw_event *)(error->elem + elem_len); - - ipw_capture_event_log(priv, log_len, error->log); - - if (elem_len) - ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem, - sizeof(*error->elem) * elem_len); - - return error; -} - -static ssize_t show_event_log(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - u32 log_len = ipw_get_event_log_len(priv); - u32 log_size; - struct ipw_event *log; - u32 len = 0, i; - - /* not using min() because of its strict type checking */ - log_size = PAGE_SIZE / sizeof(*log) > log_len ? - sizeof(*log) * log_len : PAGE_SIZE; - log = kzalloc(log_size, GFP_KERNEL); - if (!log) { - IPW_ERROR("Unable to allocate memory for log\n"); - return 0; - } - log_len = log_size / sizeof(*log); - ipw_capture_event_log(priv, log_len, log); - - len += snprintf(buf + len, PAGE_SIZE - len, "%08X", log_len); - for (i = 0; i < log_len; i++) - len += snprintf(buf + len, PAGE_SIZE - len, - "\n%08X%08X%08X", - log[i].time, log[i].event, log[i].data); - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); - kfree(log); - return len; -} - -static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL); - -static ssize_t show_error(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - u32 len = 0, i; - if (!priv->error) - return 0; - len += snprintf(buf + len, PAGE_SIZE - len, - "%08lX%08X%08X%08X", - priv->error->jiffies, - priv->error->status, - priv->error->config, priv->error->elem_len); - for (i = 0; i < priv->error->elem_len; i++) - len += snprintf(buf + len, PAGE_SIZE - len, - "\n%08X%08X%08X%08X%08X%08X%08X", - priv->error->elem[i].time, - priv->error->elem[i].desc, - priv->error->elem[i].blink1, - priv->error->elem[i].blink2, - priv->error->elem[i].link1, - priv->error->elem[i].link2, - priv->error->elem[i].data); - - len += snprintf(buf + len, PAGE_SIZE - len, - "\n%08X", priv->error->log_len); - for (i = 0; i < priv->error->log_len; i++) - len += snprintf(buf + len, PAGE_SIZE - len, - "\n%08X%08X%08X", - priv->error->log[i].time, - priv->error->log[i].event, - priv->error->log[i].data); - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); - return len; -} - -static ssize_t clear_error(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - - kfree(priv->error); - priv->error = NULL; - return count; -} - -static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error); - -static ssize_t show_cmd_log(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - u32 len = 0, i; - if (!priv->cmdlog) - return 0; - for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len; - (i != priv->cmdlog_pos) && (PAGE_SIZE - len); - i = (i + 1) % priv->cmdlog_len) { - len += - snprintf(buf + len, PAGE_SIZE - len, - "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies, - priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd, - priv->cmdlog[i].cmd.len); - len += - snprintk_buf(buf + len, PAGE_SIZE - len, - (u8 *) priv->cmdlog[i].cmd.param, - priv->cmdlog[i].cmd.len); - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); - } - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); - return len; -} - -static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); - -#ifdef CONFIG_IPW2200_PROMISCUOUS -static void ipw_prom_free(struct ipw_priv *priv); -static int ipw_prom_alloc(struct ipw_priv *priv); -static ssize_t store_rtap_iface(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - int rc = 0; - - if (count < 1) - return -EINVAL; - - switch (buf[0]) { - case '0': - if (!rtap_iface) - return count; - - if (netif_running(priv->prom_net_dev)) { - IPW_WARNING("Interface is up. Cannot unregister.\n"); - return count; - } - - ipw_prom_free(priv); - rtap_iface = 0; - break; - - case '1': - if (rtap_iface) - return count; - - rc = ipw_prom_alloc(priv); - if (!rc) - rtap_iface = 1; - break; - - default: - return -EINVAL; - } - - if (rc) { - IPW_ERROR("Failed to register promiscuous network " - "device (error %d).\n", rc); - } - - return count; -} - -static ssize_t show_rtap_iface(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - if (rtap_iface) - return sprintf(buf, "%s", priv->prom_net_dev->name); - else { - buf[0] = '-'; - buf[1] = '1'; - buf[2] = '\0'; - return 3; - } -} - -static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface, - store_rtap_iface); - -static ssize_t store_rtap_filter(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - - if (!priv->prom_priv) { - IPW_ERROR("Attempting to set filter without " - "rtap_iface enabled.\n"); - return -EPERM; - } - - priv->prom_priv->filter = simple_strtol(buf, NULL, 0); - - IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n", - BIT_ARG16(priv->prom_priv->filter)); - - return count; -} - -static ssize_t show_rtap_filter(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "0x%04X", - priv->prom_priv ? priv->prom_priv->filter : 0); -} - -static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter, - store_rtap_filter); -#endif - -static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%d\n", priv->ieee->scan_age); -} - -static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - struct net_device *dev = priv->net_dev; - char buffer[] = "00000000"; - unsigned long len = - (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; - unsigned long val; - char *p = buffer; - - IPW_DEBUG_INFO("enter\n"); - - strncpy(buffer, buf, len); - buffer[len] = 0; - - if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { - p++; - if (p[0] == 'x' || p[0] == 'X') - p++; - val = simple_strtoul(p, &p, 16); - } else - val = simple_strtoul(p, &p, 10); - if (p == buffer) { - IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); - } else { - priv->ieee->scan_age = val; - IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); - } - - IPW_DEBUG_INFO("exit\n"); - return len; -} - -static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); - -static ssize_t show_led(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1); -} - -static ssize_t store_led(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - - IPW_DEBUG_INFO("enter\n"); - - if (count == 0) - return 0; - - if (*buf == 0) { - IPW_DEBUG_LED("Disabling LED control.\n"); - priv->config |= CFG_NO_LED; - ipw_led_shutdown(priv); - } else { - IPW_DEBUG_LED("Enabling LED control.\n"); - priv->config &= ~CFG_NO_LED; - ipw_led_init(priv); - } - - IPW_DEBUG_INFO("exit\n"); - return count; -} - -static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); - -static ssize_t show_status(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ipw_priv *p = d->driver_data; - return sprintf(buf, "0x%08x\n", (int)p->status); -} - -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); - -static ssize_t show_cfg(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *p = d->driver_data; - return sprintf(buf, "0x%08x\n", (int)p->config); -} - -static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); - -static ssize_t show_nic_type(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ipw_priv *priv = d->driver_data; - return sprintf(buf, "TYPE: %d\n", priv->nic_type); -} - -static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); - -static ssize_t show_ucode_version(struct device *d, - struct device_attribute *attr, char *buf) -{ - u32 len = sizeof(u32), tmp = 0; - struct ipw_priv *p = d->driver_data; - - if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len)) - return 0; - - return sprintf(buf, "0x%08x\n", tmp); -} - -static DEVICE_ATTR(ucode_version, S_IWUSR | S_IRUGO, show_ucode_version, NULL); - -static ssize_t show_rtc(struct device *d, struct device_attribute *attr, - char *buf) -{ - u32 len = sizeof(u32), tmp = 0; - struct ipw_priv *p = d->driver_data; - - if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len)) - return 0; - - return sprintf(buf, "0x%08x\n", tmp); -} - -static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL); - -/* - * Add a device attribute to view/control the delay between eeprom - * operations. - */ -static ssize_t show_eeprom_delay(struct device *d, - struct device_attribute *attr, char *buf) -{ - int n = ((struct ipw_priv *)d->driver_data)->eeprom_delay; - return sprintf(buf, "%i\n", n); -} -static ssize_t store_eeprom_delay(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *p = d->driver_data; - sscanf(buf, "%i", &p->eeprom_delay); - return strnlen(buf, count); -} - -static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO, - show_eeprom_delay, store_eeprom_delay); - -static ssize_t show_command_event_reg(struct device *d, - struct device_attribute *attr, char *buf) -{ - u32 reg = 0; - struct ipw_priv *p = d->driver_data; - - reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT); - return sprintf(buf, "0x%08x\n", reg); -} -static ssize_t store_command_event_reg(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 reg; - struct ipw_priv *p = d->driver_data; - - sscanf(buf, "%x", ®); - ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg); - return strnlen(buf, count); -} - -static DEVICE_ATTR(command_event_reg, S_IWUSR | S_IRUGO, - show_command_event_reg, store_command_event_reg); - -static ssize_t show_mem_gpio_reg(struct device *d, - struct device_attribute *attr, char *buf) -{ - u32 reg = 0; - struct ipw_priv *p = d->driver_data; - - reg = ipw_read_reg32(p, 0x301100); - return sprintf(buf, "0x%08x\n", reg); -} -static ssize_t store_mem_gpio_reg(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 reg; - struct ipw_priv *p = d->driver_data; - - sscanf(buf, "%x", ®); - ipw_write_reg32(p, 0x301100, reg); - return strnlen(buf, count); -} - -static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO, - show_mem_gpio_reg, store_mem_gpio_reg); - -static ssize_t show_indirect_dword(struct device *d, - struct device_attribute *attr, char *buf) -{ - u32 reg = 0; - struct ipw_priv *priv = d->driver_data; - - if (priv->status & STATUS_INDIRECT_DWORD) - reg = ipw_read_reg32(priv, priv->indirect_dword); - else - reg = 0; - - return sprintf(buf, "0x%08x\n", reg); -} -static ssize_t store_indirect_dword(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = d->driver_data; - - sscanf(buf, "%x", &priv->indirect_dword); - priv->status |= STATUS_INDIRECT_DWORD; - return strnlen(buf, count); -} - -static DEVICE_ATTR(indirect_dword, S_IWUSR | S_IRUGO, - show_indirect_dword, store_indirect_dword); - -static ssize_t show_indirect_byte(struct device *d, - struct device_attribute *attr, char *buf) -{ - u8 reg = 0; - struct ipw_priv *priv = d->driver_data; - - if (priv->status & STATUS_INDIRECT_BYTE) - reg = ipw_read_reg8(priv, priv->indirect_byte); - else - reg = 0; - - return sprintf(buf, "0x%02x\n", reg); -} -static ssize_t store_indirect_byte(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = d->driver_data; - - sscanf(buf, "%x", &priv->indirect_byte); - priv->status |= STATUS_INDIRECT_BYTE; - return strnlen(buf, count); -} - -static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO, - show_indirect_byte, store_indirect_byte); - -static ssize_t show_direct_dword(struct device *d, - struct device_attribute *attr, char *buf) -{ - u32 reg = 0; - struct ipw_priv *priv = d->driver_data; - - if (priv->status & STATUS_DIRECT_DWORD) - reg = ipw_read32(priv, priv->direct_dword); - else - reg = 0; - - return sprintf(buf, "0x%08x\n", reg); -} -static ssize_t store_direct_dword(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = d->driver_data; - - sscanf(buf, "%x", &priv->direct_dword); - priv->status |= STATUS_DIRECT_DWORD; - return strnlen(buf, count); -} - -static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO, - show_direct_dword, store_direct_dword); - -static int rf_kill_active(struct ipw_priv *priv) -{ - if (0 == (ipw_read32(priv, 0x30) & 0x10000)) - priv->status |= STATUS_RF_KILL_HW; - else - priv->status &= ~STATUS_RF_KILL_HW; - - return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0; -} - -static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, - char *buf) -{ - /* 0 - RF kill not enabled - 1 - SW based RF kill active (sysfs) - 2 - HW based RF kill active - 3 - Both HW and SW baed RF kill active */ - struct ipw_priv *priv = d->driver_data; - int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | - (rf_kill_active(priv) ? 0x2 : 0x0); - return sprintf(buf, "%i\n", val); -} - -static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) -{ - if ((disable_radio ? 1 : 0) == - ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0)) - return 0; - - IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", - disable_radio ? "OFF" : "ON"); - - if (disable_radio) { - priv->status |= STATUS_RF_KILL_SW; - - if (priv->workqueue) { - cancel_delayed_work(&priv->request_scan); - cancel_delayed_work(&priv->request_direct_scan); - cancel_delayed_work(&priv->request_passive_scan); - cancel_delayed_work(&priv->scan_event); - } - queue_work(priv->workqueue, &priv->down); - } else { - priv->status &= ~STATUS_RF_KILL_SW; - if (rf_kill_active(priv)) { - IPW_DEBUG_RF_KILL("Can not turn radio back on - " - "disabled by HW switch\n"); - /* Make sure the RF_KILL check timer is running */ - cancel_delayed_work(&priv->rf_kill); - queue_delayed_work(priv->workqueue, &priv->rf_kill, - round_jiffies_relative(2 * HZ)); - } else - queue_work(priv->workqueue, &priv->up); - } - - return 1; -} - -static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = d->driver_data; - - ipw_radio_kill_sw(priv, buf[0] == '1'); - - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); - -static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; - int pos = 0, len = 0; - if (priv->config & CFG_SPEED_SCAN) { - while (priv->speed_scan[pos] != 0) - len += sprintf(&buf[len], "%d ", - priv->speed_scan[pos++]); - return len + sprintf(&buf[len], "\n"); - } - - return sprintf(buf, "0\n"); -} - -static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; - int channel, pos = 0; - const char *p = buf; - - /* list of space separated channels to scan, optionally ending with 0 */ - while ((channel = simple_strtol(p, NULL, 0))) { - if (pos == MAX_SPEED_SCAN - 1) { - priv->speed_scan[pos] = 0; - break; - } - - if (ieee80211_is_valid_channel(priv->ieee, channel)) - priv->speed_scan[pos++] = channel; - else - IPW_WARNING("Skipping invalid channel request: %d\n", - channel); - p = strchr(p, ' '); - if (!p) - break; - while (*p == ' ' || *p == '\t') - p++; - } - - if (pos == 0) - priv->config &= ~CFG_SPEED_SCAN; - else { - priv->speed_scan_pos = 0; - priv->config |= CFG_SPEED_SCAN; - } - - return count; -} - -static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, - store_speed_scan); - -static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; - return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0'); -} - -static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; - if (buf[0] == '1') - priv->config |= CFG_NET_STATS; - else - priv->config &= ~CFG_NET_STATS; - - return count; -} - -static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, - show_net_stats, store_net_stats); - -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct ipw_priv *priv = dev_get_drvdata(d); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - int len = 0, i; - - len = sprintf(&buf[len], - "Displaying %d channels in 2.4Ghz band " - "(802.11bg):\n", geo->bg_channels); - - for (i = 0; i < geo->bg_channels; i++) { - len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", - geo->bg[i].channel, - geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? - " (radar spectrum)" : "", - ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) - ? "" : ", IBSS", - geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? - "passive only" : "active/passive", - geo->bg[i].flags & IEEE80211_CH_B_ONLY ? - "B" : "B/G"); - } - - len += sprintf(&buf[len], - "Displaying %d channels in 5.2Ghz band " - "(802.11a):\n", geo->a_channels); - for (i = 0; i < geo->a_channels; i++) { - len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", - geo->a[i].channel, - geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? - " (radar spectrum)" : "", - ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) - ? "" : ", IBSS", - geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? - "passive only" : "active/passive"); - } - - return len; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); - -static void notify_wx_assoc_event(struct ipw_priv *priv) -{ - union iwreq_data wrqu; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (priv->status & STATUS_ASSOCIATED) - memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); - else - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); - wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); -} - -static void ipw_irq_tasklet(struct ipw_priv *priv) -{ - u32 inta, inta_mask, handled = 0; - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&priv->irq_lock, flags); - - inta = ipw_read32(priv, IPW_INTA_RW); - inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); - inta &= (IPW_INTA_MASK_ALL & inta_mask); - - /* Add any cached INTA values that need to be handled */ - inta |= priv->isr_inta; - - spin_unlock_irqrestore(&priv->irq_lock, flags); - - spin_lock_irqsave(&priv->lock, flags); - - /* handle all the justifications for the interrupt */ - if (inta & IPW_INTA_BIT_RX_TRANSFER) { - ipw_rx(priv); - handled |= IPW_INTA_BIT_RX_TRANSFER; - } - - if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) { - IPW_DEBUG_HC("Command completed.\n"); - rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1); - priv->status &= ~STATUS_HCMD_ACTIVE; - wake_up_interruptible(&priv->wait_command_queue); - handled |= IPW_INTA_BIT_TX_CMD_QUEUE; - } - - if (inta & IPW_INTA_BIT_TX_QUEUE_1) { - IPW_DEBUG_TX("TX_QUEUE_1\n"); - rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0); - handled |= IPW_INTA_BIT_TX_QUEUE_1; - } - - if (inta & IPW_INTA_BIT_TX_QUEUE_2) { - IPW_DEBUG_TX("TX_QUEUE_2\n"); - rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1); - handled |= IPW_INTA_BIT_TX_QUEUE_2; - } - - if (inta & IPW_INTA_BIT_TX_QUEUE_3) { - IPW_DEBUG_TX("TX_QUEUE_3\n"); - rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2); - handled |= IPW_INTA_BIT_TX_QUEUE_3; - } - - if (inta & IPW_INTA_BIT_TX_QUEUE_4) { - IPW_DEBUG_TX("TX_QUEUE_4\n"); - rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3); - handled |= IPW_INTA_BIT_TX_QUEUE_4; - } - - if (inta & IPW_INTA_BIT_STATUS_CHANGE) { - IPW_WARNING("STATUS_CHANGE\n"); - handled |= IPW_INTA_BIT_STATUS_CHANGE; - } - - if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) { - IPW_WARNING("TX_PERIOD_EXPIRED\n"); - handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED; - } - - if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) { - IPW_WARNING("HOST_CMD_DONE\n"); - handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE; - } - - if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) { - IPW_WARNING("FW_INITIALIZATION_DONE\n"); - handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE; - } - - if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) { - IPW_WARNING("PHY_OFF_DONE\n"); - handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE; - } - - if (inta & IPW_INTA_BIT_RF_KILL_DONE) { - IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); - priv->status |= STATUS_RF_KILL_HW; - wake_up_interruptible(&priv->wait_command_queue); - priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); - cancel_delayed_work(&priv->request_scan); - cancel_delayed_work(&priv->request_direct_scan); - cancel_delayed_work(&priv->request_passive_scan); - cancel_delayed_work(&priv->scan_event); - schedule_work(&priv->link_down); - queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); - handled |= IPW_INTA_BIT_RF_KILL_DONE; - } - - if (inta & IPW_INTA_BIT_FATAL_ERROR) { - IPW_WARNING("Firmware error detected. Restarting.\n"); - if (priv->error) { - IPW_DEBUG_FW("Sysfs 'error' log already exists.\n"); - if (ipw_debug_level & IPW_DL_FW_ERRORS) { - struct ipw_fw_error *error = - ipw_alloc_error_log(priv); - ipw_dump_error_log(priv, error); - kfree(error); - } - } else { - priv->error = ipw_alloc_error_log(priv); - if (priv->error) - IPW_DEBUG_FW("Sysfs 'error' log captured.\n"); - else - IPW_DEBUG_FW("Error allocating sysfs 'error' " - "log.\n"); - if (ipw_debug_level & IPW_DL_FW_ERRORS) - ipw_dump_error_log(priv, priv->error); - } - - /* XXX: If hardware encryption is for WPA/WPA2, - * we have to notify the supplicant. */ - if (priv->ieee->sec.encrypt) { - priv->status &= ~STATUS_ASSOCIATED; - notify_wx_assoc_event(priv); - } - - /* Keep the restart process from trying to send host - * commands by clearing the INIT status bit */ - priv->status &= ~STATUS_INIT; - - /* Cancel currently queued command. */ - priv->status &= ~STATUS_HCMD_ACTIVE; - wake_up_interruptible(&priv->wait_command_queue); - - queue_work(priv->workqueue, &priv->adapter_restart); - handled |= IPW_INTA_BIT_FATAL_ERROR; - } - - if (inta & IPW_INTA_BIT_PARITY_ERROR) { - IPW_ERROR("Parity error\n"); - handled |= IPW_INTA_BIT_PARITY_ERROR; - } - - if (handled != inta) { - IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - /* enable all interrupts */ - ipw_enable_interrupts(priv); -} - -#define IPW_CMD(x) case IPW_CMD_ ## x : return #x -static char *get_cmd_string(u8 cmd) -{ - switch (cmd) { - IPW_CMD(HOST_COMPLETE); - IPW_CMD(POWER_DOWN); - IPW_CMD(SYSTEM_CONFIG); - IPW_CMD(MULTICAST_ADDRESS); - IPW_CMD(SSID); - IPW_CMD(ADAPTER_ADDRESS); - IPW_CMD(PORT_TYPE); - IPW_CMD(RTS_THRESHOLD); - IPW_CMD(FRAG_THRESHOLD); - IPW_CMD(POWER_MODE); - IPW_CMD(WEP_KEY); - IPW_CMD(TGI_TX_KEY); - IPW_CMD(SCAN_REQUEST); - IPW_CMD(SCAN_REQUEST_EXT); - IPW_CMD(ASSOCIATE); - IPW_CMD(SUPPORTED_RATES); - IPW_CMD(SCAN_ABORT); - IPW_CMD(TX_FLUSH); - IPW_CMD(QOS_PARAMETERS); - IPW_CMD(DINO_CONFIG); - IPW_CMD(RSN_CAPABILITIES); - IPW_CMD(RX_KEY); - IPW_CMD(CARD_DISABLE); - IPW_CMD(SEED_NUMBER); - IPW_CMD(TX_POWER); - IPW_CMD(COUNTRY_INFO); - IPW_CMD(AIRONET_INFO); - IPW_CMD(AP_TX_POWER); - IPW_CMD(CCKM_INFO); - IPW_CMD(CCX_VER_INFO); - IPW_CMD(SET_CALIBRATION); - IPW_CMD(SENSITIVITY_CALIB); - IPW_CMD(RETRY_LIMIT); - IPW_CMD(IPW_PRE_POWER_DOWN); - IPW_CMD(VAP_BEACON_TEMPLATE); - IPW_CMD(VAP_DTIM_PERIOD); - IPW_CMD(EXT_SUPPORTED_RATES); - IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT); - IPW_CMD(VAP_QUIET_INTERVALS); - IPW_CMD(VAP_CHANNEL_SWITCH); - IPW_CMD(VAP_MANDATORY_CHANNELS); - IPW_CMD(VAP_CELL_PWR_LIMIT); - IPW_CMD(VAP_CF_PARAM_SET); - IPW_CMD(VAP_SET_BEACONING_STATE); - IPW_CMD(MEASUREMENT); - IPW_CMD(POWER_CAPABILITY); - IPW_CMD(SUPPORTED_CHANNELS); - IPW_CMD(TPC_REPORT); - IPW_CMD(WME_INFO); - IPW_CMD(PRODUCTION_COMMAND); - default: - return "UNKNOWN"; - } -} - -#define HOST_COMPLETE_TIMEOUT HZ - -static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) -{ - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (priv->status & STATUS_HCMD_ACTIVE) { - IPW_ERROR("Failed to send %s: Already sending a command.\n", - get_cmd_string(cmd->cmd)); - spin_unlock_irqrestore(&priv->lock, flags); - return -EAGAIN; - } - - priv->status |= STATUS_HCMD_ACTIVE; - - if (priv->cmdlog) { - priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies; - priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd; - priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len; - memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param, - cmd->len); - priv->cmdlog[priv->cmdlog_pos].retcode = -1; - } - - IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", - get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, - priv->status); - -#ifndef DEBUG_CMD_WEP_KEY - if (cmd->cmd == IPW_CMD_WEP_KEY) - IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n"); - else -#endif - printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); - - rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0); - if (rc) { - priv->status &= ~STATUS_HCMD_ACTIVE; - IPW_ERROR("Failed to send %s: Reason %d\n", - get_cmd_string(cmd->cmd), rc); - spin_unlock_irqrestore(&priv->lock, flags); - goto exit; - } - spin_unlock_irqrestore(&priv->lock, flags); - - rc = wait_event_interruptible_timeout(priv->wait_command_queue, - !(priv-> - status & STATUS_HCMD_ACTIVE), - HOST_COMPLETE_TIMEOUT); - if (rc == 0) { - spin_lock_irqsave(&priv->lock, flags); - if (priv->status & STATUS_HCMD_ACTIVE) { - IPW_ERROR("Failed to send %s: Command timed out.\n", - get_cmd_string(cmd->cmd)); - priv->status &= ~STATUS_HCMD_ACTIVE; - spin_unlock_irqrestore(&priv->lock, flags); - rc = -EIO; - goto exit; - } - spin_unlock_irqrestore(&priv->lock, flags); - } else - rc = 0; - - if (priv->status & STATUS_RF_KILL_HW) { - IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", - get_cmd_string(cmd->cmd)); - rc = -EIO; - goto exit; - } - - exit: - if (priv->cmdlog) { - priv->cmdlog[priv->cmdlog_pos++].retcode = rc; - priv->cmdlog_pos %= priv->cmdlog_len; - } - return rc; -} - -static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command) -{ - struct host_cmd cmd = { - .cmd = command, - }; - - return __ipw_send_cmd(priv, &cmd); -} - -static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len, - void *data) -{ - struct host_cmd cmd = { - .cmd = command, - .len = len, - .param = data, - }; - - return __ipw_send_cmd(priv, &cmd); -} - -static int ipw_send_host_complete(struct ipw_priv *priv) -{ - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE); -} - -static int ipw_send_system_config(struct ipw_priv *priv) -{ - return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, - sizeof(priv->sys_config), - &priv->sys_config); -} - -static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) -{ - if (!priv || !ssid) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE), - ssid); -} - -static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) -{ - if (!priv || !mac) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - IPW_DEBUG_INFO("%s: Setting MAC to %pM\n", - priv->net_dev->name, mac); - - return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); -} - -/* - * NOTE: This must be executed from our workqueue as it results in udelay - * being called which may corrupt the keyboard if executed on default - * workqueue - */ -static void ipw_adapter_restart(void *adapter) -{ - struct ipw_priv *priv = adapter; - - if (priv->status & STATUS_RF_KILL_MASK) - return; - - ipw_down(priv); - - if (priv->assoc_network && - (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS)) - ipw_remove_current_network(priv); - - if (ipw_up(priv)) { - IPW_ERROR("Failed to up device\n"); - return; - } -} - -static void ipw_bg_adapter_restart(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, adapter_restart); - mutex_lock(&priv->mutex); - ipw_adapter_restart(priv); - mutex_unlock(&priv->mutex); -} - -#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) - -static void ipw_scan_check(void *data) -{ - struct ipw_priv *priv = data; - if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { - IPW_DEBUG_SCAN("Scan completion watchdog resetting " - "adapter after (%dms).\n", - jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG)); - queue_work(priv->workqueue, &priv->adapter_restart); - } -} - -static void ipw_bg_scan_check(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, scan_check.work); - mutex_lock(&priv->mutex); - ipw_scan_check(priv); - mutex_unlock(&priv->mutex); -} - -static int ipw_send_scan_request_ext(struct ipw_priv *priv, - struct ipw_scan_request_ext *request) -{ - return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT, - sizeof(*request), request); -} - -static int ipw_send_scan_abort(struct ipw_priv *priv) -{ - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT); -} - -static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) -{ - struct ipw_sensitivity_calib calib = { - .beacon_rssi_raw = cpu_to_le16(sens), - }; - - return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib), - &calib); -} - -static int ipw_send_associate(struct ipw_priv *priv, - struct ipw_associate *associate) -{ - if (!priv || !associate) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate), - associate); -} - -static int ipw_send_supported_rates(struct ipw_priv *priv, - struct ipw_supported_rates *rates) -{ - if (!priv || !rates) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates), - rates); -} - -static int ipw_set_random_seed(struct ipw_priv *priv) -{ - u32 val; - - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - get_random_bytes(&val, sizeof(val)); - - return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val); -} - -static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) -{ - __le32 v = cpu_to_le32(phy_off); - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v); -} - -static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) -{ - if (!priv || !power) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power); -} - -static int ipw_set_tx_power(struct ipw_priv *priv) -{ - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - struct ipw_tx_power tx_power; - s8 max_power; - int i; - - memset(&tx_power, 0, sizeof(tx_power)); - - /* configure device for 'G' band */ - tx_power.ieee_mode = IPW_G_MODE; - tx_power.num_channels = geo->bg_channels; - for (i = 0; i < geo->bg_channels; i++) { - max_power = geo->bg[i].max_power; - tx_power.channels_tx_power[i].channel_number = - geo->bg[i].channel; - tx_power.channels_tx_power[i].tx_power = max_power ? - min(max_power, priv->tx_power) : priv->tx_power; - } - if (ipw_send_tx_power(priv, &tx_power)) - return -EIO; - - /* configure device to also handle 'B' band */ - tx_power.ieee_mode = IPW_B_MODE; - if (ipw_send_tx_power(priv, &tx_power)) - return -EIO; - - /* configure device to also handle 'A' band */ - if (priv->ieee->abg_true) { - tx_power.ieee_mode = IPW_A_MODE; - tx_power.num_channels = geo->a_channels; - for (i = 0; i < tx_power.num_channels; i++) { - max_power = geo->a[i].max_power; - tx_power.channels_tx_power[i].channel_number = - geo->a[i].channel; - tx_power.channels_tx_power[i].tx_power = max_power ? - min(max_power, priv->tx_power) : priv->tx_power; - } - if (ipw_send_tx_power(priv, &tx_power)) - return -EIO; - } - return 0; -} - -static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) -{ - struct ipw_rts_threshold rts_threshold = { - .rts_threshold = cpu_to_le16(rts), - }; - - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD, - sizeof(rts_threshold), &rts_threshold); -} - -static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) -{ - struct ipw_frag_threshold frag_threshold = { - .frag_threshold = cpu_to_le16(frag), - }; - - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD, - sizeof(frag_threshold), &frag_threshold); -} - -static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) -{ - __le32 param; - - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - /* If on battery, set to 3, if AC set to CAM, else user - * level */ - switch (mode) { - case IPW_POWER_BATTERY: - param = cpu_to_le32(IPW_POWER_INDEX_3); - break; - case IPW_POWER_AC: - param = cpu_to_le32(IPW_POWER_MODE_CAM); - break; - default: - param = cpu_to_le32(mode); - break; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), - ¶m); -} - -static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) -{ - struct ipw_retry_limit retry_limit = { - .short_retry_limit = slimit, - .long_retry_limit = llimit - }; - - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit), - &retry_limit); -} - -/* - * The IPW device contains a Microwire compatible EEPROM that stores - * various data like the MAC address. Usually the firmware has exclusive - * access to the eeprom, but during device initialization (before the - * device driver has sent the HostComplete command to the firmware) the - * device driver has read access to the EEPROM by way of indirect addressing - * through a couple of memory mapped registers. - * - * The following is a simplified implementation for pulling data out of the - * the eeprom, along with some helper functions to find information in - * the per device private data's copy of the eeprom. - * - * NOTE: To better understand how these functions work (i.e what is a chip - * select and why do have to keep driving the eeprom clock?), read - * just about any data sheet for a Microwire compatible EEPROM. - */ - -/* write a 32 bit value into the indirect accessor register */ -static inline void eeprom_write_reg(struct ipw_priv *p, u32 data) -{ - ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data); - - /* the eeprom requires some time to complete the operation */ - udelay(p->eeprom_delay); - - return; -} - -/* perform a chip select operation */ -static void eeprom_cs(struct ipw_priv *priv) -{ - eeprom_write_reg(priv, 0); - eeprom_write_reg(priv, EEPROM_BIT_CS); - eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK); - eeprom_write_reg(priv, EEPROM_BIT_CS); -} - -/* perform a chip select operation */ -static void eeprom_disable_cs(struct ipw_priv *priv) -{ - eeprom_write_reg(priv, EEPROM_BIT_CS); - eeprom_write_reg(priv, 0); - eeprom_write_reg(priv, EEPROM_BIT_SK); -} - -/* push a single bit down to the eeprom */ -static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit) -{ - int d = (bit ? EEPROM_BIT_DI : 0); - eeprom_write_reg(p, EEPROM_BIT_CS | d); - eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK); -} - -/* push an opcode followed by an address down to the eeprom */ -static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr) -{ - int i; - - eeprom_cs(priv); - eeprom_write_bit(priv, 1); - eeprom_write_bit(priv, op & 2); - eeprom_write_bit(priv, op & 1); - for (i = 7; i >= 0; i--) { - eeprom_write_bit(priv, addr & (1 << i)); - } -} - -/* pull 16 bits off the eeprom, one bit at a time */ -static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr) -{ - int i; - u16 r = 0; - - /* Send READ Opcode */ - eeprom_op(priv, EEPROM_CMD_READ, addr); - - /* Send dummy bit */ - eeprom_write_reg(priv, EEPROM_BIT_CS); - - /* Read the byte off the eeprom one bit at a time */ - for (i = 0; i < 16; i++) { - u32 data = 0; - eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK); - eeprom_write_reg(priv, EEPROM_BIT_CS); - data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS); - r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0); - } - - /* Send another dummy bit */ - eeprom_write_reg(priv, 0); - eeprom_disable_cs(priv); - - return r; -} - -/* helper function for pulling the mac address out of the private */ -/* data's copy of the eeprom data */ -static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) -{ - memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6); -} - -/* - * Either the device driver (i.e. the host) or the firmware can - * load eeprom data into the designated region in SRAM. If neither - * happens then the FW will shutdown with a fatal error. - * - * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE - * bit needs region of shared SRAM needs to be non-zero. - */ -static void ipw_eeprom_init_sram(struct ipw_priv *priv) -{ - int i; - __le16 *eeprom = (__le16 *) priv->eeprom; - - IPW_DEBUG_TRACE(">>\n"); - - /* read entire contents of eeprom into private buffer */ - for (i = 0; i < 128; i++) - eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i)); - - /* - If the data looks correct, then copy it to our private - copy. Otherwise let the firmware know to perform the operation - on its own. - */ - if (priv->eeprom[EEPROM_VERSION] != 0) { - IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n"); - - /* write the eeprom data to sram */ - for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) - ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]); - - /* Do not load eeprom data on fatal error or suspend */ - ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); - } else { - IPW_DEBUG_INFO("Enabling FW initializationg of SRAM\n"); - - /* Load eeprom data on fatal error or suspend */ - ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1); - } - - IPW_DEBUG_TRACE("<<\n"); -} - -static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count) -{ - count >>= 2; - if (!count) - return; - _ipw_write32(priv, IPW_AUTOINC_ADDR, start); - while (count--) - _ipw_write32(priv, IPW_AUTOINC_DATA, 0); -} - -static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv) -{ - ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL, - CB_NUMBER_OF_ELEMENTS_SMALL * - sizeof(struct command_block)); -} - -static int ipw_fw_dma_enable(struct ipw_priv *priv) -{ /* start dma engine but no transfers yet */ - - IPW_DEBUG_FW(">> : \n"); - - /* Start the dma */ - ipw_fw_dma_reset_command_blocks(priv); - - /* Write CB base address */ - ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL); - - IPW_DEBUG_FW("<< : \n"); - return 0; -} - -static void ipw_fw_dma_abort(struct ipw_priv *priv) -{ - u32 control = 0; - - IPW_DEBUG_FW(">> :\n"); - - /* set the Stop and Abort bit */ - control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; - ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); - priv->sram_desc.last_cb_index = 0; - - IPW_DEBUG_FW("<< \n"); -} - -static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index, - struct command_block *cb) -{ - u32 address = - IPW_SHARED_SRAM_DMA_CONTROL + - (sizeof(struct command_block) * index); - IPW_DEBUG_FW(">> :\n"); - - ipw_write_indirect(priv, address, (u8 *) cb, - (int)sizeof(struct command_block)); - - IPW_DEBUG_FW("<< :\n"); - return 0; - -} - -static int ipw_fw_dma_kick(struct ipw_priv *priv) -{ - u32 control = 0; - u32 index = 0; - - IPW_DEBUG_FW(">> :\n"); - - for (index = 0; index < priv->sram_desc.last_cb_index; index++) - ipw_fw_dma_write_command_block(priv, index, - &priv->sram_desc.cb_list[index]); - - /* Enable the DMA in the CSR register */ - ipw_clear_bit(priv, IPW_RESET_REG, - IPW_RESET_REG_MASTER_DISABLED | - IPW_RESET_REG_STOP_MASTER); - - /* Set the Start bit. */ - control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START; - ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); - - IPW_DEBUG_FW("<< :\n"); - return 0; -} - -static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv) -{ - u32 address; - u32 register_value = 0; - u32 cb_fields_address = 0; - - IPW_DEBUG_FW(">> :\n"); - address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB); - IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address); - - /* Read the DMA Controlor register */ - register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL); - IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value); - - /* Print the CB values */ - cb_fields_address = address; - register_value = ipw_read_reg32(priv, cb_fields_address); - IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n", register_value); - - cb_fields_address += sizeof(u32); - register_value = ipw_read_reg32(priv, cb_fields_address); - IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n", register_value); - - cb_fields_address += sizeof(u32); - register_value = ipw_read_reg32(priv, cb_fields_address); - IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n", - register_value); - - cb_fields_address += sizeof(u32); - register_value = ipw_read_reg32(priv, cb_fields_address); - IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n", register_value); - - IPW_DEBUG_FW(">> :\n"); -} - -static int ipw_fw_dma_command_block_index(struct ipw_priv *priv) -{ - u32 current_cb_address = 0; - u32 current_cb_index = 0; - - IPW_DEBUG_FW("<< :\n"); - current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB); - - current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) / - sizeof(struct command_block); - - IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n", - current_cb_index, current_cb_address); - - IPW_DEBUG_FW(">> :\n"); - return current_cb_index; - -} - -static int ipw_fw_dma_add_command_block(struct ipw_priv *priv, - u32 src_address, - u32 dest_address, - u32 length, - int interrupt_enabled, int is_last) -{ - - u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC | - CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG | - CB_DEST_SIZE_LONG; - struct command_block *cb; - u32 last_cb_element = 0; - - IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n", - src_address, dest_address, length); - - if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL) - return -1; - - last_cb_element = priv->sram_desc.last_cb_index; - cb = &priv->sram_desc.cb_list[last_cb_element]; - priv->sram_desc.last_cb_index++; - - /* Calculate the new CB control word */ - if (interrupt_enabled) - control |= CB_INT_ENABLED; - - if (is_last) - control |= CB_LAST_VALID; - - control |= length; - - /* Calculate the CB Element's checksum value */ - cb->status = control ^ src_address ^ dest_address; - - /* Copy the Source and Destination addresses */ - cb->dest_addr = dest_address; - cb->source_addr = src_address; - - /* Copy the Control Word last */ - cb->control = control; - - return 0; -} - -static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, - u32 src_phys, u32 dest_address, u32 length) -{ - u32 bytes_left = length; - u32 src_offset = 0; - u32 dest_offset = 0; - int status = 0; - IPW_DEBUG_FW(">> \n"); - IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n", - src_phys, dest_address, length); - while (bytes_left > CB_MAX_LENGTH) { - status = ipw_fw_dma_add_command_block(priv, - src_phys + src_offset, - dest_address + - dest_offset, - CB_MAX_LENGTH, 0, 0); - if (status) { - IPW_DEBUG_FW_INFO(": Failed\n"); - return -1; - } else - IPW_DEBUG_FW_INFO(": Added new cb\n"); - - src_offset += CB_MAX_LENGTH; - dest_offset += CB_MAX_LENGTH; - bytes_left -= CB_MAX_LENGTH; - } - - /* add the buffer tail */ - if (bytes_left > 0) { - status = - ipw_fw_dma_add_command_block(priv, src_phys + src_offset, - dest_address + dest_offset, - bytes_left, 0, 0); - if (status) { - IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n"); - return -1; - } else - IPW_DEBUG_FW_INFO - (": Adding new cb - the buffer tail\n"); - } - - IPW_DEBUG_FW("<< \n"); - return 0; -} - -static int ipw_fw_dma_wait(struct ipw_priv *priv) -{ - u32 current_index = 0, previous_index; - u32 watchdog = 0; - - IPW_DEBUG_FW(">> : \n"); - - current_index = ipw_fw_dma_command_block_index(priv); - IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n", - (int)priv->sram_desc.last_cb_index); - - while (current_index < priv->sram_desc.last_cb_index) { - udelay(50); - previous_index = current_index; - current_index = ipw_fw_dma_command_block_index(priv); - - if (previous_index < current_index) { - watchdog = 0; - continue; - } - if (++watchdog > 400) { - IPW_DEBUG_FW_INFO("Timeout\n"); - ipw_fw_dma_dump_command_block(priv); - ipw_fw_dma_abort(priv); - return -1; - } - } - - ipw_fw_dma_abort(priv); - - /*Disable the DMA in the CSR register */ - ipw_set_bit(priv, IPW_RESET_REG, - IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER); - - IPW_DEBUG_FW("<< dmaWaitSync \n"); - return 0; -} - -static void ipw_remove_current_network(struct ipw_priv *priv) -{ - struct list_head *element, *safe; - struct ieee80211_network *network = NULL; - unsigned long flags; - - spin_lock_irqsave(&priv->ieee->lock, flags); - list_for_each_safe(element, safe, &priv->ieee->network_list) { - network = list_entry(element, struct ieee80211_network, list); - if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - list_del(element); - list_add_tail(&network->list, - &priv->ieee->network_free_list); - } - } - spin_unlock_irqrestore(&priv->ieee->lock, flags); -} - -/** - * Check that card is still alive. - * Reads debug register from domain0. - * If card is present, pre-defined value should - * be found there. - * - * @param priv - * @return 1 if card is present, 0 otherwise - */ -static inline int ipw_alive(struct ipw_priv *priv) -{ - return ipw_read32(priv, 0x90) == 0xd55555d5; -} - -/* timeout in msec, attempted in 10-msec quanta */ -static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask, - int timeout) -{ - int i = 0; - - do { - if ((ipw_read32(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIME; -} - -/* These functions load the firmware and micro code for the operation of - * the ipw hardware. It assumes the buffer has all the bits for the - * image and the caller is handling the memory allocation and clean up. - */ - -static int ipw_stop_master(struct ipw_priv *priv) -{ - int rc; - - IPW_DEBUG_TRACE(">> \n"); - /* stop master. typical delay - 0 */ - ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); - - /* timeout is in msec, polled in 10-msec quanta */ - rc = ipw_poll_bit(priv, IPW_RESET_REG, - IPW_RESET_REG_MASTER_DISABLED, 100); - if (rc < 0) { - IPW_ERROR("wait for stop master failed after 100ms\n"); - return -1; - } - - IPW_DEBUG_INFO("stop master %dms\n", rc); - - return rc; -} - -static void ipw_arc_release(struct ipw_priv *priv) -{ - IPW_DEBUG_TRACE(">> \n"); - mdelay(5); - - ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); - - /* no one knows timing, for safety add some delay */ - mdelay(5); -} - -struct fw_chunk { - __le32 address; - __le32 length; -}; - -static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) -{ - int rc = 0, i, addr; - u8 cr = 0; - __le16 *image; - - image = (__le16 *) data; - - IPW_DEBUG_TRACE(">> \n"); - - rc = ipw_stop_master(priv); - - if (rc < 0) - return rc; - - for (addr = IPW_SHARED_LOWER_BOUND; - addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { - ipw_write32(priv, addr, 0); - } - - /* no ucode (yet) */ - memset(&priv->dino_alive, 0, sizeof(priv->dino_alive)); - /* destroy DMA queues */ - /* reset sequence */ - - ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON); - ipw_arc_release(priv); - ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF); - mdelay(1); - - /* reset PHY */ - ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN); - mdelay(1); - - ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0); - mdelay(1); - - /* enable ucode store */ - ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0); - ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS); - mdelay(1); - - /* write ucode */ - /** - * @bug - * Do NOT set indirect address register once and then - * store data to indirect data register in the loop. - * It seems very reasonable, but in this case DINO do not - * accept ucode. It is essential to set address each time. - */ - /* load new ipw uCode */ - for (i = 0; i < len / 2; i++) - ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE, - le16_to_cpu(image[i])); - - /* enable DINO */ - ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); - ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM); - - /* this is where the igx / win driver deveates from the VAP driver. */ - - /* wait for alive response */ - for (i = 0; i < 100; i++) { - /* poll for incoming data */ - cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS); - if (cr & DINO_RXFIFO_DATA) - break; - mdelay(1); - } - - if (cr & DINO_RXFIFO_DATA) { - /* alive_command_responce size is NOT multiple of 4 */ - __le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4]; - - for (i = 0; i < ARRAY_SIZE(response_buffer); i++) - response_buffer[i] = - cpu_to_le32(ipw_read_reg32(priv, - IPW_BASEBAND_RX_FIFO_READ)); - memcpy(&priv->dino_alive, response_buffer, - sizeof(priv->dino_alive)); - if (priv->dino_alive.alive_command == 1 - && priv->dino_alive.ucode_valid == 1) { - rc = 0; - IPW_DEBUG_INFO - ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) " - "of %02d/%02d/%02d %02d:%02d\n", - priv->dino_alive.software_revision, - priv->dino_alive.software_revision, - priv->dino_alive.device_identifier, - priv->dino_alive.device_identifier, - priv->dino_alive.time_stamp[0], - priv->dino_alive.time_stamp[1], - priv->dino_alive.time_stamp[2], - priv->dino_alive.time_stamp[3], - priv->dino_alive.time_stamp[4]); - } else { - IPW_DEBUG_INFO("Microcode is not alive\n"); - rc = -EINVAL; - } - } else { - IPW_DEBUG_INFO("No alive response from DINO\n"); - rc = -ETIME; - } - - /* disable DINO, otherwise for some reason - firmware have problem getting alive resp. */ - ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); - - return rc; -} - -static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) -{ - int rc = -1; - int offset = 0; - struct fw_chunk *chunk; - dma_addr_t shared_phys; - u8 *shared_virt; - - IPW_DEBUG_TRACE("<< : \n"); - shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys); - - if (!shared_virt) - return -ENOMEM; - - memmove(shared_virt, data, len); - - /* Start the Dma */ - rc = ipw_fw_dma_enable(priv); - - if (priv->sram_desc.last_cb_index > 0) { - /* the DMA is already ready this would be a bug. */ - BUG(); - goto out; - } - - do { - chunk = (struct fw_chunk *)(data + offset); - offset += sizeof(struct fw_chunk); - /* build DMA packet and queue up for sending */ - /* dma to chunk->address, the chunk->length bytes from data + - * offeset*/ - /* Dma loading */ - rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, - le32_to_cpu(chunk->address), - le32_to_cpu(chunk->length)); - if (rc) { - IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); - goto out; - } - - offset += le32_to_cpu(chunk->length); - } while (offset < len); - - /* Run the DMA and wait for the answer */ - rc = ipw_fw_dma_kick(priv); - if (rc) { - IPW_ERROR("dmaKick Failed\n"); - goto out; - } - - rc = ipw_fw_dma_wait(priv); - if (rc) { - IPW_ERROR("dmaWaitSync Failed\n"); - goto out; - } - out: - pci_free_consistent(priv->pci_dev, len, shared_virt, shared_phys); - return rc; -} - -/* stop nic */ -static int ipw_stop_nic(struct ipw_priv *priv) -{ - int rc = 0; - - /* stop */ - ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); - - rc = ipw_poll_bit(priv, IPW_RESET_REG, - IPW_RESET_REG_MASTER_DISABLED, 500); - if (rc < 0) { - IPW_ERROR("wait for reg master disabled failed after 500ms\n"); - return rc; - } - - ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); - - return rc; -} - -static void ipw_start_nic(struct ipw_priv *priv) -{ - IPW_DEBUG_TRACE(">>\n"); - - /* prvHwStartNic release ARC */ - ipw_clear_bit(priv, IPW_RESET_REG, - IPW_RESET_REG_MASTER_DISABLED | - IPW_RESET_REG_STOP_MASTER | - CBD_RESET_REG_PRINCETON_RESET); - - /* enable power management */ - ipw_set_bit(priv, IPW_GP_CNTRL_RW, - IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); - - IPW_DEBUG_TRACE("<<\n"); -} - -static int ipw_init_nic(struct ipw_priv *priv) -{ - int rc; - - IPW_DEBUG_TRACE(">>\n"); - /* reset */ - /*prvHwInitNic */ - /* set "initialization complete" bit to move adapter to D0 state */ - ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE); - - /* low-level PLL activation */ - ipw_write32(priv, IPW_READ_INT_REGISTER, - IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER); - - /* wait for clock stabilization */ - rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW, - IPW_GP_CNTRL_BIT_CLOCK_READY, 250); - if (rc < 0) - IPW_DEBUG_INFO("FAILED wait for clock stablization\n"); - - /* assert SW reset */ - ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET); - - udelay(10); - - /* set "initialization complete" bit to move adapter to D0 state */ - ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE); - - IPW_DEBUG_TRACE(">>\n"); - return 0; -} - -/* Call this function from process context, it will sleep in request_firmware. - * Probe is an ok place to call this from. - */ -static int ipw_reset_nic(struct ipw_priv *priv) -{ - int rc = 0; - unsigned long flags; - - IPW_DEBUG_TRACE(">>\n"); - - rc = ipw_init_nic(priv); - - spin_lock_irqsave(&priv->lock, flags); - /* Clear the 'host command active' bit... */ - priv->status &= ~STATUS_HCMD_ACTIVE; - wake_up_interruptible(&priv->wait_command_queue); - priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); - wake_up_interruptible(&priv->wait_state); - spin_unlock_irqrestore(&priv->lock, flags); - - IPW_DEBUG_TRACE("<<\n"); - return rc; -} - - -struct ipw_fw { - __le32 ver; - __le32 boot_size; - __le32 ucode_size; - __le32 fw_size; - u8 data[0]; -}; - -static int ipw_get_fw(struct ipw_priv *priv, - const struct firmware **raw, const char *name) -{ - struct ipw_fw *fw; - int rc; - - /* ask firmware_class module to get the boot firmware off disk */ - rc = request_firmware(raw, name, &priv->pci_dev->dev); - if (rc < 0) { - IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc); - return rc; - } - - if ((*raw)->size < sizeof(*fw)) { - IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size); - return -EINVAL; - } - - fw = (void *)(*raw)->data; - - if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) + - le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) { - IPW_ERROR("%s is too small or corrupt (%zd)\n", - name, (*raw)->size); - return -EINVAL; - } - - IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n", - name, - le32_to_cpu(fw->ver) >> 16, - le32_to_cpu(fw->ver) & 0xff, - (*raw)->size - sizeof(*fw)); - return 0; -} - -#define IPW_RX_BUF_SIZE (3000) - -static void ipw_rx_queue_reset(struct ipw_priv *priv, - struct ipw_rx_queue *rxq) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&rxq->lock, flags); - - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); -} - -#ifdef CONFIG_PM -static int fw_loaded = 0; -static const struct firmware *raw = NULL; - -static void free_firmware(void) -{ - if (fw_loaded) { - release_firmware(raw); - raw = NULL; - fw_loaded = 0; - } -} -#else -#define free_firmware() do {} while (0) -#endif - -static int ipw_load(struct ipw_priv *priv) -{ -#ifndef CONFIG_PM - const struct firmware *raw = NULL; -#endif - struct ipw_fw *fw; - u8 *boot_img, *ucode_img, *fw_img; - u8 *name = NULL; - int rc = 0, retries = 3; - - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - name = "ipw2200-ibss.fw"; - break; -#ifdef CONFIG_IPW2200_MONITOR - case IW_MODE_MONITOR: - name = "ipw2200-sniffer.fw"; - break; -#endif - case IW_MODE_INFRA: - name = "ipw2200-bss.fw"; - break; - } - - if (!name) { - rc = -EINVAL; - goto error; - } - -#ifdef CONFIG_PM - if (!fw_loaded) { -#endif - rc = ipw_get_fw(priv, &raw, name); - if (rc < 0) - goto error; -#ifdef CONFIG_PM - } -#endif - - fw = (void *)raw->data; - boot_img = &fw->data[0]; - ucode_img = &fw->data[le32_to_cpu(fw->boot_size)]; - fw_img = &fw->data[le32_to_cpu(fw->boot_size) + - le32_to_cpu(fw->ucode_size)]; - - if (rc < 0) - goto error; - - if (!priv->rxq) - priv->rxq = ipw_rx_queue_alloc(priv); - else - ipw_rx_queue_reset(priv, priv->rxq); - if (!priv->rxq) { - IPW_ERROR("Unable to initialize Rx queue\n"); - goto error; - } - - retry: - /* Ensure interrupts are disabled */ - ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); - priv->status &= ~STATUS_INT_ENABLED; - - /* ack pending interrupts */ - ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); - - ipw_stop_nic(priv); - - rc = ipw_reset_nic(priv); - if (rc < 0) { - IPW_ERROR("Unable to reset NIC\n"); - goto error; - } - - ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, - IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); - - /* DMA the initial boot firmware into the device */ - rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size)); - if (rc < 0) { - IPW_ERROR("Unable to load boot firmware: %d\n", rc); - goto error; - } - - /* kick start the device */ - ipw_start_nic(priv); - - /* wait for the device to finish its initial startup sequence */ - rc = ipw_poll_bit(priv, IPW_INTA_RW, - IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); - if (rc < 0) { - IPW_ERROR("device failed to boot initial fw image\n"); - goto error; - } - IPW_DEBUG_INFO("initial device response after %dms\n", rc); - - /* ack fw init done interrupt */ - ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); - - /* DMA the ucode into the device */ - rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size)); - if (rc < 0) { - IPW_ERROR("Unable to load ucode: %d\n", rc); - goto error; - } - - /* stop nic */ - ipw_stop_nic(priv); - - /* DMA bss firmware into the device */ - rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size)); - if (rc < 0) { - IPW_ERROR("Unable to load firmware: %d\n", rc); - goto error; - } -#ifdef CONFIG_PM - fw_loaded = 1; -#endif - - ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); - - rc = ipw_queue_reset(priv); - if (rc < 0) { - IPW_ERROR("Unable to initialize queues\n"); - goto error; - } - - /* Ensure interrupts are disabled */ - ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); - /* ack pending interrupts */ - ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); - - /* kick start the device */ - ipw_start_nic(priv); - - if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) { - if (retries > 0) { - IPW_WARNING("Parity error. Retrying init.\n"); - retries--; - goto retry; - } - - IPW_ERROR("TODO: Handle parity error -- schedule restart?\n"); - rc = -EIO; - goto error; - } - - /* wait for the device */ - rc = ipw_poll_bit(priv, IPW_INTA_RW, - IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); - if (rc < 0) { - IPW_ERROR("device failed to start within 500ms\n"); - goto error; - } - IPW_DEBUG_INFO("device response after %dms\n", rc); - - /* ack fw init done interrupt */ - ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); - - /* read eeprom data and initialize the eeprom region of sram */ - priv->eeprom_delay = 1; - ipw_eeprom_init_sram(priv); - - /* enable interrupts */ - ipw_enable_interrupts(priv); - - /* Ensure our queue has valid packets */ - ipw_rx_queue_replenish(priv); - - ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read); - - /* ack pending interrupts */ - ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); - -#ifndef CONFIG_PM - release_firmware(raw); -#endif - return 0; - - error: - if (priv->rxq) { - ipw_rx_queue_free(priv, priv->rxq); - priv->rxq = NULL; - } - ipw_tx_queue_free(priv); - if (raw) - release_firmware(raw); -#ifdef CONFIG_PM - fw_loaded = 0; - raw = NULL; -#endif - - return rc; -} - -/** - * DMA services - * - * Theory of operation - * - * A queue is a circular buffers with 'Read' and 'Write' pointers. - * 2 empty entries always kept in the buffer to protect from overflow. - * - * For Tx queue, there are low mark and high mark limits. If, after queuing - * the packet for Tx, free space become < low mark, Tx queue stopped. When - * reclaiming packets (on 'tx done IRQ), if free space become > high mark, - * Tx queue resumed. - * - * The IPW operates with six queues, one receive queue in the device's - * sram, one transmit queue for sending commands to the device firmware, - * and four transmit queues for data. - * - * The four transmit queues allow for performing quality of service (qos) - * transmissions as per the 802.11 protocol. Currently Linux does not - * provide a mechanism to the user for utilizing prioritized queues, so - * we only utilize the first data transmit queue (queue1). - */ - -/** - * Driver allocates buffers of this size for Rx - */ - -/** - * ipw_rx_queue_space - Return number of free slots available in queue. - */ -static int ipw_rx_queue_space(const struct ipw_rx_queue *q) -{ - int s = q->read - q->write; - if (s <= 0) - s += RX_QUEUE_SIZE; - /* keep some buffer to not confuse full and empty queue */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - -static inline int ipw_tx_queue_space(const struct clx2_queue *q) -{ - int s = q->last_used - q->first_empty; - if (s <= 0) - s += q->n_bd; - s -= 2; /* keep some reserve to not confuse empty and full situations */ - if (s < 0) - s = 0; - return s; -} - -static inline int ipw_queue_inc_wrap(int index, int n_bd) -{ - return (++index == n_bd) ? 0 : index; -} - -/** - * Initialize common DMA queue structure - * - * @param q queue to init - * @param count Number of BD's to allocate. Should be power of 2 - * @param read_register Address for 'read' register - * (not offset within BAR, full address) - * @param write_register Address for 'write' register - * (not offset within BAR, full address) - * @param base_register Address for 'base' register - * (not offset within BAR, full address) - * @param size Address for 'size' register - * (not offset within BAR, full address) - */ -static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q, - int count, u32 read, u32 write, u32 base, u32 size) -{ - q->n_bd = count; - - q->low_mark = q->n_bd / 4; - if (q->low_mark < 4) - q->low_mark = 4; - - q->high_mark = q->n_bd / 8; - if (q->high_mark < 2) - q->high_mark = 2; - - q->first_empty = q->last_used = 0; - q->reg_r = read; - q->reg_w = write; - - ipw_write32(priv, base, q->dma_addr); - ipw_write32(priv, size, count); - ipw_write32(priv, read, 0); - ipw_write32(priv, write, 0); - - _ipw_read32(priv, 0x90); -} - -static int ipw_queue_tx_init(struct ipw_priv *priv, - struct clx2_tx_queue *q, - int count, u32 read, u32 write, u32 base, u32 size) -{ - struct pci_dev *dev = priv->pci_dev; - - q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL); - if (!q->txb) { - IPW_ERROR("vmalloc for auxilary BD structures failed\n"); - return -ENOMEM; - } - - q->bd = - pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr); - if (!q->bd) { - IPW_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(q->bd[0]) * count); - kfree(q->txb); - q->txb = NULL; - return -ENOMEM; - } - - ipw_queue_init(priv, &q->q, count, read, write, base, size); - return 0; -} - -/** - * Free one TFD, those at index [txq->q.last_used]. - * Do NOT advance any indexes - * - * @param dev - * @param txq - */ -static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, - struct clx2_tx_queue *txq) -{ - struct tfd_frame *bd = &txq->bd[txq->q.last_used]; - struct pci_dev *dev = priv->pci_dev; - int i; - - /* classify bd */ - if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE) - /* nothing to cleanup after for host commands */ - return; - - /* sanity check */ - if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) { - IPW_ERROR("Too many chunks: %i\n", - le32_to_cpu(bd->u.data.num_chunks)); - /** @todo issue fatal error, it is quite serious situation */ - return; - } - - /* unmap chunks if any */ - for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) { - pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]), - le16_to_cpu(bd->u.data.chunk_len[i]), - PCI_DMA_TODEVICE); - if (txq->txb[txq->q.last_used]) { - ieee80211_txb_free(txq->txb[txq->q.last_used]); - txq->txb[txq->q.last_used] = NULL; - } - } -} - -/** - * Deallocate DMA queue. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. - * - * @param dev - * @param q - */ -static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq) -{ - struct clx2_queue *q = &txq->q; - struct pci_dev *dev = priv->pci_dev; - - if (q->n_bd == 0) - return; - - /* first, empty all BD's */ - for (; q->first_empty != q->last_used; - q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) { - ipw_queue_tx_free_tfd(priv, txq); - } - - /* free buffers belonging to queue itself */ - pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd, - q->dma_addr); - kfree(txq->txb); - - /* 0 fill whole structure */ - memset(txq, 0, sizeof(*txq)); -} - -/** - * Destroy all DMA queues and structures - * - * @param priv - */ -static void ipw_tx_queue_free(struct ipw_priv *priv) -{ - /* Tx CMD queue */ - ipw_queue_tx_free(priv, &priv->txq_cmd); - - /* Tx queues */ - ipw_queue_tx_free(priv, &priv->txq[0]); - ipw_queue_tx_free(priv, &priv->txq[1]); - ipw_queue_tx_free(priv, &priv->txq[2]); - ipw_queue_tx_free(priv, &priv->txq[3]); -} - -static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid) -{ - /* First 3 bytes are manufacturer */ - bssid[0] = priv->mac_addr[0]; - bssid[1] = priv->mac_addr[1]; - bssid[2] = priv->mac_addr[2]; - - /* Last bytes are random */ - get_random_bytes(&bssid[3], ETH_ALEN - 3); - - bssid[0] &= 0xfe; /* clear multicast bit */ - bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */ -} - -static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) -{ - struct ipw_station_entry entry; - int i; - - for (i = 0; i < priv->num_stations; i++) { - if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { - /* Another node is active in network */ - priv->missed_adhoc_beacons = 0; - if (!(priv->config & CFG_STATIC_CHANNEL)) - /* when other nodes drop out, we drop out */ - priv->config &= ~CFG_ADHOC_PERSIST; - - return i; - } - } - - if (i == MAX_STATIONS) - return IPW_INVALID_STATION; - - IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid); - - entry.reserved = 0; - entry.support_mode = 0; - memcpy(entry.mac_addr, bssid, ETH_ALEN); - memcpy(priv->stations[i], bssid, ETH_ALEN); - ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry), - &entry, sizeof(entry)); - priv->num_stations++; - - return i; -} - -static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) -{ - int i; - - for (i = 0; i < priv->num_stations; i++) - if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) - return i; - - return IPW_INVALID_STATION; -} - -static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) -{ - int err; - - if (priv->status & STATUS_ASSOCIATING) { - IPW_DEBUG_ASSOC("Disassociating while associating.\n"); - queue_work(priv->workqueue, &priv->disassociate); - return; - } - - if (!(priv->status & STATUS_ASSOCIATED)) { - IPW_DEBUG_ASSOC("Disassociating while not associated.\n"); - return; - } - - IPW_DEBUG_ASSOC("Disassocation attempt from %pM " - "on channel %d.\n", - priv->assoc_request.bssid, - priv->assoc_request.channel); - - priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); - priv->status |= STATUS_DISASSOCIATING; - - if (quiet) - priv->assoc_request.assoc_type = HC_DISASSOC_QUIET; - else - priv->assoc_request.assoc_type = HC_DISASSOCIATE; - - err = ipw_send_associate(priv, &priv->assoc_request); - if (err) { - IPW_DEBUG_HC("Attempt to send [dis]associate command " - "failed.\n"); - return; - } - -} - -static int ipw_disassociate(void *data) -{ - struct ipw_priv *priv = data; - if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) - return 0; - ipw_send_disassociate(data, 0); - return 1; -} - -static void ipw_bg_disassociate(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, disassociate); - mutex_lock(&priv->mutex); - ipw_disassociate(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_system_config(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, system_config); - -#ifdef CONFIG_IPW2200_PROMISCUOUS - if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { - priv->sys_config.accept_all_data_frames = 1; - priv->sys_config.accept_non_directed_frames = 1; - priv->sys_config.accept_all_mgmt_bcpr = 1; - priv->sys_config.accept_all_mgmt_frames = 1; - } -#endif - - ipw_send_system_config(priv); -} - -struct ipw_status_code { - u16 status; - const char *reason; -}; - -static const struct ipw_status_code ipw_status_codes[] = { - {0x00, "Successful"}, - {0x01, "Unspecified failure"}, - {0x0A, "Cannot support all requested capabilities in the " - "Capability information field"}, - {0x0B, "Reassociation denied due to inability to confirm that " - "association exists"}, - {0x0C, "Association denied due to reason outside the scope of this " - "standard"}, - {0x0D, - "Responding station does not support the specified authentication " - "algorithm"}, - {0x0E, - "Received an Authentication frame with authentication sequence " - "transaction sequence number out of expected sequence"}, - {0x0F, "Authentication rejected because of challenge failure"}, - {0x10, "Authentication rejected due to timeout waiting for next " - "frame in sequence"}, - {0x11, "Association denied because AP is unable to handle additional " - "associated stations"}, - {0x12, - "Association denied due to requesting station not supporting all " - "of the datarates in the BSSBasicServiceSet Parameter"}, - {0x13, - "Association denied due to requesting station not supporting " - "short preamble operation"}, - {0x14, - "Association denied due to requesting station not supporting " - "PBCC encoding"}, - {0x15, - "Association denied due to requesting station not supporting " - "channel agility"}, - {0x19, - "Association denied due to requesting station not supporting " - "short slot operation"}, - {0x1A, - "Association denied due to requesting station not supporting " - "DSSS-OFDM operation"}, - {0x28, "Invalid Information Element"}, - {0x29, "Group Cipher is not valid"}, - {0x2A, "Pairwise Cipher is not valid"}, - {0x2B, "AKMP is not valid"}, - {0x2C, "Unsupported RSN IE version"}, - {0x2D, "Invalid RSN IE Capabilities"}, - {0x2E, "Cipher suite is rejected per security policy"}, -}; - -static const char *ipw_get_status_code(u16 status) -{ - int i; - for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++) - if (ipw_status_codes[i].status == (status & 0xff)) - return ipw_status_codes[i].reason; - return "Unknown status value."; -} - -static void inline average_init(struct average *avg) -{ - memset(avg, 0, sizeof(*avg)); -} - -#define DEPTH_RSSI 8 -#define DEPTH_NOISE 16 -static s16 exponential_average(s16 prev_avg, s16 val, u8 depth) -{ - return ((depth-1)*prev_avg + val)/depth; -} - -static void average_add(struct average *avg, s16 val) -{ - avg->sum -= avg->entries[avg->pos]; - avg->sum += val; - avg->entries[avg->pos++] = val; - if (unlikely(avg->pos == AVG_ENTRIES)) { - avg->init = 1; - avg->pos = 0; - } -} - -static s16 average_value(struct average *avg) -{ - if (!unlikely(avg->init)) { - if (avg->pos) - return avg->sum / avg->pos; - return 0; - } - - return avg->sum / AVG_ENTRIES; -} - -static void ipw_reset_stats(struct ipw_priv *priv) -{ - u32 len = sizeof(u32); - - priv->quality = 0; - - average_init(&priv->average_missed_beacons); - priv->exp_avg_rssi = -60; - priv->exp_avg_noise = -85 + 0x100; - - priv->last_rate = 0; - priv->last_missed_beacons = 0; - priv->last_rx_packets = 0; - priv->last_tx_packets = 0; - priv->last_tx_failures = 0; - - /* Firmware managed, reset only when NIC is restarted, so we have to - * normalize on the current value */ - ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, - &priv->last_rx_err, &len); - ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, - &priv->last_tx_failures, &len); - - /* Driver managed, reset with each association */ - priv->missed_adhoc_beacons = 0; - priv->missed_beacons = 0; - priv->tx_packets = 0; - priv->rx_packets = 0; - -} - -static u32 ipw_get_max_rate(struct ipw_priv *priv) -{ - u32 i = 0x80000000; - u32 mask = priv->rates_mask; - /* If currently associated in B mode, restrict the maximum - * rate match to B rates */ - if (priv->assoc_request.ieee_mode == IPW_B_MODE) - mask &= IEEE80211_CCK_RATES_MASK; - - /* TODO: Verify that the rate is supported by the current rates - * list. */ - - while (i && !(mask & i)) - i >>= 1; - switch (i) { - case IEEE80211_CCK_RATE_1MB_MASK: - return 1000000; - case IEEE80211_CCK_RATE_2MB_MASK: - return 2000000; - case IEEE80211_CCK_RATE_5MB_MASK: - return 5500000; - case IEEE80211_OFDM_RATE_6MB_MASK: - return 6000000; - case IEEE80211_OFDM_RATE_9MB_MASK: - return 9000000; - case IEEE80211_CCK_RATE_11MB_MASK: - return 11000000; - case IEEE80211_OFDM_RATE_12MB_MASK: - return 12000000; - case IEEE80211_OFDM_RATE_18MB_MASK: - return 18000000; - case IEEE80211_OFDM_RATE_24MB_MASK: - return 24000000; - case IEEE80211_OFDM_RATE_36MB_MASK: - return 36000000; - case IEEE80211_OFDM_RATE_48MB_MASK: - return 48000000; - case IEEE80211_OFDM_RATE_54MB_MASK: - return 54000000; - } - - if (priv->ieee->mode == IEEE_B) - return 11000000; - else - return 54000000; -} - -static u32 ipw_get_current_rate(struct ipw_priv *priv) -{ - u32 rate, len = sizeof(rate); - int err; - - if (!(priv->status & STATUS_ASSOCIATED)) - return 0; - - if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) { - err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate, - &len); - if (err) { - IPW_DEBUG_INFO("failed querying ordinals.\n"); - return 0; - } - } else - return ipw_get_max_rate(priv); - - switch (rate) { - case IPW_TX_RATE_1MB: - return 1000000; - case IPW_TX_RATE_2MB: - return 2000000; - case IPW_TX_RATE_5MB: - return 5500000; - case IPW_TX_RATE_6MB: - return 6000000; - case IPW_TX_RATE_9MB: - return 9000000; - case IPW_TX_RATE_11MB: - return 11000000; - case IPW_TX_RATE_12MB: - return 12000000; - case IPW_TX_RATE_18MB: - return 18000000; - case IPW_TX_RATE_24MB: - return 24000000; - case IPW_TX_RATE_36MB: - return 36000000; - case IPW_TX_RATE_48MB: - return 48000000; - case IPW_TX_RATE_54MB: - return 54000000; - } - - return 0; -} - -#define IPW_STATS_INTERVAL (2 * HZ) -static void ipw_gather_stats(struct ipw_priv *priv) -{ - u32 rx_err, rx_err_delta, rx_packets_delta; - u32 tx_failures, tx_failures_delta, tx_packets_delta; - u32 missed_beacons_percent, missed_beacons_delta; - u32 quality = 0; - u32 len = sizeof(u32); - s16 rssi; - u32 beacon_quality, signal_quality, tx_quality, rx_quality, - rate_quality; - u32 max_rate; - - if (!(priv->status & STATUS_ASSOCIATED)) { - priv->quality = 0; - return; - } - - /* Update the statistics */ - ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS, - &priv->missed_beacons, &len); - missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons; - priv->last_missed_beacons = priv->missed_beacons; - if (priv->assoc_request.beacon_interval) { - missed_beacons_percent = missed_beacons_delta * - (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) / - (IPW_STATS_INTERVAL * 10); - } else { - missed_beacons_percent = 0; - } - average_add(&priv->average_missed_beacons, missed_beacons_percent); - - ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len); - rx_err_delta = rx_err - priv->last_rx_err; - priv->last_rx_err = rx_err; - - ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len); - tx_failures_delta = tx_failures - priv->last_tx_failures; - priv->last_tx_failures = tx_failures; - - rx_packets_delta = priv->rx_packets - priv->last_rx_packets; - priv->last_rx_packets = priv->rx_packets; - - tx_packets_delta = priv->tx_packets - priv->last_tx_packets; - priv->last_tx_packets = priv->tx_packets; - - /* Calculate quality based on the following: - * - * Missed beacon: 100% = 0, 0% = 70% missed - * Rate: 60% = 1Mbs, 100% = Max - * Rx and Tx errors represent a straight % of total Rx/Tx - * RSSI: 100% = > -50, 0% = < -80 - * Rx errors: 100% = 0, 0% = 50% missed - * - * The lowest computed quality is used. - * - */ -#define BEACON_THRESHOLD 5 - beacon_quality = 100 - missed_beacons_percent; - if (beacon_quality < BEACON_THRESHOLD) - beacon_quality = 0; - else - beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 / - (100 - BEACON_THRESHOLD); - IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n", - beacon_quality, missed_beacons_percent); - - priv->last_rate = ipw_get_current_rate(priv); - max_rate = ipw_get_max_rate(priv); - rate_quality = priv->last_rate * 40 / max_rate + 60; - IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n", - rate_quality, priv->last_rate / 1000000); - - if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta) - rx_quality = 100 - (rx_err_delta * 100) / - (rx_packets_delta + rx_err_delta); - else - rx_quality = 100; - IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n", - rx_quality, rx_err_delta, rx_packets_delta); - - if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta) - tx_quality = 100 - (tx_failures_delta * 100) / - (tx_packets_delta + tx_failures_delta); - else - tx_quality = 100; - IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n", - tx_quality, tx_failures_delta, tx_packets_delta); - - rssi = priv->exp_avg_rssi; - signal_quality = - (100 * - (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * - (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) - - (priv->ieee->perfect_rssi - rssi) * - (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) + - 62 * (priv->ieee->perfect_rssi - rssi))) / - ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * - (priv->ieee->perfect_rssi - priv->ieee->worst_rssi)); - if (signal_quality > 100) - signal_quality = 100; - else if (signal_quality < 1) - signal_quality = 0; - - IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", - signal_quality, rssi); - - quality = min(beacon_quality, - min(rate_quality, - min(tx_quality, min(rx_quality, signal_quality)))); - if (quality == beacon_quality) - IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n", - quality); - if (quality == rate_quality) - IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n", - quality); - if (quality == tx_quality) - IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n", - quality); - if (quality == rx_quality) - IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n", - quality); - if (quality == signal_quality) - IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n", - quality); - - priv->quality = quality; - - queue_delayed_work(priv->workqueue, &priv->gather_stats, - IPW_STATS_INTERVAL); -} - -static void ipw_bg_gather_stats(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, gather_stats.work); - mutex_lock(&priv->mutex); - ipw_gather_stats(priv); - mutex_unlock(&priv->mutex); -} - -/* Missed beacon behavior: - * 1st missed -> roaming_threshold, just wait, don't do any scan/roam. - * roaming_threshold -> disassociate_threshold, scan and roam for better signal. - * Above disassociate threshold, give up and stop scanning. - * Roaming is disabled if disassociate_threshold <= roaming_threshold */ -static void ipw_handle_missed_beacon(struct ipw_priv *priv, - int missed_count) -{ - priv->notif_missed_beacons = missed_count; - - if (missed_count > priv->disassociate_threshold && - priv->status & STATUS_ASSOCIATED) { - /* If associated and we've hit the missed - * beacon threshold, disassociate, turn - * off roaming, and abort any active scans */ - IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | - IPW_DL_STATE | IPW_DL_ASSOC, - "Missed beacon: %d - disassociate\n", missed_count); - priv->status &= ~STATUS_ROAMING; - if (priv->status & STATUS_SCANNING) { - IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | - IPW_DL_STATE, - "Aborting scan with missed beacon.\n"); - queue_work(priv->workqueue, &priv->abort_scan); - } - - queue_work(priv->workqueue, &priv->disassociate); - return; - } - - if (priv->status & STATUS_ROAMING) { - /* If we are currently roaming, then just - * print a debug statement... */ - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "Missed beacon: %d - roam in progress\n", - missed_count); - return; - } - - if (roaming && - (missed_count > priv->roaming_threshold && - missed_count <= priv->disassociate_threshold)) { - /* If we are not already roaming, set the ROAM - * bit in the status and kick off a scan. - * This can happen several times before we reach - * disassociate_threshold. */ - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "Missed beacon: %d - initiate " - "roaming\n", missed_count); - if (!(priv->status & STATUS_ROAMING)) { - priv->status |= STATUS_ROAMING; - if (!(priv->status & STATUS_SCANNING)) - queue_delayed_work(priv->workqueue, - &priv->request_scan, 0); - } - return; - } - - if (priv->status & STATUS_SCANNING) { - /* Stop scan to keep fw from getting - * stuck (only if we aren't roaming -- - * otherwise we'll never scan more than 2 or 3 - * channels..) */ - IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE, - "Aborting scan with missed beacon.\n"); - queue_work(priv->workqueue, &priv->abort_scan); - } - - IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); -} - -static void ipw_scan_event(struct work_struct *work) -{ - union iwreq_data wrqu; - - struct ipw_priv *priv = - container_of(work, struct ipw_priv, scan_event.work); - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); -} - -static void handle_scan_event(struct ipw_priv *priv) -{ - /* Only userspace-requested scan completion events go out immediately */ - if (!priv->user_requested_scan) { - if (!delayed_work_pending(&priv->scan_event)) - queue_delayed_work(priv->workqueue, &priv->scan_event, - round_jiffies_relative(msecs_to_jiffies(4000))); - } else { - union iwreq_data wrqu; - - priv->user_requested_scan = 0; - cancel_delayed_work(&priv->scan_event); - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); - } -} - -/** - * Handle host notification packet. - * Called from interrupt routine - */ -static void ipw_rx_notification(struct ipw_priv *priv, - struct ipw_rx_notification *notif) -{ - DECLARE_SSID_BUF(ssid); - u16 size = le16_to_cpu(notif->size); - notif->size = le16_to_cpu(notif->size); - - IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size); - - switch (notif->subtype) { - case HOST_NOTIFICATION_STATUS_ASSOCIATED:{ - struct notif_association *assoc = ¬if->u.assoc; - - switch (assoc->state) { - case CMAS_ASSOCIATED:{ - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, - "associated: '%s' %pM \n", - print_ssid(ssid, priv->essid, - priv->essid_len), - priv->bssid); - - switch (priv->ieee->iw_mode) { - case IW_MODE_INFRA: - memcpy(priv->ieee->bssid, - priv->bssid, ETH_ALEN); - break; - - case IW_MODE_ADHOC: - memcpy(priv->ieee->bssid, - priv->bssid, ETH_ALEN); - - /* clear out the station table */ - priv->num_stations = 0; - - IPW_DEBUG_ASSOC - ("queueing adhoc check\n"); - queue_delayed_work(priv-> - workqueue, - &priv-> - adhoc_check, - le16_to_cpu(priv-> - assoc_request. - beacon_interval)); - break; - } - - priv->status &= ~STATUS_ASSOCIATING; - priv->status |= STATUS_ASSOCIATED; - queue_work(priv->workqueue, - &priv->system_config); - -#ifdef CONFIG_IPW2200_QOS -#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ - le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control)) - if ((priv->status & STATUS_AUTH) && - (IPW_GET_PACKET_STYPE(¬if->u.raw) - == IEEE80211_STYPE_ASSOC_RESP)) { - if ((sizeof - (struct - ieee80211_assoc_response) - <= size) - && (size <= 2314)) { - struct - ieee80211_rx_stats - stats = { - .len = size - 1, - }; - - IPW_DEBUG_QOS - ("QoS Associate " - "size %d\n", size); - ieee80211_rx_mgt(priv-> - ieee, - (struct - ieee80211_hdr_4addr - *) - ¬if->u.raw, &stats); - } - } -#endif - - schedule_work(&priv->link_up); - - break; - } - - case CMAS_AUTHENTICATED:{ - if (priv-> - status & (STATUS_ASSOCIATED | - STATUS_AUTH)) { - struct notif_authenticate *auth - = ¬if->u.auth; - IPW_DEBUG(IPW_DL_NOTIF | - IPW_DL_STATE | - IPW_DL_ASSOC, - "deauthenticated: '%s' " - "%pM" - ": (0x%04X) - %s \n", - print_ssid(ssid, - priv-> - essid, - priv-> - essid_len), - priv->bssid, - le16_to_cpu(auth->status), - ipw_get_status_code - (le16_to_cpu - (auth->status))); - - priv->status &= - ~(STATUS_ASSOCIATING | - STATUS_AUTH | - STATUS_ASSOCIATED); - - schedule_work(&priv->link_down); - break; - } - - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, - "authenticated: '%s' %pM\n", - print_ssid(ssid, priv->essid, - priv->essid_len), - priv->bssid); - break; - } - - case CMAS_INIT:{ - if (priv->status & STATUS_AUTH) { - struct - ieee80211_assoc_response - *resp; - resp = - (struct - ieee80211_assoc_response - *)¬if->u.raw; - IPW_DEBUG(IPW_DL_NOTIF | - IPW_DL_STATE | - IPW_DL_ASSOC, - "association failed (0x%04X): %s\n", - le16_to_cpu(resp->status), - ipw_get_status_code - (le16_to_cpu - (resp->status))); - } - - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, - "disassociated: '%s' %pM \n", - print_ssid(ssid, priv->essid, - priv->essid_len), - priv->bssid); - - priv->status &= - ~(STATUS_DISASSOCIATING | - STATUS_ASSOCIATING | - STATUS_ASSOCIATED | STATUS_AUTH); - if (priv->assoc_network - && (priv->assoc_network-> - capability & - WLAN_CAPABILITY_IBSS)) - ipw_remove_current_network - (priv); - - schedule_work(&priv->link_down); - - break; - } - - case CMAS_RX_ASSOC_RESP: - break; - - default: - IPW_ERROR("assoc: unknown (%d)\n", - assoc->state); - break; - } - - break; - } - - case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{ - struct notif_authenticate *auth = ¬if->u.auth; - switch (auth->state) { - case CMAS_AUTHENTICATED: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "authenticated: '%s' %pM \n", - print_ssid(ssid, priv->essid, - priv->essid_len), - priv->bssid); - priv->status |= STATUS_AUTH; - break; - - case CMAS_INIT: - if (priv->status & STATUS_AUTH) { - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, - "authentication failed (0x%04X): %s\n", - le16_to_cpu(auth->status), - ipw_get_status_code(le16_to_cpu - (auth-> - status))); - } - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, - "deauthenticated: '%s' %pM\n", - print_ssid(ssid, priv->essid, - priv->essid_len), - priv->bssid); - - priv->status &= ~(STATUS_ASSOCIATING | - STATUS_AUTH | - STATUS_ASSOCIATED); - - schedule_work(&priv->link_down); - break; - - case CMAS_TX_AUTH_SEQ_1: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUTH_SEQ_1\n"); - break; - case CMAS_RX_AUTH_SEQ_2: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUTH_SEQ_2\n"); - break; - case CMAS_AUTH_SEQ_1_PASS: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n"); - break; - case CMAS_AUTH_SEQ_1_FAIL: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n"); - break; - case CMAS_TX_AUTH_SEQ_3: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUTH_SEQ_3\n"); - break; - case CMAS_RX_AUTH_SEQ_4: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n"); - break; - case CMAS_AUTH_SEQ_2_PASS: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n"); - break; - case CMAS_AUTH_SEQ_2_FAIL: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n"); - break; - case CMAS_TX_ASSOC: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "TX_ASSOC\n"); - break; - case CMAS_RX_ASSOC_RESP: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "RX_ASSOC_RESP\n"); - - break; - case CMAS_ASSOCIATED: - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | - IPW_DL_ASSOC, "ASSOCIATED\n"); - break; - default: - IPW_DEBUG_NOTIF("auth: failure - %d\n", - auth->state); - break; - } - break; - } - - case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{ - struct notif_channel_result *x = - ¬if->u.channel_result; - - if (size == sizeof(*x)) { - IPW_DEBUG_SCAN("Scan result for channel %d\n", - x->channel_num); - } else { - IPW_DEBUG_SCAN("Scan result of wrong size %d " - "(should be %zd)\n", - size, sizeof(*x)); - } - break; - } - - case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{ - struct notif_scan_complete *x = ¬if->u.scan_complete; - if (size == sizeof(*x)) { - IPW_DEBUG_SCAN - ("Scan completed: type %d, %d channels, " - "%d status\n", x->scan_type, - x->num_channels, x->status); - } else { - IPW_ERROR("Scan completed of wrong size %d " - "(should be %zd)\n", - size, sizeof(*x)); - } - - priv->status &= - ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); - - wake_up_interruptible(&priv->wait_state); - cancel_delayed_work(&priv->scan_check); - - if (priv->status & STATUS_EXIT_PENDING) - break; - - priv->ieee->scans++; - -#ifdef CONFIG_IPW2200_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - priv->status |= STATUS_SCAN_FORCED; - queue_delayed_work(priv->workqueue, - &priv->request_scan, 0); - break; - } - priv->status &= ~STATUS_SCAN_FORCED; -#endif /* CONFIG_IPW2200_MONITOR */ - - /* Do queued direct scans first */ - if (priv->status & STATUS_DIRECT_SCAN_PENDING) { - queue_delayed_work(priv->workqueue, - &priv->request_direct_scan, 0); - } - - if (!(priv->status & (STATUS_ASSOCIATED | - STATUS_ASSOCIATING | - STATUS_ROAMING | - STATUS_DISASSOCIATING))) - queue_work(priv->workqueue, &priv->associate); - else if (priv->status & STATUS_ROAMING) { - if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) - /* If a scan completed and we are in roam mode, then - * the scan that completed was the one requested as a - * result of entering roam... so, schedule the - * roam work */ - queue_work(priv->workqueue, - &priv->roam); - else - /* Don't schedule if we aborted the scan */ - priv->status &= ~STATUS_ROAMING; - } else if (priv->status & STATUS_SCAN_PENDING) - queue_delayed_work(priv->workqueue, - &priv->request_scan, 0); - else if (priv->config & CFG_BACKGROUND_SCAN - && priv->status & STATUS_ASSOCIATED) - queue_delayed_work(priv->workqueue, - &priv->request_scan, - round_jiffies_relative(HZ)); - - /* Send an empty event to user space. - * We don't send the received data on the event because - * it would require us to do complex transcoding, and - * we want to minimise the work done in the irq handler - * Use a request to extract the data. - * Also, we generate this even for any scan, regardless - * on how the scan was initiated. User space can just - * sync on periodic scan to get fresh data... - * Jean II */ - if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) - handle_scan_event(priv); - break; - } - - case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{ - struct notif_frag_length *x = ¬if->u.frag_len; - - if (size == sizeof(*x)) - IPW_ERROR("Frag length: %d\n", - le16_to_cpu(x->frag_length)); - else - IPW_ERROR("Frag length of wrong size %d " - "(should be %zd)\n", - size, sizeof(*x)); - break; - } - - case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{ - struct notif_link_deterioration *x = - ¬if->u.link_deterioration; - - if (size == sizeof(*x)) { - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "link deterioration: type %d, cnt %d\n", - x->silence_notification_type, - x->silence_count); - memcpy(&priv->last_link_deterioration, x, - sizeof(*x)); - } else { - IPW_ERROR("Link Deterioration of wrong size %d " - "(should be %zd)\n", - size, sizeof(*x)); - } - break; - } - - case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{ - IPW_ERROR("Dino config\n"); - if (priv->hcmd - && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG) - IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n"); - - break; - } - - case HOST_NOTIFICATION_STATUS_BEACON_STATE:{ - struct notif_beacon_state *x = ¬if->u.beacon_state; - if (size != sizeof(*x)) { - IPW_ERROR - ("Beacon state of wrong size %d (should " - "be %zd)\n", size, sizeof(*x)); - break; - } - - if (le32_to_cpu(x->state) == - HOST_NOTIFICATION_STATUS_BEACON_MISSING) - ipw_handle_missed_beacon(priv, - le32_to_cpu(x-> - number)); - - break; - } - - case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{ - struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key; - if (size == sizeof(*x)) { - IPW_ERROR("TGi Tx Key: state 0x%02x sec type " - "0x%02x station %d\n", - x->key_state, x->security_type, - x->station_index); - break; - } - - IPW_ERROR - ("TGi Tx Key of wrong size %d (should be %zd)\n", - size, sizeof(*x)); - break; - } - - case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{ - struct notif_calibration *x = ¬if->u.calibration; - - if (size == sizeof(*x)) { - memcpy(&priv->calib, x, sizeof(*x)); - IPW_DEBUG_INFO("TODO: Calibration\n"); - break; - } - - IPW_ERROR - ("Calibration of wrong size %d (should be %zd)\n", - size, sizeof(*x)); - break; - } - - case HOST_NOTIFICATION_NOISE_STATS:{ - if (size == sizeof(u32)) { - priv->exp_avg_noise = - exponential_average(priv->exp_avg_noise, - (u8) (le32_to_cpu(notif->u.noise.value) & 0xff), - DEPTH_NOISE); - break; - } - - IPW_ERROR - ("Noise stat is wrong size %d (should be %zd)\n", - size, sizeof(u32)); - break; - } - - default: - IPW_DEBUG_NOTIF("Unknown notification: " - "subtype=%d,flags=0x%2x,size=%d\n", - notif->subtype, notif->flags, size); - } -} - -/** - * Destroys all DMA structures and initialise them again - * - * @param priv - * @return error code - */ -static int ipw_queue_reset(struct ipw_priv *priv) -{ - int rc = 0; - /** @todo customize queue sizes */ - int nTx = 64, nTxCmd = 8; - ipw_tx_queue_free(priv); - /* Tx CMD queue */ - rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd, - IPW_TX_CMD_QUEUE_READ_INDEX, - IPW_TX_CMD_QUEUE_WRITE_INDEX, - IPW_TX_CMD_QUEUE_BD_BASE, - IPW_TX_CMD_QUEUE_BD_SIZE); - if (rc) { - IPW_ERROR("Tx Cmd queue init failed\n"); - goto error; - } - /* Tx queue(s) */ - rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx, - IPW_TX_QUEUE_0_READ_INDEX, - IPW_TX_QUEUE_0_WRITE_INDEX, - IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE); - if (rc) { - IPW_ERROR("Tx 0 queue init failed\n"); - goto error; - } - rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx, - IPW_TX_QUEUE_1_READ_INDEX, - IPW_TX_QUEUE_1_WRITE_INDEX, - IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE); - if (rc) { - IPW_ERROR("Tx 1 queue init failed\n"); - goto error; - } - rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx, - IPW_TX_QUEUE_2_READ_INDEX, - IPW_TX_QUEUE_2_WRITE_INDEX, - IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE); - if (rc) { - IPW_ERROR("Tx 2 queue init failed\n"); - goto error; - } - rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx, - IPW_TX_QUEUE_3_READ_INDEX, - IPW_TX_QUEUE_3_WRITE_INDEX, - IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE); - if (rc) { - IPW_ERROR("Tx 3 queue init failed\n"); - goto error; - } - /* statistics */ - priv->rx_bufs_min = 0; - priv->rx_pend_max = 0; - return rc; - - error: - ipw_tx_queue_free(priv); - return rc; -} - -/** - * Reclaim Tx queue entries no more used by NIC. - * - * When FW advances 'R' index, all entries between old and - * new 'R' index need to be reclaimed. As result, some free space - * forms. If there is enough free space (> low mark), wake Tx queue. - * - * @note Need to protect against garbage in 'R' index - * @param priv - * @param txq - * @param qindex - * @return Number of used entries remains in the queue - */ -static int ipw_queue_tx_reclaim(struct ipw_priv *priv, - struct clx2_tx_queue *txq, int qindex) -{ - u32 hw_tail; - int used; - struct clx2_queue *q = &txq->q; - - hw_tail = ipw_read32(priv, q->reg_r); - if (hw_tail >= q->n_bd) { - IPW_ERROR - ("Read index for DMA queue (%d) is out of range [0-%d)\n", - hw_tail, q->n_bd); - goto done; - } - for (; q->last_used != hw_tail; - q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) { - ipw_queue_tx_free_tfd(priv, txq); - priv->tx_packets++; - } - done: - if ((ipw_tx_queue_space(q) > q->low_mark) && - (qindex >= 0)) - netif_wake_queue(priv->net_dev); - used = q->first_empty - q->last_used; - if (used < 0) - used += q->n_bd; - - return used; -} - -static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, - int len, int sync) -{ - struct clx2_tx_queue *txq = &priv->txq_cmd; - struct clx2_queue *q = &txq->q; - struct tfd_frame *tfd; - - if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) { - IPW_ERROR("No space for Tx\n"); - return -EBUSY; - } - - tfd = &txq->bd[q->first_empty]; - txq->txb[q->first_empty] = NULL; - - memset(tfd, 0, sizeof(*tfd)); - tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE; - tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; - priv->hcmd_seq++; - tfd->u.cmd.index = hcmd; - tfd->u.cmd.length = len; - memcpy(tfd->u.cmd.payload, buf, len); - q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); - ipw_write32(priv, q->reg_w, q->first_empty); - _ipw_read32(priv, 0x90); - - return 0; -} - -/* - * Rx theory of operation - * - * The host allocates 32 DMA target addresses and passes the host address - * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is - * 0 to 31 - * - * Rx Queue Indexes - * The host/firmware share two index registers for managing the Rx buffers. - * - * The READ index maps to the first position that the firmware may be writing - * to -- the driver can read up to (but not including) this position and get - * good data. - * The READ index is managed by the firmware once the card is enabled. - * - * The WRITE index maps to the last position the driver has read from -- the - * position preceding WRITE is the last slot the firmware can place a packet. - * - * The queue is empty (no good data) if WRITE = READ - 1, and is full if - * WRITE = READ. - * - * During initialization the host sets up the READ queue position to the first - * INDEX position, and WRITE to the last (READ - 1 wrapped) - * - * When the firmware places a packet in a buffer it will advance the READ index - * and fire the RX interrupt. The driver can then query the READ index and - * process as many packets as possible, moving the WRITE index forward as it - * resets the Rx queue buffers with new memory. - * - * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When - * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replensish the ipw->rxq->rx_free. - * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the - * ipw->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) - * + A received packet is processed and handed to the kernel network stack, - * detached from the ipw->rxq. The driver 'processed' index is updated. - * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free - * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ - * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there - * were enough free buffers and RX_STALLED is set it is cleared. - * - * - * Driver sequence: - * - * ipw_rx_queue_alloc() Allocates rx_free - * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls - * ipw_rx_queue_restock - * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx - * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules ipw_rx_queue_replenish - * - * -- enable interrupts -- - * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the - * READ INDEX, detaching the SKB from the pool. - * Moves the packet buffer from queue to rx_used. - * Calls ipw_rx_queue_restock to refill any empty - * slots. - * ... - * - */ - -/* - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. - */ -static void ipw_rx_queue_restock(struct ipw_priv *priv) -{ - struct ipw_rx_queue *rxq = priv->rxq; - struct list_head *element; - struct ipw_rx_mem_buffer *rxb; - unsigned long flags; - int write; - - spin_lock_irqsave(&rxq->lock, flags); - write = rxq->write; - while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) { - element = rxq->rx_free.next; - rxb = list_entry(element, struct ipw_rx_mem_buffer, list); - list_del(element); - - ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE, - rxb->dma_addr); - rxq->queue[rxq->write] = rxb; - rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE; - rxq->free_count--; - } - spin_unlock_irqrestore(&rxq->lock, flags); - - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(priv->workqueue, &priv->rx_replenish); - - /* If we've added more space for the firmware to place data, tell it */ - if (write != rxq->write) - ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write); -} - -/* - * Move all used packet from rx_used to rx_free, allocating a new SKB for each. - * Also restock the Rx queue via ipw_rx_queue_restock. - * - * This is called as a scheduled work item (except for during intialization) - */ -static void ipw_rx_queue_replenish(void *data) -{ - struct ipw_priv *priv = data; - struct ipw_rx_queue *rxq = priv->rxq; - struct list_head *element; - struct ipw_rx_mem_buffer *rxb; - unsigned long flags; - - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { - element = rxq->rx_used.next; - rxb = list_entry(element, struct ipw_rx_mem_buffer, list); - rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC); - if (!rxb->skb) { - printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n", - priv->net_dev->name); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ - break; - } - list_del(element); - - rxb->dma_addr = - pci_map_single(priv->pci_dev, rxb->skb->data, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } - spin_unlock_irqrestore(&rxq->lock, flags); - - ipw_rx_queue_restock(priv); -} - -static void ipw_bg_rx_queue_replenish(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, rx_replenish); - mutex_lock(&priv->mutex); - ipw_rx_queue_replenish(priv); - mutex_unlock(&priv->mutex); -} - -/* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have its SKB set to NULL - * This free routine walks the list of POOL entries and if SKB is set to - * non NULL it is unmapped and freed - */ -static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq) -{ - int i; - - if (!rxq) - return; - - for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); - } - } - - kfree(rxq); -} - -static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) -{ - struct ipw_rx_queue *rxq; - int i; - - rxq = kzalloc(sizeof(*rxq), GFP_KERNEL); - if (unlikely(!rxq)) { - IPW_ERROR("memory allocation failed\n"); - return NULL; - } - spin_lock_init(&rxq->lock); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->free_count = 0; - - return rxq; -} - -static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) -{ - rate &= ~IEEE80211_BASIC_RATE_MASK; - if (ieee_mode == IEEE_A) { - switch (rate) { - case IEEE80211_OFDM_RATE_6MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? - 1 : 0; - case IEEE80211_OFDM_RATE_9MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? - 1 : 0; - case IEEE80211_OFDM_RATE_12MB: - return priv-> - rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_18MB: - return priv-> - rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_24MB: - return priv-> - rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_36MB: - return priv-> - rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_48MB: - return priv-> - rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_54MB: - return priv-> - rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; - default: - return 0; - } - } - - /* B and G mixed */ - switch (rate) { - case IEEE80211_CCK_RATE_1MB: - return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_2MB: - return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_5MB: - return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_11MB: - return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0; - } - - /* If we are limited to B modulations, bail at this point */ - if (ieee_mode == IEEE_B) - return 0; - - /* G */ - switch (rate) { - case IEEE80211_OFDM_RATE_6MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_9MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_12MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_18MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_24MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_36MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_48MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_54MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; - } - - return 0; -} - -static int ipw_compatible_rates(struct ipw_priv *priv, - const struct ieee80211_network *network, - struct ipw_supported_rates *rates) -{ - int num_rates, i; - - memset(rates, 0, sizeof(*rates)); - num_rates = min(network->rates_len, (u8) IPW_MAX_RATES); - rates->num_rates = 0; - for (i = 0; i < num_rates; i++) { - if (!ipw_is_rate_in_mask(priv, network->mode, - network->rates[i])) { - - if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { - IPW_DEBUG_SCAN("Adding masked mandatory " - "rate %02X\n", - network->rates[i]); - rates->supported_rates[rates->num_rates++] = - network->rates[i]; - continue; - } - - IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", - network->rates[i], priv->rates_mask); - continue; - } - - rates->supported_rates[rates->num_rates++] = network->rates[i]; - } - - num_rates = min(network->rates_ex_len, - (u8) (IPW_MAX_RATES - num_rates)); - for (i = 0; i < num_rates; i++) { - if (!ipw_is_rate_in_mask(priv, network->mode, - network->rates_ex[i])) { - if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { - IPW_DEBUG_SCAN("Adding masked mandatory " - "rate %02X\n", - network->rates_ex[i]); - rates->supported_rates[rates->num_rates++] = - network->rates[i]; - continue; - } - - IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", - network->rates_ex[i], priv->rates_mask); - continue; - } - - rates->supported_rates[rates->num_rates++] = - network->rates_ex[i]; - } - - return 1; -} - -static void ipw_copy_rates(struct ipw_supported_rates *dest, - const struct ipw_supported_rates *src) -{ - u8 i; - for (i = 0; i < src->num_rates; i++) - dest->supported_rates[i] = src->supported_rates[i]; - dest->num_rates = src->num_rates; -} - -/* TODO: Look at sniffed packets in the air to determine if the basic rate - * mask should ever be used -- right now all callers to add the scan rates are - * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */ -static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates, - u8 modulation, u32 rate_mask) -{ - u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? - IEEE80211_BASIC_RATE_MASK : 0; - - if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - - if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - - if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK) - rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_CCK_RATE_5MB; - - if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK) - rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_CCK_RATE_11MB; -} - -static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates, - u8 modulation, u32 rate_mask) -{ - u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? - IEEE80211_BASIC_RATE_MASK : 0; - - if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK) - rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_6MB; - - if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_9MB; - - if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK) - rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_12MB; - - if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_18MB; - - if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK) - rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_24MB; - - if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_36MB; - - if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_48MB; - - if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK) - rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_54MB; -} - -struct ipw_network_match { - struct ieee80211_network *network; - struct ipw_supported_rates rates; -}; - -static int ipw_find_adhoc_network(struct ipw_priv *priv, - struct ipw_network_match *match, - struct ieee80211_network *network, - int roaming) -{ - struct ipw_supported_rates rates; - DECLARE_SSID_BUF(ssid); - - /* Verify that this network's capability is compatible with the - * current mode (AdHoc or Infrastructure) */ - if ((priv->ieee->iw_mode == IW_MODE_ADHOC && - !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " - "capability mismatch.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - if (unlikely(roaming)) { - /* If we are roaming, then ensure check if this is a valid - * network to try and roam to */ - if ((network->ssid_len != match->network->ssid_len) || - memcmp(network->ssid, match->network->ssid, - network->ssid_len)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of non-network ESSID.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - } else { - /* If an ESSID has been configured then compare the broadcast - * ESSID to ours */ - if ((priv->config & CFG_STATIC_ESSID) && - ((network->ssid_len != priv->essid_len) || - memcmp(network->ssid, priv->essid, - min(network->ssid_len, priv->essid_len)))) { - char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - - strncpy(escaped, - print_ssid(ssid, network->ssid, - network->ssid_len), - sizeof(escaped)); - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of ESSID mismatch: '%s'.\n", - escaped, network->bssid, - print_ssid(ssid, priv->essid, - priv->essid_len)); - return 0; - } - } - - /* If the old network rate is better than this one, don't bother - * testing everything else. */ - - if (network->time_stamp[0] < match->network->time_stamp[0]) { - IPW_DEBUG_MERGE("Network '%s excluded because newer than " - "current network.\n", - print_ssid(ssid, match->network->ssid, - match->network->ssid_len)); - return 0; - } else if (network->time_stamp[1] < match->network->time_stamp[1]) { - IPW_DEBUG_MERGE("Network '%s excluded because newer than " - "current network.\n", - print_ssid(ssid, match->network->ssid, - match->network->ssid_len)); - return 0; - } - - /* Now go through and see if the requested network is valid... */ - if (priv->ieee->scan_age != 0 && - time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of age: %ums.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - jiffies_to_msecs(jiffies - - network->last_scanned)); - return 0; - } - - if ((priv->config & CFG_STATIC_CHANNEL) && - (network->channel != priv->channel)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of channel mismatch: %d != %d.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - network->channel, priv->channel); - return 0; - } - - /* Verify privacy compatability */ - if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != - ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of privacy mismatch: %s != %s.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - priv-> - capability & CAP_PRIVACY_ON ? "on" : "off", - network-> - capability & WLAN_CAPABILITY_PRIVACY ? "on" : - "off"); - return 0; - } - - if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of the same BSSID match: %pM" - ".\n", print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - priv->bssid); - return 0; - } - - /* Filter out any incompatible freq / mode combinations */ - if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of invalid frequency/mode " - "combination.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - /* Ensure that the rates supported by the driver are compatible with - * this AP, including verification of basic rates (mandatory) */ - if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because configured rate mask excludes " - "AP mandatory rate.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - if (rates.num_rates == 0) { - IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " - "because of no compatible rates.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - /* TODO: Perform any further minimal comparititive tests. We do not - * want to put too much policy logic here; intelligent scan selection - * should occur within a generic IEEE 802.11 user space tool. */ - - /* Set up 'new' AP to this network */ - ipw_copy_rates(&match->rates, &rates); - match->network = network; - IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", - print_ssid(ssid, network->ssid, network->ssid_len), - network->bssid); - - return 1; -} - -static void ipw_merge_adhoc_network(struct work_struct *work) -{ - DECLARE_SSID_BUF(ssid); - struct ipw_priv *priv = - container_of(work, struct ipw_priv, merge_networks); - struct ieee80211_network *network = NULL; - struct ipw_network_match match = { - .network = priv->assoc_network - }; - - if ((priv->status & STATUS_ASSOCIATED) && - (priv->ieee->iw_mode == IW_MODE_ADHOC)) { - /* First pass through ROAM process -- look for a better - * network */ - unsigned long flags; - - spin_lock_irqsave(&priv->ieee->lock, flags); - list_for_each_entry(network, &priv->ieee->network_list, list) { - if (network != priv->assoc_network) - ipw_find_adhoc_network(priv, &match, network, - 1); - } - spin_unlock_irqrestore(&priv->ieee->lock, flags); - - if (match.network == priv->assoc_network) { - IPW_DEBUG_MERGE("No better ADHOC in this network to " - "merge to.\n"); - return; - } - - mutex_lock(&priv->mutex); - if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { - IPW_DEBUG_MERGE("remove network %s\n", - print_ssid(ssid, priv->essid, - priv->essid_len)); - ipw_remove_current_network(priv); - } - - ipw_disassociate(priv); - priv->assoc_network = match.network; - mutex_unlock(&priv->mutex); - return; - } -} - -static int ipw_best_network(struct ipw_priv *priv, - struct ipw_network_match *match, - struct ieee80211_network *network, int roaming) -{ - struct ipw_supported_rates rates; - DECLARE_SSID_BUF(ssid); - - /* Verify that this network's capability is compatible with the - * current mode (AdHoc or Infrastructure) */ - if ((priv->ieee->iw_mode == IW_MODE_INFRA && - !(network->capability & WLAN_CAPABILITY_ESS)) || - (priv->ieee->iw_mode == IW_MODE_ADHOC && - !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " - "capability mismatch.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - if (unlikely(roaming)) { - /* If we are roaming, then ensure check if this is a valid - * network to try and roam to */ - if ((network->ssid_len != match->network->ssid_len) || - memcmp(network->ssid, match->network->ssid, - network->ssid_len)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of non-network ESSID.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - } else { - /* If an ESSID has been configured then compare the broadcast - * ESSID to ours */ - if ((priv->config & CFG_STATIC_ESSID) && - ((network->ssid_len != priv->essid_len) || - memcmp(network->ssid, priv->essid, - min(network->ssid_len, priv->essid_len)))) { - char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - strncpy(escaped, - print_ssid(ssid, network->ssid, - network->ssid_len), - sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of ESSID mismatch: '%s'.\n", - escaped, network->bssid, - print_ssid(ssid, priv->essid, - priv->essid_len)); - return 0; - } - } - - /* If the old network rate is better than this one, don't bother - * testing everything else. */ - if (match->network && match->network->stats.rssi > network->stats.rssi) { - char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - strncpy(escaped, - print_ssid(ssid, network->ssid, network->ssid_len), - sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " - "'%s (%pM)' has a stronger signal.\n", - escaped, network->bssid, - print_ssid(ssid, match->network->ssid, - match->network->ssid_len), - match->network->bssid); - return 0; - } - - /* If this network has already had an association attempt within the - * last 3 seconds, do not try and associate again... */ - if (network->last_associate && - time_after(network->last_associate + (HZ * 3UL), jiffies)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of storming (%ums since last " - "assoc attempt).\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - jiffies_to_msecs(jiffies - - network->last_associate)); - return 0; - } - - /* Now go through and see if the requested network is valid... */ - if (priv->ieee->scan_age != 0 && - time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of age: %ums.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - jiffies_to_msecs(jiffies - - network->last_scanned)); - return 0; - } - - if ((priv->config & CFG_STATIC_CHANNEL) && - (network->channel != priv->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of channel mismatch: %d != %d.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - network->channel, priv->channel); - return 0; - } - - /* Verify privacy compatability */ - if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != - ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of privacy mismatch: %s != %s.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, - priv->capability & CAP_PRIVACY_ON ? "on" : - "off", - network->capability & - WLAN_CAPABILITY_PRIVACY ? "on" : "off"); - return 0; - } - - if ((priv->config & CFG_STATIC_BSSID) && - memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of BSSID mismatch: %pM.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid, priv->bssid); - return 0; - } - - /* Filter out any incompatible freq / mode combinations */ - if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of invalid frequency/mode " - "combination.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - /* Filter out invalid channel in current GEO */ - if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of invalid channel in current GEO\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - /* Ensure that the rates supported by the driver are compatible with - * this AP, including verification of basic rates (mandatory) */ - if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because configured rate mask excludes " - "AP mandatory rate.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - if (rates.num_rates == 0) { - IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " - "because of no compatible rates.\n", - print_ssid(ssid, network->ssid, - network->ssid_len), - network->bssid); - return 0; - } - - /* TODO: Perform any further minimal comparititive tests. We do not - * want to put too much policy logic here; intelligent scan selection - * should occur within a generic IEEE 802.11 user space tool. */ - - /* Set up 'new' AP to this network */ - ipw_copy_rates(&match->rates, &rates); - match->network = network; - - IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", - print_ssid(ssid, network->ssid, network->ssid_len), - network->bssid); - - return 1; -} - -static void ipw_adhoc_create(struct ipw_priv *priv, - struct ieee80211_network *network) -{ - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - int i; - - /* - * For the purposes of scanning, we can set our wireless mode - * to trigger scans across combinations of bands, but when it - * comes to creating a new ad-hoc network, we have tell the FW - * exactly which band to use. - * - * We also have the possibility of an invalid channel for the - * chossen band. Attempting to create a new ad-hoc network - * with an invalid channel for wireless mode will trigger a - * FW fatal error. - * - */ - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: - network->mode = IEEE_A; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); - BUG_ON(i == -1); - if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { - IPW_WARNING("Overriding invalid channel\n"); - priv->channel = geo->a[0].channel; - } - break; - - case IEEE80211_24GHZ_BAND: - if (priv->ieee->mode & IEEE_G) - network->mode = IEEE_G; - else - network->mode = IEEE_B; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); - BUG_ON(i == -1); - if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { - IPW_WARNING("Overriding invalid channel\n"); - priv->channel = geo->bg[0].channel; - } - break; - - default: - IPW_WARNING("Overriding invalid channel\n"); - if (priv->ieee->mode & IEEE_A) { - network->mode = IEEE_A; - priv->channel = geo->a[0].channel; - } else if (priv->ieee->mode & IEEE_G) { - network->mode = IEEE_G; - priv->channel = geo->bg[0].channel; - } else { - network->mode = IEEE_B; - priv->channel = geo->bg[0].channel; - } - break; - } - - network->channel = priv->channel; - priv->config |= CFG_ADHOC_PERSIST; - ipw_create_bssid(priv, network->bssid); - network->ssid_len = priv->essid_len; - memcpy(network->ssid, priv->essid, priv->essid_len); - memset(&network->stats, 0, sizeof(network->stats)); - network->capability = WLAN_CAPABILITY_IBSS; - if (!(priv->config & CFG_PREAMBLE_LONG)) - network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; - if (priv->capability & CAP_PRIVACY_ON) - network->capability |= WLAN_CAPABILITY_PRIVACY; - network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH); - memcpy(network->rates, priv->rates.supported_rates, network->rates_len); - network->rates_ex_len = priv->rates.num_rates - network->rates_len; - memcpy(network->rates_ex, - &priv->rates.supported_rates[network->rates_len], - network->rates_ex_len); - network->last_scanned = 0; - network->flags = 0; - network->last_associate = 0; - network->time_stamp[0] = 0; - network->time_stamp[1] = 0; - network->beacon_interval = 100; /* Default */ - network->listen_interval = 10; /* Default */ - network->atim_window = 0; /* Default */ - network->wpa_ie_len = 0; - network->rsn_ie_len = 0; -} - -static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index) -{ - struct ipw_tgi_tx_key key; - - if (!(priv->ieee->sec.flags & (1 << index))) - return; - - key.key_id = index; - memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); - key.security_type = type; - key.station_index = 0; /* always 0 for BSS */ - key.flags = 0; - /* 0 for new key; previous value of counter (after fatal error) */ - key.tx_counter[0] = cpu_to_le32(0); - key.tx_counter[1] = cpu_to_le32(0); - - ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key); -} - -static void ipw_send_wep_keys(struct ipw_priv *priv, int type) -{ - struct ipw_wep_key key; - int i; - - key.cmd_id = DINO_CMD_WEP_KEY; - key.seq_num = 0; - - /* Note: AES keys cannot be set for multiple times. - * Only set it at the first time. */ - for (i = 0; i < 4; i++) { - key.key_index = i | type; - if (!(priv->ieee->sec.flags & (1 << i))) { - key.key_size = 0; - continue; - } - - key.key_size = priv->ieee->sec.key_sizes[i]; - memcpy(key.key, priv->ieee->sec.keys[i], key.key_size); - - ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key); - } -} - -static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level) -{ - if (priv->ieee->host_encrypt) - return; - - switch (level) { - case SEC_LEVEL_3: - priv->sys_config.disable_unicast_decryption = 0; - priv->ieee->host_decrypt = 0; - break; - case SEC_LEVEL_2: - priv->sys_config.disable_unicast_decryption = 1; - priv->ieee->host_decrypt = 1; - break; - case SEC_LEVEL_1: - priv->sys_config.disable_unicast_decryption = 0; - priv->ieee->host_decrypt = 0; - break; - case SEC_LEVEL_0: - priv->sys_config.disable_unicast_decryption = 1; - break; - default: - break; - } -} - -static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level) -{ - if (priv->ieee->host_encrypt) - return; - - switch (level) { - case SEC_LEVEL_3: - priv->sys_config.disable_multicast_decryption = 0; - break; - case SEC_LEVEL_2: - priv->sys_config.disable_multicast_decryption = 1; - break; - case SEC_LEVEL_1: - priv->sys_config.disable_multicast_decryption = 0; - break; - case SEC_LEVEL_0: - priv->sys_config.disable_multicast_decryption = 1; - break; - default: - break; - } -} - -static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) -{ - switch (priv->ieee->sec.level) { - case SEC_LEVEL_3: - if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) - ipw_send_tgi_tx_key(priv, - DCT_FLAG_EXT_SECURITY_CCM, - priv->ieee->sec.active_key); - - if (!priv->ieee->host_mc_decrypt) - ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); - break; - case SEC_LEVEL_2: - if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) - ipw_send_tgi_tx_key(priv, - DCT_FLAG_EXT_SECURITY_TKIP, - priv->ieee->sec.active_key); - break; - case SEC_LEVEL_1: - ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); - ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level); - ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level); - break; - case SEC_LEVEL_0: - default: - break; - } -} - -static void ipw_adhoc_check(void *data) -{ - struct ipw_priv *priv = data; - - if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold && - !(priv->config & CFG_ADHOC_PERSIST)) { - IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | - IPW_DL_STATE | IPW_DL_ASSOC, - "Missed beacon: %d - disassociate\n", - priv->missed_adhoc_beacons); - ipw_remove_current_network(priv); - ipw_disassociate(priv); - return; - } - - queue_delayed_work(priv->workqueue, &priv->adhoc_check, - le16_to_cpu(priv->assoc_request.beacon_interval)); -} - -static void ipw_bg_adhoc_check(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, adhoc_check.work); - mutex_lock(&priv->mutex); - ipw_adhoc_check(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_debug_config(struct ipw_priv *priv) -{ - DECLARE_SSID_BUF(ssid); - IPW_DEBUG_INFO("Scan completed, no valid APs matched " - "[CFG 0x%08X]\n", priv->config); - if (priv->config & CFG_STATIC_CHANNEL) - IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel); - else - IPW_DEBUG_INFO("Channel unlocked.\n"); - if (priv->config & CFG_STATIC_ESSID) - IPW_DEBUG_INFO("ESSID locked to '%s'\n", - print_ssid(ssid, priv->essid, priv->essid_len)); - else - IPW_DEBUG_INFO("ESSID unlocked.\n"); - if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid); - else - IPW_DEBUG_INFO("BSSID unlocked.\n"); - if (priv->capability & CAP_PRIVACY_ON) - IPW_DEBUG_INFO("PRIVACY on\n"); - else - IPW_DEBUG_INFO("PRIVACY off\n"); - IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask); -} - -static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) -{ - /* TODO: Verify that this works... */ - struct ipw_fixed_rate fr = { - .tx_rates = priv->rates_mask - }; - u32 reg; - u16 mask = 0; - - /* Identify 'current FW band' and match it with the fixed - * Tx rates */ - - switch (priv->ieee->freq_band) { - case IEEE80211_52GHZ_BAND: /* A only */ - /* IEEE_A */ - if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { - /* Invalid fixed rate mask */ - IPW_DEBUG_WX - ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; - break; - } - - fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; - break; - - default: /* 2.4Ghz or Mixed */ - /* IEEE_B */ - if (mode == IEEE_B) { - if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { - /* Invalid fixed rate mask */ - IPW_DEBUG_WX - ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; - } - break; - } - - /* IEEE_G */ - if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | - IEEE80211_OFDM_RATES_MASK)) { - /* Invalid fixed rate mask */ - IPW_DEBUG_WX - ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; - break; - } - - if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) { - mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; - } - - if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) { - mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; - } - - if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) { - mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; - } - - fr.tx_rates |= mask; - break; - } - - reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE); - ipw_write_reg32(priv, reg, *(u32 *) & fr); -} - -static void ipw_abort_scan(struct ipw_priv *priv) -{ - int err; - - if (priv->status & STATUS_SCAN_ABORTING) { - IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); - return; - } - priv->status |= STATUS_SCAN_ABORTING; - - err = ipw_send_scan_abort(priv); - if (err) - IPW_DEBUG_HC("Request to abort scan failed.\n"); -} - -static void ipw_add_scan_channels(struct ipw_priv *priv, - struct ipw_scan_request_ext *scan, - int scan_type) -{ - int channel_index = 0; - const struct ieee80211_geo *geo; - int i; - - geo = ieee80211_get_geo(priv->ieee); - - if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { - int start = channel_index; - for (i = 0; i < geo->a_channels; i++) { - if ((priv->status & STATUS_ASSOCIATED) && - geo->a[i].channel == priv->channel) - continue; - channel_index++; - scan->channels_list[channel_index] = geo->a[i].channel; - ipw_set_scan_type(scan, channel_index, - geo->a[i]. - flags & IEEE80211_CH_PASSIVE_ONLY ? - IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : - scan_type); - } - - if (start != channel_index) { - scan->channels_list[start] = (u8) (IPW_A_MODE << 6) | - (channel_index - start); - channel_index++; - } - } - - if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { - int start = channel_index; - if (priv->config & CFG_SPEED_SCAN) { - int index; - u8 channels[IEEE80211_24GHZ_CHANNELS] = { - /* nop out the list */ - [0] = 0 - }; - - u8 channel; - while (channel_index < IPW_SCAN_CHANNELS) { - channel = - priv->speed_scan[priv->speed_scan_pos]; - if (channel == 0) { - priv->speed_scan_pos = 0; - channel = priv->speed_scan[0]; - } - if ((priv->status & STATUS_ASSOCIATED) && - channel == priv->channel) { - priv->speed_scan_pos++; - continue; - } - - /* If this channel has already been - * added in scan, break from loop - * and this will be the first channel - * in the next scan. - */ - if (channels[channel - 1] != 0) - break; - - channels[channel - 1] = 1; - priv->speed_scan_pos++; - channel_index++; - scan->channels_list[channel_index] = channel; - index = - ieee80211_channel_to_index(priv->ieee, channel); - ipw_set_scan_type(scan, channel_index, - geo->bg[index]. - flags & - IEEE80211_CH_PASSIVE_ONLY ? - IPW_SCAN_PASSIVE_FULL_DWELL_SCAN - : scan_type); - } - } else { - for (i = 0; i < geo->bg_channels; i++) { - if ((priv->status & STATUS_ASSOCIATED) && - geo->bg[i].channel == priv->channel) - continue; - channel_index++; - scan->channels_list[channel_index] = - geo->bg[i].channel; - ipw_set_scan_type(scan, channel_index, - geo->bg[i]. - flags & - IEEE80211_CH_PASSIVE_ONLY ? - IPW_SCAN_PASSIVE_FULL_DWELL_SCAN - : scan_type); - } - } - - if (start != channel_index) { - scan->channels_list[start] = (u8) (IPW_B_MODE << 6) | - (channel_index - start); - } - } -} - -static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) -{ - struct ipw_scan_request_ext scan; - int err = 0, scan_type; - - if (!(priv->status & STATUS_INIT) || - (priv->status & STATUS_EXIT_PENDING)) - return 0; - - mutex_lock(&priv->mutex); - - if (direct && (priv->direct_scan_ssid_len == 0)) { - IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n"); - priv->status &= ~STATUS_DIRECT_SCAN_PENDING; - goto done; - } - - if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n"); - priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : - STATUS_SCAN_PENDING; - goto done; - } - - if (!(priv->status & STATUS_SCAN_FORCED) && - priv->status & STATUS_SCAN_ABORTING) { - IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); - priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : - STATUS_SCAN_PENDING; - goto done; - } - - if (priv->status & STATUS_RF_KILL_MASK) { - IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n"); - priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : - STATUS_SCAN_PENDING; - goto done; - } - - memset(&scan, 0, sizeof(scan)); - scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); - - if (type == IW_SCAN_TYPE_PASSIVE) { - IPW_DEBUG_WX("use passive scanning\n"); - scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = - cpu_to_le16(120); - ipw_add_scan_channels(priv, &scan, scan_type); - goto send_request; - } - - /* Use active scan by default. */ - if (priv->config & CFG_SPEED_SCAN) - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(30); - else - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(20); - - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = - cpu_to_le16(20); - - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); - scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); - -#ifdef CONFIG_IPW2200_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - u8 channel; - u8 band = 0; - - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: - band = (u8) (IPW_A_MODE << 6) | 1; - channel = priv->channel; - break; - - case IEEE80211_24GHZ_BAND: - band = (u8) (IPW_B_MODE << 6) | 1; - channel = priv->channel; - break; - - default: - band = (u8) (IPW_B_MODE << 6) | 1; - channel = 9; - break; - } - - scan.channels_list[0] = band; - scan.channels_list[1] = channel; - ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); - - /* NOTE: The card will sit on this channel for this time - * period. Scan aborts are timing sensitive and frequently - * result in firmware restarts. As such, it is best to - * set a small dwell_time here and just keep re-issuing - * scans. Otherwise fast channel hopping will not actually - * hop channels. - * - * TODO: Move SPEED SCAN support to all modes and bands */ - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = - cpu_to_le16(2000); - } else { -#endif /* CONFIG_IPW2200_MONITOR */ - /* Honor direct scans first, otherwise if we are roaming make - * this a direct scan for the current network. Finally, - * ensure that every other scan is a fast channel hop scan */ - if (direct) { - err = ipw_send_ssid(priv, priv->direct_scan_ssid, - priv->direct_scan_ssid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command " - "failed\n"); - goto done; - } - - scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; - } else if ((priv->status & STATUS_ROAMING) - || (!(priv->status & STATUS_ASSOCIATED) - && (priv->config & CFG_STATIC_ESSID) - && (le32_to_cpu(scan.full_scan_index) % 2))) { - err = ipw_send_ssid(priv, priv->essid, priv->essid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command " - "failed.\n"); - goto done; - } - - scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; - } else - scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; - - ipw_add_scan_channels(priv, &scan, scan_type); -#ifdef CONFIG_IPW2200_MONITOR - } -#endif - -send_request: - err = ipw_send_scan_request_ext(priv, &scan); - if (err) { - IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); - goto done; - } - - priv->status |= STATUS_SCANNING; - if (direct) { - priv->status &= ~STATUS_DIRECT_SCAN_PENDING; - priv->direct_scan_ssid_len = 0; - } else - priv->status &= ~STATUS_SCAN_PENDING; - - queue_delayed_work(priv->workqueue, &priv->scan_check, - IPW_SCAN_CHECK_WATCHDOG); -done: - mutex_unlock(&priv->mutex); - return err; -} - -static void ipw_request_passive_scan(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, request_passive_scan.work); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0); -} - -static void ipw_request_scan(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, request_scan.work); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0); -} - -static void ipw_request_direct_scan(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, request_direct_scan.work); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1); -} - -static void ipw_bg_abort_scan(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, abort_scan); - mutex_lock(&priv->mutex); - ipw_abort_scan(priv); - mutex_unlock(&priv->mutex); -} - -static int ipw_wpa_enable(struct ipw_priv *priv, int value) -{ - /* This is called when wpa_supplicant loads and closes the driver - * interface. */ - priv->ieee->wpa_enabled = value; - return 0; -} - -static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) -{ - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { - .flags = SEC_AUTH_MODE, - }; - int ret = 0; - - if (value & IW_AUTH_ALG_SHARED_KEY) { - sec.auth_mode = WLAN_AUTH_SHARED_KEY; - ieee->open_wep = 0; - } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { - sec.auth_mode = WLAN_AUTH_OPEN; - ieee->open_wep = 1; - } else if (value & IW_AUTH_ALG_LEAP) { - sec.auth_mode = WLAN_AUTH_LEAP; - ieee->open_wep = 1; - } else - return -EINVAL; - - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - else - ret = -EOPNOTSUPP; - - return ret; -} - -static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, - int wpa_ie_len) -{ - /* make sure WPA is enabled */ - ipw_wpa_enable(priv, 1); -} - -static int ipw_set_rsn_capa(struct ipw_priv *priv, - char *capabilities, int length) -{ - IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); - - return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length, - capabilities); -} - -/* - * WE-18 support - */ - -/* SIOCSIWGENIE */ -static int ipw_wx_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - u8 *buf; - int err = 0; - - if (wrqu->data.length > MAX_WPA_IE_LEN || - (wrqu->data.length && extra == NULL)) - return -EINVAL; - - if (wrqu->data.length) { - buf = kmalloc(wrqu->data.length, GFP_KERNEL); - if (buf == NULL) { - err = -ENOMEM; - goto out; - } - - memcpy(buf, extra, wrqu->data.length); - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = wrqu->data.length; - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - } - - ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); - out: - return err; -} - -/* SIOCGIWGENIE */ -static int ipw_wx_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - int err = 0; - - if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { - wrqu->data.length = 0; - goto out; - } - - if (wrqu->data.length < ieee->wpa_ie_len) { - err = -E2BIG; - goto out; - } - - wrqu->data.length = ieee->wpa_ie_len; - memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); - - out: - return err; -} - -static int wext_cipher2level(int cipher) -{ - switch (cipher) { - case IW_AUTH_CIPHER_NONE: - return SEC_LEVEL_0; - case IW_AUTH_CIPHER_WEP40: - case IW_AUTH_CIPHER_WEP104: - return SEC_LEVEL_1; - case IW_AUTH_CIPHER_TKIP: - return SEC_LEVEL_2; - case IW_AUTH_CIPHER_CCMP: - return SEC_LEVEL_3; - default: - return -1; - } -} - -/* SIOCSIWAUTH */ -static int ipw_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - struct iw_param *param = &wrqu->param; - struct lib80211_crypt_data *crypt; - unsigned long flags; - int ret = 0; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - break; - case IW_AUTH_CIPHER_PAIRWISE: - ipw_set_hw_decrypt_unicast(priv, - wext_cipher2level(param->value)); - break; - case IW_AUTH_CIPHER_GROUP: - ipw_set_hw_decrypt_multicast(priv, - wext_cipher2level(param->value)); - break; - case IW_AUTH_KEY_MGMT: - /* - * ipw2200 does not use these parameters - */ - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) - break; - - flags = crypt->ops->get_flags(crypt->priv); - - if (param->value) - flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - else - flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - - crypt->ops->set_flags(flags, crypt->priv); - - break; - - case IW_AUTH_DROP_UNENCRYPTED:{ - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - struct ieee80211_security sec = { - .flags = SEC_ENABLED, - .enabled = param->value, - }; - priv->ieee->drop_unencrypted = param->value; - /* We only change SEC_LEVEL for open mode. Others - * are set by ipw_wpa_set_encryption. - */ - if (!param->value) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_0; - } else { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } - if (priv->ieee->set_security) - priv->ieee->set_security(priv->ieee->dev, &sec); - break; - } - - case IW_AUTH_80211_AUTH_ALG: - ret = ipw_wpa_set_auth_algs(priv, param->value); - break; - - case IW_AUTH_WPA_ENABLED: - ret = ipw_wpa_enable(priv, param->value); - ipw_disassociate(priv); - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ieee->ieee802_1x = param->value; - break; - - case IW_AUTH_PRIVACY_INVOKED: - ieee->privacy_invoked = param->value; - break; - - default: - return -EOPNOTSUPP; - } - return ret; -} - -/* SIOCGIWAUTH */ -static int ipw_wx_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - struct lib80211_crypt_data *crypt; - struct iw_param *param = &wrqu->param; - int ret = 0; - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * wpa_supplicant will control these internally - */ - ret = -EOPNOTSUPP; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; - if (!crypt || !crypt->ops->get_flags) - break; - - param->value = (crypt->ops->get_flags(crypt->priv) & - IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; - - break; - - case IW_AUTH_DROP_UNENCRYPTED: - param->value = ieee->drop_unencrypted; - break; - - case IW_AUTH_80211_AUTH_ALG: - param->value = ieee->sec.auth_mode; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = ieee->wpa_enabled; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - param->value = ieee->ieee802_1x; - break; - - case IW_AUTH_ROAMING_CONTROL: - case IW_AUTH_PRIVACY_INVOKED: - param->value = ieee->privacy_invoked; - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -/* SIOCSIWENCODEEXT */ -static int ipw_wx_set_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - - if (hwcrypto) { - if (ext->alg == IW_ENCODE_ALG_TKIP) { - /* IPW HW can't build TKIP MIC, - host decryption still needed */ - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - priv->ieee->host_mc_decrypt = 1; - else { - priv->ieee->host_encrypt = 0; - priv->ieee->host_encrypt_msdu = 1; - priv->ieee->host_decrypt = 1; - } - } else { - priv->ieee->host_encrypt = 0; - priv->ieee->host_encrypt_msdu = 0; - priv->ieee->host_decrypt = 0; - priv->ieee->host_mc_decrypt = 0; - } - } - - return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); -} - -/* SIOCGIWENCODEEXT */ -static int ipw_wx_get_encodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); -} - -/* SIOCSIWMLME */ -static int ipw_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - __le16 reason; - - reason = cpu_to_le16(mlme->reason_code); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* silently ignore */ - break; - - case IW_MLME_DISASSOC: - ipw_disassociate(priv); - break; - - default: - return -EOPNOTSUPP; - } - return 0; -} - -#ifdef CONFIG_IPW2200_QOS - -/* QoS */ -/* -* get the modulation type of the current network or -* the card current mode -*/ -static u8 ipw_qos_current_mode(struct ipw_priv * priv) -{ - u8 mode = 0; - - if (priv->status & STATUS_ASSOCIATED) { - unsigned long flags; - - spin_lock_irqsave(&priv->ieee->lock, flags); - mode = priv->assoc_network->mode; - spin_unlock_irqrestore(&priv->ieee->lock, flags); - } else { - mode = priv->ieee->mode; - } - IPW_DEBUG_QOS("QoS network/card mode %d \n", mode); - return mode; -} - -/* -* Handle management frame beacon and probe response -*/ -static int ipw_qos_handle_probe_response(struct ipw_priv *priv, - int active_network, - struct ieee80211_network *network) -{ - u32 size = sizeof(struct ieee80211_qos_parameters); - - if (network->capability & WLAN_CAPABILITY_IBSS) - network->qos_data.active = network->qos_data.supported; - - if (network->flags & NETWORK_HAS_QOS_MASK) { - if (active_network && - (network->flags & NETWORK_HAS_QOS_PARAMETERS)) - network->qos_data.active = network->qos_data.supported; - - if ((network->qos_data.active == 1) && (active_network == 1) && - (network->flags & NETWORK_HAS_QOS_PARAMETERS) && - (network->qos_data.old_param_count != - network->qos_data.param_count)) { - network->qos_data.old_param_count = - network->qos_data.param_count; - schedule_work(&priv->qos_activate); - IPW_DEBUG_QOS("QoS parameters change call " - "qos_activate\n"); - } - } else { - if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) - memcpy(&network->qos_data.parameters, - &def_parameters_CCK, size); - else - memcpy(&network->qos_data.parameters, - &def_parameters_OFDM, size); - - if ((network->qos_data.active == 1) && (active_network == 1)) { - IPW_DEBUG_QOS("QoS was disabled call qos_activate \n"); - schedule_work(&priv->qos_activate); - } - - network->qos_data.active = 0; - network->qos_data.supported = 0; - } - if ((priv->status & STATUS_ASSOCIATED) && - (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { - if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) - if (network->capability & WLAN_CAPABILITY_IBSS) - if ((network->ssid_len == - priv->assoc_network->ssid_len) && - !memcmp(network->ssid, - priv->assoc_network->ssid, - network->ssid_len)) { - queue_work(priv->workqueue, - &priv->merge_networks); - } - } - - return 0; -} - -/* -* This function set up the firmware to support QoS. It sends -* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO -*/ -static int ipw_qos_activate(struct ipw_priv *priv, - struct ieee80211_qos_data *qos_network_data) -{ - int err; - struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS]; - struct ieee80211_qos_parameters *active_one = NULL; - u32 size = sizeof(struct ieee80211_qos_parameters); - u32 burst_duration; - int i; - u8 type; - - type = ipw_qos_current_mode(priv); - - active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]); - memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size); - active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]); - memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size); - - if (qos_network_data == NULL) { - if (type == IEEE_B) { - IPW_DEBUG_QOS("QoS activate network mode %d\n", type); - active_one = &def_parameters_CCK; - } else - active_one = &def_parameters_OFDM; - - memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); - burst_duration = ipw_qos_get_burst_duration(priv); - for (i = 0; i < QOS_QUEUE_NUM; i++) - qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] = - cpu_to_le16(burst_duration); - } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - if (type == IEEE_B) { - IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", - type); - if (priv->qos_data.qos_enable == 0) - active_one = &def_parameters_CCK; - else - active_one = priv->qos_data.def_qos_parm_CCK; - } else { - if (priv->qos_data.qos_enable == 0) - active_one = &def_parameters_OFDM; - else - active_one = priv->qos_data.def_qos_parm_OFDM; - } - memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); - } else { - unsigned long flags; - int active; - - spin_lock_irqsave(&priv->ieee->lock, flags); - active_one = &(qos_network_data->parameters); - qos_network_data->old_param_count = - qos_network_data->param_count; - memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); - active = qos_network_data->supported; - spin_unlock_irqrestore(&priv->ieee->lock, flags); - - if (active == 0) { - burst_duration = ipw_qos_get_burst_duration(priv); - for (i = 0; i < QOS_QUEUE_NUM; i++) - qos_parameters[QOS_PARAM_SET_ACTIVE]. - tx_op_limit[i] = cpu_to_le16(burst_duration); - } - } - - IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); - err = ipw_send_qos_params_command(priv, - (struct ieee80211_qos_parameters *) - &(qos_parameters[0])); - if (err) - IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); - - return err; -} - -/* -* send IPW_CMD_WME_INFO to the firmware -*/ -static int ipw_qos_set_info_element(struct ipw_priv *priv) -{ - int ret = 0; - struct ieee80211_qos_information_element qos_info; - - if (priv == NULL) - return -1; - - qos_info.elementID = QOS_ELEMENT_ID; - qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2; - - qos_info.version = QOS_VERSION_1; - qos_info.ac_info = 0; - - memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN); - qos_info.qui_type = QOS_OUI_TYPE; - qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE; - - ret = ipw_send_qos_info_command(priv, &qos_info); - if (ret != 0) { - IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n"); - } - return ret; -} - -/* -* Set the QoS parameter with the association request structure -*/ -static int ipw_qos_association(struct ipw_priv *priv, - struct ieee80211_network *network) -{ - int err = 0; - struct ieee80211_qos_data *qos_data = NULL; - struct ieee80211_qos_data ibss_data = { - .supported = 1, - .active = 1, - }; - - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS)); - - qos_data = &ibss_data; - break; - - case IW_MODE_INFRA: - qos_data = &network->qos_data; - break; - - default: - BUG(); - break; - } - - err = ipw_qos_activate(priv, qos_data); - if (err) { - priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC; - return err; - } - - if (priv->qos_data.qos_enable && qos_data->supported) { - IPW_DEBUG_QOS("QoS will be enabled for this association\n"); - priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC; - return ipw_qos_set_info_element(priv); - } - - return 0; -} - -/* -* handling the beaconing responses. if we get different QoS setting -* off the network from the associated setting, adjust the QoS -* setting -*/ -static int ipw_qos_association_resp(struct ipw_priv *priv, - struct ieee80211_network *network) -{ - int ret = 0; - unsigned long flags; - u32 size = sizeof(struct ieee80211_qos_parameters); - int set_qos_param = 0; - - if ((priv == NULL) || (network == NULL) || - (priv->assoc_network == NULL)) - return ret; - - if (!(priv->status & STATUS_ASSOCIATED)) - return ret; - - if ((priv->ieee->iw_mode != IW_MODE_INFRA)) - return ret; - - spin_lock_irqsave(&priv->ieee->lock, flags); - if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { - memcpy(&priv->assoc_network->qos_data, &network->qos_data, - sizeof(struct ieee80211_qos_data)); - priv->assoc_network->qos_data.active = 1; - if ((network->qos_data.old_param_count != - network->qos_data.param_count)) { - set_qos_param = 1; - network->qos_data.old_param_count = - network->qos_data.param_count; - } - - } else { - if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) - memcpy(&priv->assoc_network->qos_data.parameters, - &def_parameters_CCK, size); - else - memcpy(&priv->assoc_network->qos_data.parameters, - &def_parameters_OFDM, size); - priv->assoc_network->qos_data.active = 0; - priv->assoc_network->qos_data.supported = 0; - set_qos_param = 1; - } - - spin_unlock_irqrestore(&priv->ieee->lock, flags); - - if (set_qos_param == 1) - schedule_work(&priv->qos_activate); - - return ret; -} - -static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) -{ - u32 ret = 0; - - if ((priv == NULL)) - return 0; - - if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) - ret = priv->qos_data.burst_duration_CCK; - else - ret = priv->qos_data.burst_duration_OFDM; - - return ret; -} - -/* -* Initialize the setting of QoS global -*/ -static void ipw_qos_init(struct ipw_priv *priv, int enable, - int burst_enable, u32 burst_duration_CCK, - u32 burst_duration_OFDM) -{ - priv->qos_data.qos_enable = enable; - - if (priv->qos_data.qos_enable) { - priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK; - priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM; - IPW_DEBUG_QOS("QoS is enabled\n"); - } else { - priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK; - priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM; - IPW_DEBUG_QOS("QoS is not enabled\n"); - } - - priv->qos_data.burst_enable = burst_enable; - - if (burst_enable) { - priv->qos_data.burst_duration_CCK = burst_duration_CCK; - priv->qos_data.burst_duration_OFDM = burst_duration_OFDM; - } else { - priv->qos_data.burst_duration_CCK = 0; - priv->qos_data.burst_duration_OFDM = 0; - } -} - -/* -* map the packet priority to the right TX Queue -*/ -static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) -{ - if (priority > 7 || !priv->qos_data.qos_enable) - priority = 0; - - return from_priority_to_tx_queue[priority] - 1; -} - -static int ipw_is_qos_active(struct net_device *dev, - struct sk_buff *skb) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_qos_data *qos_data = NULL; - int active, supported; - u8 *daddr = skb->data + ETH_ALEN; - int unicast = !is_multicast_ether_addr(daddr); - - if (!(priv->status & STATUS_ASSOCIATED)) - return 0; - - qos_data = &priv->assoc_network->qos_data; - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - if (unicast == 0) - qos_data->active = 0; - else - qos_data->active = qos_data->supported; - } - active = qos_data->active; - supported = qos_data->supported; - IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " - "unicast %d\n", - priv->qos_data.qos_enable, active, supported, unicast); - if (active && priv->qos_data.qos_enable) - return 1; - - return 0; - -} -/* -* add QoS parameter to the TX command -*/ -static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, - u16 priority, - struct tfd_data *tfd) -{ - int tx_queue_id = 0; - - - tx_queue_id = from_priority_to_tx_queue[priority] - 1; - tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; - - if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) { - tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; - tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK); - } - return 0; -} - -/* -* background support to run QoS activate functionality -*/ -static void ipw_bg_qos_activate(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, qos_activate); - - if (priv == NULL) - return; - - mutex_lock(&priv->mutex); - - if (priv->status & STATUS_ASSOCIATED) - ipw_qos_activate(priv, &(priv->assoc_network->qos_data)); - - mutex_unlock(&priv->mutex); -} - -static int ipw_handle_probe_response(struct net_device *dev, - struct ieee80211_probe_response *resp, - struct ieee80211_network *network) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int active_network = ((priv->status & STATUS_ASSOCIATED) && - (network == priv->assoc_network)); - - ipw_qos_handle_probe_response(priv, active_network, network); - - return 0; -} - -static int ipw_handle_beacon(struct net_device *dev, - struct ieee80211_beacon *resp, - struct ieee80211_network *network) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int active_network = ((priv->status & STATUS_ASSOCIATED) && - (network == priv->assoc_network)); - - ipw_qos_handle_probe_response(priv, active_network, network); - - return 0; -} - -static int ipw_handle_assoc_response(struct net_device *dev, - struct ieee80211_assoc_response *resp, - struct ieee80211_network *network) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - ipw_qos_association_resp(priv, network); - return 0; -} - -static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters - *qos_param) -{ - return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, - sizeof(*qos_param) * 3, qos_param); -} - -static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element - *qos_param) -{ - return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param), - qos_param); -} - -#endif /* CONFIG_IPW2200_QOS */ - -static int ipw_associate_network(struct ipw_priv *priv, - struct ieee80211_network *network, - struct ipw_supported_rates *rates, int roaming) -{ - int err; - DECLARE_SSID_BUF(ssid); - - if (priv->config & CFG_FIXED_RATE) - ipw_set_fixed_rate(priv, network->mode); - - if (!(priv->config & CFG_STATIC_ESSID)) { - priv->essid_len = min(network->ssid_len, - (u8) IW_ESSID_MAX_SIZE); - memcpy(priv->essid, network->ssid, priv->essid_len); - } - - network->last_associate = jiffies; - - memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); - priv->assoc_request.channel = network->channel; - priv->assoc_request.auth_key = 0; - - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) { - priv->assoc_request.auth_type = AUTH_SHARED_KEY; - priv->assoc_request.auth_key = priv->ieee->sec.active_key; - - if (priv->ieee->sec.level == SEC_LEVEL_1) - ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); - - } else if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)) - priv->assoc_request.auth_type = AUTH_LEAP; - else - priv->assoc_request.auth_type = AUTH_OPEN; - - if (priv->ieee->wpa_ie_len) { - priv->assoc_request.policy_support = cpu_to_le16(0x02); /* RSN active */ - ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, - priv->ieee->wpa_ie_len); - } - - /* - * It is valid for our ieee device to support multiple modes, but - * when it comes to associating to a given network we have to choose - * just one mode. - */ - if (network->mode & priv->ieee->mode & IEEE_A) - priv->assoc_request.ieee_mode = IPW_A_MODE; - else if (network->mode & priv->ieee->mode & IEEE_G) - priv->assoc_request.ieee_mode = IPW_G_MODE; - else if (network->mode & priv->ieee->mode & IEEE_B) - priv->assoc_request.ieee_mode = IPW_B_MODE; - - priv->assoc_request.capability = cpu_to_le16(network->capability); - if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - && !(priv->config & CFG_PREAMBLE_LONG)) { - priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE; - } else { - priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE; - - /* Clear the short preamble if we won't be supporting it */ - priv->assoc_request.capability &= - ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - } - - /* Clear capability bits that aren't used in Ad Hoc */ - if (priv->ieee->iw_mode == IW_MODE_ADHOC) - priv->assoc_request.capability &= - ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); - - IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " - "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", - roaming ? "Rea" : "A", - print_ssid(ssid, priv->essid, priv->essid_len), - network->channel, - ipw_modes[priv->assoc_request.ieee_mode], - rates->num_rates, - (priv->assoc_request.preamble_length == - DCT_FLAG_LONG_PREAMBLE) ? "long" : "short", - network->capability & - WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long", - priv->capability & CAP_PRIVACY_ON ? "on " : "off", - priv->capability & CAP_PRIVACY_ON ? - (priv->capability & CAP_SHARED_KEY ? "(shared)" : - "(open)") : "", - priv->capability & CAP_PRIVACY_ON ? " key=" : "", - priv->capability & CAP_PRIVACY_ON ? - '1' + priv->ieee->sec.active_key : '.', - priv->capability & CAP_PRIVACY_ON ? '.' : ' '); - - priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval); - if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) { - priv->assoc_request.assoc_type = HC_IBSS_START; - priv->assoc_request.assoc_tsf_msw = 0; - priv->assoc_request.assoc_tsf_lsw = 0; - } else { - if (unlikely(roaming)) - priv->assoc_request.assoc_type = HC_REASSOCIATE; - else - priv->assoc_request.assoc_type = HC_ASSOCIATE; - priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]); - priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]); - } - - memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN); - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); - priv->assoc_request.atim_window = cpu_to_le16(network->atim_window); - } else { - memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN); - priv->assoc_request.atim_window = 0; - } - - priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval); - - err = ipw_send_ssid(priv, priv->essid, priv->essid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); - return err; - } - - rates->ieee_mode = priv->assoc_request.ieee_mode; - rates->purpose = IPW_RATE_CONNECT; - ipw_send_supported_rates(priv, rates); - - if (priv->assoc_request.ieee_mode == IPW_G_MODE) - priv->sys_config.dot11g_auto_detection = 1; - else - priv->sys_config.dot11g_auto_detection = 0; - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) - priv->sys_config.answer_broadcast_ssid_probe = 1; - else - priv->sys_config.answer_broadcast_ssid_probe = 0; - - err = ipw_send_system_config(priv); - if (err) { - IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); - return err; - } - - IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); - err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM); - if (err) { - IPW_DEBUG_HC("Attempt to send associate command failed.\n"); - return err; - } - - /* - * If preemption is enabled, it is possible for the association - * to complete before we return from ipw_send_associate. Therefore - * we have to be sure and update our priviate data first. - */ - priv->channel = network->channel; - memcpy(priv->bssid, network->bssid, ETH_ALEN); - priv->status |= STATUS_ASSOCIATING; - priv->status &= ~STATUS_SECURITY_UPDATED; - - priv->assoc_network = network; - -#ifdef CONFIG_IPW2200_QOS - ipw_qos_association(priv, network); -#endif - - err = ipw_send_associate(priv, &priv->assoc_request); - if (err) { - IPW_DEBUG_HC("Attempt to send associate command failed.\n"); - return err; - } - - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", - print_ssid(ssid, priv->essid, priv->essid_len), - priv->bssid); - - return 0; -} - -static void ipw_roam(void *data) -{ - struct ipw_priv *priv = data; - struct ieee80211_network *network = NULL; - struct ipw_network_match match = { - .network = priv->assoc_network - }; - - /* The roaming process is as follows: - * - * 1. Missed beacon threshold triggers the roaming process by - * setting the status ROAM bit and requesting a scan. - * 2. When the scan completes, it schedules the ROAM work - * 3. The ROAM work looks at all of the known networks for one that - * is a better network than the currently associated. If none - * found, the ROAM process is over (ROAM bit cleared) - * 4. If a better network is found, a disassociation request is - * sent. - * 5. When the disassociation completes, the roam work is again - * scheduled. The second time through, the driver is no longer - * associated, and the newly selected network is sent an - * association request. - * 6. At this point ,the roaming process is complete and the ROAM - * status bit is cleared. - */ - - /* If we are no longer associated, and the roaming bit is no longer - * set, then we are not actively roaming, so just return */ - if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING))) - return; - - if (priv->status & STATUS_ASSOCIATED) { - /* First pass through ROAM process -- look for a better - * network */ - unsigned long flags; - u8 rssi = priv->assoc_network->stats.rssi; - priv->assoc_network->stats.rssi = -128; - spin_lock_irqsave(&priv->ieee->lock, flags); - list_for_each_entry(network, &priv->ieee->network_list, list) { - if (network != priv->assoc_network) - ipw_best_network(priv, &match, network, 1); - } - spin_unlock_irqrestore(&priv->ieee->lock, flags); - priv->assoc_network->stats.rssi = rssi; - - if (match.network == priv->assoc_network) { - IPW_DEBUG_ASSOC("No better APs in this network to " - "roam to.\n"); - priv->status &= ~STATUS_ROAMING; - ipw_debug_config(priv); - return; - } - - ipw_send_disassociate(priv, 1); - priv->assoc_network = match.network; - - return; - } - - /* Second pass through ROAM process -- request association */ - ipw_compatible_rates(priv, priv->assoc_network, &match.rates); - ipw_associate_network(priv, priv->assoc_network, &match.rates, 1); - priv->status &= ~STATUS_ROAMING; -} - -static void ipw_bg_roam(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, roam); - mutex_lock(&priv->mutex); - ipw_roam(priv); - mutex_unlock(&priv->mutex); -} - -static int ipw_associate(void *data) -{ - struct ipw_priv *priv = data; - - struct ieee80211_network *network = NULL; - struct ipw_network_match match = { - .network = NULL - }; - struct ipw_supported_rates *rates; - struct list_head *element; - unsigned long flags; - DECLARE_SSID_BUF(ssid); - - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n"); - return 0; - } - - if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_ASSOC("Not attempting association (already in " - "progress)\n"); - return 0; - } - - if (priv->status & STATUS_DISASSOCIATING) { - IPW_DEBUG_ASSOC("Not attempting association (in " - "disassociating)\n "); - queue_work(priv->workqueue, &priv->associate); - return 0; - } - - if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { - IPW_DEBUG_ASSOC("Not attempting association (scanning or not " - "initialized)\n"); - return 0; - } - - if (!(priv->config & CFG_ASSOCIATE) && - !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) { - IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); - return 0; - } - - /* Protect our use of the network_list */ - spin_lock_irqsave(&priv->ieee->lock, flags); - list_for_each_entry(network, &priv->ieee->network_list, list) - ipw_best_network(priv, &match, network, 0); - - network = match.network; - rates = &match.rates; - - if (network == NULL && - priv->ieee->iw_mode == IW_MODE_ADHOC && - priv->config & CFG_ADHOC_CREATE && - priv->config & CFG_STATIC_ESSID && - priv->config & CFG_STATIC_CHANNEL) { - /* Use oldest network if the free list is empty */ - if (list_empty(&priv->ieee->network_free_list)) { - struct ieee80211_network *oldest = NULL; - struct ieee80211_network *target; - - list_for_each_entry(target, &priv->ieee->network_list, list) { - if ((oldest == NULL) || - (target->last_scanned < oldest->last_scanned)) - oldest = target; - } - - /* If there are no more slots, expire the oldest */ - list_del(&oldest->list); - target = oldest; - IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " - "network list.\n", - print_ssid(ssid, target->ssid, - target->ssid_len), - target->bssid); - list_add_tail(&target->list, - &priv->ieee->network_free_list); - } - - element = priv->ieee->network_free_list.next; - network = list_entry(element, struct ieee80211_network, list); - ipw_adhoc_create(priv, network); - rates = &priv->rates; - list_del(element); - list_add_tail(&network->list, &priv->ieee->network_list); - } - spin_unlock_irqrestore(&priv->ieee->lock, flags); - - /* If we reached the end of the list, then we don't have any valid - * matching APs */ - if (!network) { - ipw_debug_config(priv); - - if (!(priv->status & STATUS_SCANNING)) { - if (!(priv->config & CFG_SPEED_SCAN)) - queue_delayed_work(priv->workqueue, - &priv->request_scan, - SCAN_INTERVAL); - else - queue_delayed_work(priv->workqueue, - &priv->request_scan, 0); - } - - return 0; - } - - ipw_associate_network(priv, network, rates, 0); - - return 1; -} - -static void ipw_bg_associate(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, associate); - mutex_lock(&priv->mutex); - ipw_associate(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_control); - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return; - - fc &= ~IEEE80211_FCTL_PROTECTED; - hdr->frame_control = cpu_to_le16(fc); - switch (priv->ieee->sec.level) { - case SEC_LEVEL_3: - /* Remove CCMP HDR */ - memmove(skb->data + IEEE80211_3ADDR_LEN, - skb->data + IEEE80211_3ADDR_LEN + 8, - skb->len - IEEE80211_3ADDR_LEN - 8); - skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */ - break; - case SEC_LEVEL_2: - break; - case SEC_LEVEL_1: - /* Remove IV */ - memmove(skb->data + IEEE80211_3ADDR_LEN, - skb->data + IEEE80211_3ADDR_LEN + 4, - skb->len - IEEE80211_3ADDR_LEN - 4); - skb_trim(skb, skb->len - 8); /* IV + ICV */ - break; - case SEC_LEVEL_0: - break; - default: - printk(KERN_ERR "Unknow security level %d\n", - priv->ieee->sec.level); - break; - } -} - -static void ipw_handle_data_packet(struct ipw_priv *priv, - struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) -{ - struct ieee80211_hdr_4addr *hdr; - struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; - - /* We received data from the HW, so stop the watchdog */ - priv->net_dev->trans_start = jiffies; - - /* We only process data packets if the - * interface is open */ - if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > - skb_tailroom(rxb->skb))) { - priv->ieee->stats.rx_errors++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); - return; - } else if (unlikely(!netif_running(priv->net_dev))) { - priv->ieee->stats.rx_dropped++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); - return; - } - - /* Advance skb->data to the start of the actual payload */ - skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data)); - - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length)); - - IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - - /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ - hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data; - if (priv->ieee->iw_mode != IW_MODE_MONITOR && - (is_multicast_ether_addr(hdr->addr1) ? - !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt)) - ipw_rebuild_decrypted_skb(priv, rxb->skb); - - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) - priv->ieee->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ - rxb->skb = NULL; - __ipw_led_activity_on(priv); - } -} - -#ifdef CONFIG_IPW2200_RADIOTAP -static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, - struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) -{ - struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; - struct ipw_rx_frame *frame = &pkt->u.frame; - - /* initial pull of some data */ - u16 received_channel = frame->received_channel; - u8 antennaAndPhy = frame->antennaAndPhy; - s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */ - u16 pktrate = frame->rate; - - /* Magic struct that slots into the radiotap header -- no reason - * to build this manually element by element, we can write it much - * more efficiently than we can parse it. ORDER MATTERS HERE */ - struct ipw_rt_hdr *ipw_rt; - - short len = le16_to_cpu(pkt->u.frame.length); - - /* We received data from the HW, so stop the watchdog */ - priv->net_dev->trans_start = jiffies; - - /* We only process data packets if the - * interface is open */ - if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > - skb_tailroom(rxb->skb))) { - priv->ieee->stats.rx_errors++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); - return; - } else if (unlikely(!netif_running(priv->net_dev))) { - priv->ieee->stats.rx_dropped++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); - return; - } - - /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use - * that now */ - if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { - /* FIXME: Should alloc bigger skb instead */ - priv->ieee->stats.rx_dropped++; - priv->wstats.discard.misc++; - IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); - return; - } - - /* copy the frame itself */ - memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), - rxb->skb->data + IPW_RX_FRAME_SIZE, len); - - /* Zero the radiotap static buffer ... We only need to zero the bytes NOT - * part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before merging - * patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - - ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; - - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total header+data */ - - /* Big bitfield of all the fields we provide in radiotap */ - ipw_rt->rt_hdr.it_present = cpu_to_le32( - (1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)); - - /* Zero the flags, we'll add to them as we go */ - ipw_rt->rt_flags = 0; - ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 | - frame->parent_tsf[2] << 16 | - frame->parent_tsf[1] << 8 | - frame->parent_tsf[0]); - - /* Convert signal to DBM */ - ipw_rt->rt_dbmsignal = antsignal; - ipw_rt->rt_dbmnoise = frame->noise; - - /* Convert the channel data and set the flags */ - ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); - if (received_channel > 14) { /* 802.11a */ - ipw_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); - } else if (antennaAndPhy & 32) { /* 802.11b */ - ipw_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); - } else { /* 802.11g */ - ipw_rt->rt_chbitmask = - cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); - } - - /* set the rate in multiples of 500k/s */ - switch (pktrate) { - case IPW_TX_RATE_1MB: - ipw_rt->rt_rate = 2; - break; - case IPW_TX_RATE_2MB: - ipw_rt->rt_rate = 4; - break; - case IPW_TX_RATE_5MB: - ipw_rt->rt_rate = 10; - break; - case IPW_TX_RATE_6MB: - ipw_rt->rt_rate = 12; - break; - case IPW_TX_RATE_9MB: - ipw_rt->rt_rate = 18; - break; - case IPW_TX_RATE_11MB: - ipw_rt->rt_rate = 22; - break; - case IPW_TX_RATE_12MB: - ipw_rt->rt_rate = 24; - break; - case IPW_TX_RATE_18MB: - ipw_rt->rt_rate = 36; - break; - case IPW_TX_RATE_24MB: - ipw_rt->rt_rate = 48; - break; - case IPW_TX_RATE_36MB: - ipw_rt->rt_rate = 72; - break; - case IPW_TX_RATE_48MB: - ipw_rt->rt_rate = 96; - break; - case IPW_TX_RATE_54MB: - ipw_rt->rt_rate = 108; - break; - default: - ipw_rt->rt_rate = 0; - break; - } - - /* antenna number */ - ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */ - - /* set the preamble flag if we have it */ - if ((antennaAndPhy & 64)) - ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr)); - - IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) - priv->ieee->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ - rxb->skb = NULL; - /* no LED during capture */ - } -} -#endif - -#ifdef CONFIG_IPW2200_PROMISCUOUS -#define ieee80211_is_probe_response(fc) \ - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \ - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP ) - -#define ieee80211_is_management(fc) \ - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - -#define ieee80211_is_control(fc) \ - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) - -#define ieee80211_is_data(fc) \ - ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) - -#define ieee80211_is_assoc_request(fc) \ - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ) - -#define ieee80211_is_reassoc_request(fc) \ - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - -static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, - struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) -{ - struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; - struct ipw_rx_frame *frame = &pkt->u.frame; - struct ipw_rt_hdr *ipw_rt; - - /* First cache any information we need before we overwrite - * the information provided in the skb from the hardware */ - struct ieee80211_hdr *hdr; - u16 channel = frame->received_channel; - u8 phy_flags = frame->antennaAndPhy; - s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; - s8 noise = frame->noise; - u8 rate = frame->rate; - short len = le16_to_cpu(pkt->u.frame.length); - struct sk_buff *skb; - int hdr_only = 0; - u16 filter = priv->prom_priv->filter; - - /* If the filter is set to not include Rx frames then return */ - if (filter & IPW_PROM_NO_RX) - return; - - /* We received data from the HW, so stop the watchdog */ - priv->prom_net_dev->trans_start = jiffies; - - if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { - priv->prom_priv->ieee->stats.rx_errors++; - IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); - return; - } - - /* We only process data packets if the interface is open */ - if (unlikely(!netif_running(priv->prom_net_dev))) { - priv->prom_priv->ieee->stats.rx_dropped++; - IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); - return; - } - - /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use - * that now */ - if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { - /* FIXME: Should alloc bigger skb instead */ - priv->prom_priv->ieee->stats.rx_dropped++; - IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); - return; - } - - hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { - if (filter & IPW_PROM_NO_MGMT) - return; - if (filter & IPW_PROM_MGMT_HEADER_ONLY) - hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { - if (filter & IPW_PROM_NO_CTL) - return; - if (filter & IPW_PROM_CTL_HEADER_ONLY) - hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { - if (filter & IPW_PROM_NO_DATA) - return; - if (filter & IPW_PROM_DATA_HEADER_ONLY) - hdr_only = 1; - } - - /* Copy the SKB since this is for the promiscuous side */ - skb = skb_copy(rxb->skb, GFP_ATOMIC); - if (skb == NULL) { - IPW_ERROR("skb_clone failed for promiscuous copy.\n"); - return; - } - - /* copy the frame data to write after where the radiotap header goes */ - ipw_rt = (void *)skb->data; - - if (hdr_only) - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - - memcpy(ipw_rt->payload, hdr, len); - - /* Zero the radiotap static buffer ... We only need to zero the bytes - * NOT part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before - * merging patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */ - - /* Set the size of the skb to the size of the frame */ - skb_put(skb, sizeof(*ipw_rt) + len); - - /* Big bitfield of all the fields we provide in radiotap */ - ipw_rt->rt_hdr.it_present = cpu_to_le32( - (1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)); - - /* Zero the flags, we'll add to them as we go */ - ipw_rt->rt_flags = 0; - ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 | - frame->parent_tsf[2] << 16 | - frame->parent_tsf[1] << 8 | - frame->parent_tsf[0]); - - /* Convert to DBM */ - ipw_rt->rt_dbmsignal = signal; - ipw_rt->rt_dbmnoise = noise; - - /* Convert the channel data and set the flags */ - ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel)); - if (channel > 14) { /* 802.11a */ - ipw_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); - } else if (phy_flags & (1 << 5)) { /* 802.11b */ - ipw_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); - } else { /* 802.11g */ - ipw_rt->rt_chbitmask = - cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); - } - - /* set the rate in multiples of 500k/s */ - switch (rate) { - case IPW_TX_RATE_1MB: - ipw_rt->rt_rate = 2; - break; - case IPW_TX_RATE_2MB: - ipw_rt->rt_rate = 4; - break; - case IPW_TX_RATE_5MB: - ipw_rt->rt_rate = 10; - break; - case IPW_TX_RATE_6MB: - ipw_rt->rt_rate = 12; - break; - case IPW_TX_RATE_9MB: - ipw_rt->rt_rate = 18; - break; - case IPW_TX_RATE_11MB: - ipw_rt->rt_rate = 22; - break; - case IPW_TX_RATE_12MB: - ipw_rt->rt_rate = 24; - break; - case IPW_TX_RATE_18MB: - ipw_rt->rt_rate = 36; - break; - case IPW_TX_RATE_24MB: - ipw_rt->rt_rate = 48; - break; - case IPW_TX_RATE_36MB: - ipw_rt->rt_rate = 72; - break; - case IPW_TX_RATE_48MB: - ipw_rt->rt_rate = 96; - break; - case IPW_TX_RATE_54MB: - ipw_rt->rt_rate = 108; - break; - default: - ipw_rt->rt_rate = 0; - break; - } - - /* antenna number */ - ipw_rt->rt_antenna = (phy_flags & 3); - - /* set the preamble flag if we have it */ - if (phy_flags & (1 << 6)) - ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len); - - if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) { - priv->prom_priv->ieee->stats.rx_errors++; - dev_kfree_skb_any(skb); - } -} -#endif - -static int is_network_packet(struct ipw_priv *priv, - struct ieee80211_hdr_4addr *header) -{ - /* Filter incoming packets to determine if they are targetted toward - * this network, discarding packets coming from ourselves */ - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ - /* packets from our adapter are dropped (echo) */ - if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) - return 0; - - /* {broad,multi}cast packets to our BSSID go through */ - if (is_multicast_ether_addr(header->addr1)) - return !memcmp(header->addr3, priv->bssid, ETH_ALEN); - - /* packets to our adapter go through */ - return !memcmp(header->addr1, priv->net_dev->dev_addr, - ETH_ALEN); - - case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */ - /* packets from our adapter are dropped (echo) */ - if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN)) - return 0; - - /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(header->addr1)) - return !memcmp(header->addr2, priv->bssid, ETH_ALEN); - - /* packets to our adapter go through */ - return !memcmp(header->addr1, priv->net_dev->dev_addr, - ETH_ALEN); - } - - return 1; -} - -#define IPW_PACKET_RETRY_TIME HZ - -static int is_duplicate_packet(struct ipw_priv *priv, - struct ieee80211_hdr_4addr *header) -{ - u16 sc = le16_to_cpu(header->seq_ctl); - u16 seq = WLAN_GET_SEQ_SEQ(sc); - u16 frag = WLAN_GET_SEQ_FRAG(sc); - u16 *last_seq, *last_frag; - unsigned long *last_time; - - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - { - struct list_head *p; - struct ipw_ibss_seq *entry = NULL; - u8 *mac = header->addr2; - int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE; - - __list_for_each(p, &priv->ibss_mac_hash[index]) { - entry = - list_entry(p, struct ipw_ibss_seq, list); - if (!memcmp(entry->mac, mac, ETH_ALEN)) - break; - } - if (p == &priv->ibss_mac_hash[index]) { - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - IPW_ERROR - ("Cannot malloc new mac entry\n"); - return 0; - } - memcpy(entry->mac, mac, ETH_ALEN); - entry->seq_num = seq; - entry->frag_num = frag; - entry->packet_time = jiffies; - list_add(&entry->list, - &priv->ibss_mac_hash[index]); - return 0; - } - last_seq = &entry->seq_num; - last_frag = &entry->frag_num; - last_time = &entry->packet_time; - break; - } - case IW_MODE_INFRA: - last_seq = &priv->last_seq_num; - last_frag = &priv->last_frag_num; - last_time = &priv->last_packet_time; - break; - default: - return 0; - } - if ((*last_seq == seq) && - time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) { - if (*last_frag == frag) - goto drop; - if (*last_frag + 1 != frag) - /* out-of-order fragment */ - goto drop; - } else - *last_seq = seq; - - *last_frag = frag; - *last_time = jiffies; - return 0; - - drop: - /* Comment this line now since we observed the card receives - * duplicate packets but the FCTL_RETRY bit is not set in the - * IBSS mode with fragmentation enabled. - BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */ - return 1; -} - -static void ipw_handle_mgmt_packet(struct ipw_priv *priv, - struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) -{ - struct sk_buff *skb = rxb->skb; - struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data; - struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *) - (skb->data + IPW_RX_FRAME_SIZE); - - ieee80211_rx_mgt(priv->ieee, header, stats); - - if (priv->ieee->iw_mode == IW_MODE_ADHOC && - ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == - IEEE80211_STYPE_PROBE_RESP) || - (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == - IEEE80211_STYPE_BEACON))) { - if (!memcmp(header->addr3, priv->bssid, ETH_ALEN)) - ipw_add_station(priv, header->addr2); - } - - if (priv->config & CFG_NET_STATS) { - IPW_DEBUG_HC("sending stat packet\n"); - - /* Set the size of the skb to the size of the full - * ipw header and 802.11 frame */ - skb_put(skb, le16_to_cpu(pkt->u.frame.length) + - IPW_RX_FRAME_SIZE); - - /* Advance past the ipw packet header to the 802.11 frame */ - skb_pull(skb, IPW_RX_FRAME_SIZE); - - /* Push the ieee80211_rx_stats before the 802.11 frame */ - memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats)); - - skb->dev = priv->ieee->dev; - - /* Point raw at the ieee80211_stats */ - skb_reset_mac_header(skb); - - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = __constant_htons(ETH_P_80211_STATS); - memset(skb->cb, 0, sizeof(rxb->skb->cb)); - netif_rx(skb); - rxb->skb = NULL; - } -} - -/* - * Main entry function for recieving a packet with 80211 headers. This - * should be called when ever the FW has notified us that there is a new - * skb in the recieve queue. - */ -static void ipw_rx(struct ipw_priv *priv) -{ - struct ipw_rx_mem_buffer *rxb; - struct ipw_rx_packet *pkt; - struct ieee80211_hdr_4addr *header; - u32 r, w, i; - u8 network_packet; - u8 fill_rx = 0; - - r = ipw_read32(priv, IPW_RX_READ_INDEX); - w = ipw_read32(priv, IPW_RX_WRITE_INDEX); - i = priv->rxq->read; - - if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2)) - fill_rx = 1; - - while (i != r) { - rxb = priv->rxq->queue[i]; - if (unlikely(rxb == NULL)) { - printk(KERN_CRIT "Queue not allocated!\n"); - break; - } - priv->rxq->queue[i] = NULL; - - pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, - IPW_RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); - - pkt = (struct ipw_rx_packet *)rxb->skb->data; - IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n", - pkt->header.message_type, - pkt->header.rx_seq_num, pkt->header.control_bits); - - switch (pkt->header.message_type) { - case RX_FRAME_TYPE: /* 802.11 frame */ { - struct ieee80211_rx_stats stats = { - .rssi = pkt->u.frame.rssi_dbm - - IPW_RSSI_TO_DBM, - .signal = - le16_to_cpu(pkt->u.frame.rssi_dbm) - - IPW_RSSI_TO_DBM + 0x100, - .noise = - le16_to_cpu(pkt->u.frame.noise), - .rate = pkt->u.frame.rate, - .mac_time = jiffies, - .received_channel = - pkt->u.frame.received_channel, - .freq = - (pkt->u.frame. - control & (1 << 0)) ? - IEEE80211_24GHZ_BAND : - IEEE80211_52GHZ_BAND, - .len = le16_to_cpu(pkt->u.frame.length), - }; - - if (stats.rssi != 0) - stats.mask |= IEEE80211_STATMASK_RSSI; - if (stats.signal != 0) - stats.mask |= IEEE80211_STATMASK_SIGNAL; - if (stats.noise != 0) - stats.mask |= IEEE80211_STATMASK_NOISE; - if (stats.rate != 0) - stats.mask |= IEEE80211_STATMASK_RATE; - - priv->rx_packets++; - -#ifdef CONFIG_IPW2200_PROMISCUOUS - if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) - ipw_handle_promiscuous_rx(priv, rxb, &stats); -#endif - -#ifdef CONFIG_IPW2200_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { -#ifdef CONFIG_IPW2200_RADIOTAP - - ipw_handle_data_packet_monitor(priv, - rxb, - &stats); -#else - ipw_handle_data_packet(priv, rxb, - &stats); -#endif - break; - } -#endif - - header = - (struct ieee80211_hdr_4addr *)(rxb->skb-> - data + - IPW_RX_FRAME_SIZE); - /* TODO: Check Ad-Hoc dest/source and make sure - * that we are actually parsing these packets - * correctly -- we should probably use the - * frame control of the packet and disregard - * the current iw_mode */ - - network_packet = - is_network_packet(priv, header); - if (network_packet && priv->assoc_network) { - priv->assoc_network->stats.rssi = - stats.rssi; - priv->exp_avg_rssi = - exponential_average(priv->exp_avg_rssi, - stats.rssi, DEPTH_RSSI); - } - - IPW_DEBUG_RX("Frame: len=%u\n", - le16_to_cpu(pkt->u.frame.length)); - - if (le16_to_cpu(pkt->u.frame.length) < - ieee80211_get_hdrlen(le16_to_cpu( - header->frame_ctl))) { - IPW_DEBUG_DROP - ("Received packet is too small. " - "Dropping.\n"); - priv->ieee->stats.rx_errors++; - priv->wstats.discard.misc++; - break; - } - - switch (WLAN_FC_GET_TYPE - (le16_to_cpu(header->frame_ctl))) { - - case IEEE80211_FTYPE_MGMT: - ipw_handle_mgmt_packet(priv, rxb, - &stats); - break; - - case IEEE80211_FTYPE_CTL: - break; - - case IEEE80211_FTYPE_DATA: - if (unlikely(!network_packet || - is_duplicate_packet(priv, - header))) - { - IPW_DEBUG_DROP("Dropping: " - "%pM, " - "%pM, " - "%pM\n", - header->addr1, - header->addr2, - header->addr3); - break; - } - - ipw_handle_data_packet(priv, rxb, - &stats); - - break; - } - break; - } - - case RX_HOST_NOTIFICATION_TYPE:{ - IPW_DEBUG_RX - ("Notification: subtype=%02X flags=%02X size=%d\n", - pkt->u.notification.subtype, - pkt->u.notification.flags, - le16_to_cpu(pkt->u.notification.size)); - ipw_rx_notification(priv, &pkt->u.notification); - break; - } - - default: - IPW_DEBUG_RX("Bad Rx packet of type %d\n", - pkt->header.message_type); - break; - } - - /* For now we just don't re-use anything. We can tweak this - * later to try and re-use notification packets and SKBs that - * fail to Rx correctly */ - if (rxb->skb != NULL) { - dev_kfree_skb_any(rxb->skb); - rxb->skb = NULL; - } - - pci_unmap_single(priv->pci_dev, rxb->dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - list_add_tail(&rxb->list, &priv->rxq->rx_used); - - i = (i + 1) % RX_QUEUE_SIZE; - - /* If there are a lot of unsued frames, restock the Rx queue - * so the ucode won't assert */ - if (fill_rx) { - priv->rxq->read = i; - ipw_rx_queue_replenish(priv); - } - } - - /* Backtrack one entry */ - priv->rxq->read = i; - ipw_rx_queue_restock(priv); -} - -#define DEFAULT_RTS_THRESHOLD 2304U -#define MIN_RTS_THRESHOLD 1U -#define MAX_RTS_THRESHOLD 2304U -#define DEFAULT_BEACON_INTERVAL 100U -#define DEFAULT_SHORT_RETRY_LIMIT 7U -#define DEFAULT_LONG_RETRY_LIMIT 4U - -/** - * ipw_sw_reset - * @option: options to control different reset behaviour - * 0 = reset everything except the 'disable' module_param - * 1 = reset everything and print out driver info (for probe only) - * 2 = reset everything - */ -static int ipw_sw_reset(struct ipw_priv *priv, int option) -{ - int band, modulation; - int old_mode = priv->ieee->iw_mode; - - /* Initialize module parameter values here */ - priv->config = 0; - - /* We default to disabling the LED code as right now it causes - * too many systems to lock up... */ - if (!led) - priv->config |= CFG_NO_LED; - - if (associate) - priv->config |= CFG_ASSOCIATE; - else - IPW_DEBUG_INFO("Auto associate disabled.\n"); - - if (auto_create) - priv->config |= CFG_ADHOC_CREATE; - else - IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); - - priv->config &= ~CFG_STATIC_ESSID; - priv->essid_len = 0; - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - - if (disable && option) { - priv->status |= STATUS_RF_KILL_SW; - IPW_DEBUG_INFO("Radio disabled.\n"); - } - - if (channel != 0) { - priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); - /* TODO: Validate that provided channel is in range */ - } -#ifdef CONFIG_IPW2200_QOS - ipw_qos_init(priv, qos_enable, qos_burst_enable, - burst_duration_CCK, burst_duration_OFDM); -#endif /* CONFIG_IPW2200_QOS */ - - switch (mode) { - case 1: - priv->ieee->iw_mode = IW_MODE_ADHOC; - priv->net_dev->type = ARPHRD_ETHER; - - break; -#ifdef CONFIG_IPW2200_MONITOR - case 2: - priv->ieee->iw_mode = IW_MODE_MONITOR; -#ifdef CONFIG_IPW2200_RADIOTAP - priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; -#else - priv->net_dev->type = ARPHRD_IEEE80211; -#endif - break; -#endif - default: - case 0: - priv->net_dev->type = ARPHRD_ETHER; - priv->ieee->iw_mode = IW_MODE_INFRA; - break; - } - - if (hwcrypto) { - priv->ieee->host_encrypt = 0; - priv->ieee->host_encrypt_msdu = 0; - priv->ieee->host_decrypt = 0; - priv->ieee->host_mc_decrypt = 0; - } - IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); - - /* IPW2200/2915 is abled to do hardware fragmentation. */ - priv->ieee->host_open_frag = 0; - - if ((priv->pci_dev->device == 0x4223) || - (priv->pci_dev->device == 0x4224)) { - if (option == 1) - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2915ABG Network " - "Connection\n"); - priv->ieee->abg_true = 1; - band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - priv->adapter = IPW_2915ABG; - priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; - } else { - if (option == 1) - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2200BG Network " - "Connection\n"); - - priv->ieee->abg_true = 0; - band = IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - priv->adapter = IPW_2200BG; - priv->ieee->mode = IEEE_G | IEEE_B; - } - - priv->ieee->freq_band = band; - priv->ieee->modulation = modulation; - - priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; - - priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; - priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; - - priv->rts_threshold = DEFAULT_RTS_THRESHOLD; - priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; - priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; - - /* If power management is turned on, default to AC mode */ - priv->power_mode = IPW_POWER_AC; - priv->tx_power = IPW_TX_POWER_DEFAULT; - - return old_mode == priv->ieee->iw_mode; -} - -/* - * This file defines the Wireless Extension handlers. It does not - * define any methods of hardware manipulation and relies on the - * functions defined in ipw_main to provide the HW interaction. - * - * The exception to this is the use of the ipw_get_ordinal() - * function used to poll the hardware vs. making unecessary calls. - * - */ - -static int ipw_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - if (priv->status & STATUS_RF_KILL_MASK) - strcpy(wrqu->name, "radio off"); - else if (!(priv->status & STATUS_ASSOCIATED)) - strcpy(wrqu->name, "unassociated"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", - ipw_modes[priv->assoc_request.ieee_mode]); - IPW_DEBUG_WX("Name: %s\n", wrqu->name); - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_set_channel(struct ipw_priv *priv, u8 channel) -{ - if (channel == 0) { - IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); - priv->config &= ~CFG_STATIC_CHANNEL; - IPW_DEBUG_ASSOC("Attempting to associate with new " - "parameters.\n"); - ipw_associate(priv); - return 0; - } - - priv->config |= CFG_STATIC_CHANNEL; - - if (priv->channel == channel) { - IPW_DEBUG_INFO("Request to set channel to current value (%d)\n", - channel); - return 0; - } - - IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); - priv->channel = channel; - -#ifdef CONFIG_IPW2200_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - int i; - if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_SCAN("Scan abort triggered due to " - "channel change.\n"); - ipw_abort_scan(priv); - } - - for (i = 1000; i && (priv->status & STATUS_SCANNING); i--) - udelay(10); - - if (priv->status & STATUS_SCANNING) - IPW_DEBUG_SCAN("Still scanning...\n"); - else - IPW_DEBUG_SCAN("Took %dms to abort current scan\n", - 1000 - i); - - return 0; - } -#endif /* CONFIG_IPW2200_MONITOR */ - - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - - return 0; -} - -static int ipw_wx_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - struct iw_freq *fwrq = &wrqu->freq; - int ret = 0, i; - u8 channel, flags; - int band; - - if (fwrq->m == 0) { - IPW_DEBUG_WX("SET Freq/Channel -> any\n"); - mutex_lock(&priv->mutex); - ret = ipw_set_channel(priv, 0); - mutex_unlock(&priv->mutex); - return ret; - } - /* if setting by freq convert to channel */ - if (fwrq->e == 1) { - channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); - if (channel == 0) - return -EINVAL; - } else - channel = fwrq->m; - - if (!(band = ieee80211_is_valid_channel(priv->ieee, channel))) - return -EINVAL; - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - i = ieee80211_channel_to_index(priv->ieee, channel); - if (i == -1) - return -EINVAL; - - flags = (band == IEEE80211_24GHZ_BAND) ? - geo->bg[i].flags : geo->a[i].flags; - if (flags & IEEE80211_CH_PASSIVE_ONLY) { - IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); - return -EINVAL; - } - } - - IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); - mutex_lock(&priv->mutex); - ret = ipw_set_channel(priv, channel); - mutex_unlock(&priv->mutex); - return ret; -} - -static int ipw_wx_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - wrqu->freq.e = 0; - - /* If we are associated, trying to associate, or have a statically - * configured CHANNEL then return that; otherwise return ANY */ - mutex_lock(&priv->mutex); - if (priv->config & CFG_STATIC_CHANNEL || - priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) { - int i; - - i = ieee80211_channel_to_index(priv->ieee, priv->channel); - BUG_ON(i == -1); - wrqu->freq.e = 1; - - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: - wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000; - break; - - case IEEE80211_24GHZ_BAND: - wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000; - break; - - default: - BUG(); - } - } else - wrqu->freq.m = 0; - - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); - return 0; -} - -static int ipw_wx_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int err = 0; - - IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); - - switch (wrqu->mode) { -#ifdef CONFIG_IPW2200_MONITOR - case IW_MODE_MONITOR: -#endif - case IW_MODE_ADHOC: - case IW_MODE_INFRA: - break; - case IW_MODE_AUTO: - wrqu->mode = IW_MODE_INFRA; - break; - default: - return -EINVAL; - } - if (wrqu->mode == priv->ieee->iw_mode) - return 0; - - mutex_lock(&priv->mutex); - - ipw_sw_reset(priv, 0); - -#ifdef CONFIG_IPW2200_MONITOR - if (priv->ieee->iw_mode == IW_MODE_MONITOR) - priv->net_dev->type = ARPHRD_ETHER; - - if (wrqu->mode == IW_MODE_MONITOR) -#ifdef CONFIG_IPW2200_RADIOTAP - priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; -#else - priv->net_dev->type = ARPHRD_IEEE80211; -#endif -#endif /* CONFIG_IPW2200_MONITOR */ - - /* Free the existing firmware and reset the fw_loaded - * flag so ipw_load() will bring in the new firmawre */ - free_firmware(); - - priv->ieee->iw_mode = wrqu->mode; - - queue_work(priv->workqueue, &priv->adapter_restart); - mutex_unlock(&priv->mutex); - return err; -} - -static int ipw_wx_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - wrqu->mode = priv->ieee->iw_mode; - IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); - mutex_unlock(&priv->mutex); - return 0; -} - -/* Values are in microsecond */ -static const s32 timeout_duration[] = { - 350000, - 250000, - 75000, - 37000, - 25000, -}; - -static const s32 period_duration[] = { - 400000, - 700000, - 1000000, - 1000000, - 1000000 -}; - -static int ipw_wx_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - int i = 0, j; - - wrqu->data.length = sizeof(*range); - memset(range, 0, sizeof(*range)); - - /* 54Mbs == ~27 Mb/s real (802.11g) */ - range->throughput = 27 * 1000 * 1000; - - range->max_qual.qual = 100; - /* TODO: Find real max RSSI and stick here */ - range->max_qual.level = 0; - range->max_qual.noise = 0; - range->max_qual.updated = 7; /* Updated all three */ - - range->avg_qual.qual = 70; - /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ - range->avg_qual.level = 0; /* FIXME to real average level */ - range->avg_qual.noise = 0; - range->avg_qual.updated = 7; /* Updated all three */ - mutex_lock(&priv->mutex); - range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); - - for (i = 0; i < range->num_bitrates; i++) - range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) * - 500000; - - range->max_rts = DEFAULT_RTS_THRESHOLD; - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = WEP_KEYS; - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 18; - - i = 0; - if (priv->ieee->mode & (IEEE_B | IEEE_G)) { - for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) { - if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY)) - continue; - - range->freq[i].i = geo->bg[j].channel; - range->freq[i].m = geo->bg[j].freq * 100000; - range->freq[i].e = 1; - i++; - } - } - - if (priv->ieee->mode & IEEE_A) { - for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) { - if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY)) - continue; - - range->freq[i].i = geo->a[j].channel; - range->freq[i].m = geo->a[j].freq * 100000; - range->freq[i].e = 1; - i++; - } - } - - range->num_channels = i; - range->num_frequency = i; - - mutex_unlock(&priv->mutex); - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | - IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP) | - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; - - IPW_DEBUG_WX("GET Range\n"); - return 0; -} - -static int ipw_wx_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - static const unsigned char any[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - static const unsigned char off[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) - return -EINVAL; - mutex_lock(&priv->mutex); - if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || - !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { - /* we disable mandatory BSSID association */ - IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); - priv->config &= ~CFG_STATIC_BSSID; - IPW_DEBUG_ASSOC("Attempting to associate with new " - "parameters.\n"); - ipw_associate(priv); - mutex_unlock(&priv->mutex); - return 0; - } - - priv->config |= CFG_STATIC_BSSID; - if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { - IPW_DEBUG_WX("BSSID set to current BSSID.\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n", - wrqu->ap_addr.sa_data); - - memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); - - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - /* If we are associated, trying to associate, or have a statically - * configured BSSID then return that; otherwise return ANY */ - mutex_lock(&priv->mutex); - if (priv->config & CFG_STATIC_BSSID || - priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); - } else - memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - - IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", - wrqu->ap_addr.sa_data); - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int length; - DECLARE_SSID_BUF(ssid); - - mutex_lock(&priv->mutex); - - if (!wrqu->essid.flags) - { - IPW_DEBUG_WX("Setting ESSID to ANY\n"); - ipw_disassociate(priv); - priv->config &= ~CFG_STATIC_ESSID; - ipw_associate(priv); - mutex_unlock(&priv->mutex); - return 0; - } - - length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE); - - priv->config |= CFG_STATIC_ESSID; - - if (priv->essid_len == length && !memcmp(priv->essid, extra, length) - && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { - IPW_DEBUG_WX("ESSID set to current ESSID.\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", - print_ssid(ssid, extra, length), length); - - priv->essid_len = length; - memcpy(priv->essid, extra, priv->essid_len); - - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_SSID_BUF(ssid); - - /* If we are associated, trying to associate, or have a statically - * configured ESSID then return that; otherwise return ANY */ - mutex_lock(&priv->mutex); - if (priv->config & CFG_STATIC_ESSID || - priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_WX("Getting essid: '%s'\n", - print_ssid(ssid, priv->essid, priv->essid_len)); - memcpy(extra, priv->essid, priv->essid_len); - wrqu->essid.length = priv->essid_len; - wrqu->essid.flags = 1; /* active */ - } else { - IPW_DEBUG_WX("Getting essid: ANY\n"); - wrqu->essid.length = 0; - wrqu->essid.flags = 0; /* active */ - } - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_set_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - IPW_DEBUG_WX("Setting nick to '%s'\n", extra); - if (wrqu->data.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - mutex_lock(&priv->mutex); - wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); - memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, extra, wrqu->data.length); - IPW_DEBUG_TRACE("<<\n"); - mutex_unlock(&priv->mutex); - return 0; - -} - -static int ipw_wx_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - IPW_DEBUG_WX("Getting nick\n"); - mutex_lock(&priv->mutex); - wrqu->data.length = strlen(priv->nick); - memcpy(extra, priv->nick, wrqu->data.length); - wrqu->data.flags = 1; /* active */ - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int err = 0; - - IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value); - IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value); - mutex_lock(&priv->mutex); - - if (wrqu->sens.fixed == 0) - { - priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; - priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; - goto out; - } - if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) || - (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) { - err = -EINVAL; - goto out; - } - - priv->roaming_threshold = wrqu->sens.value; - priv->disassociate_threshold = 3*wrqu->sens.value; - out: - mutex_unlock(&priv->mutex); - return err; -} - -static int ipw_wx_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - wrqu->sens.fixed = 1; - wrqu->sens.value = priv->roaming_threshold; - mutex_unlock(&priv->mutex); - - IPW_DEBUG_WX("GET roaming threshold -> %s %d \n", - wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); - - return 0; -} - -static int ipw_wx_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* TODO: We should use semaphores or locks for access to priv */ - struct ipw_priv *priv = ieee80211_priv(dev); - u32 target_rate = wrqu->bitrate.value; - u32 fixed, mask; - - /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */ - /* value = X, fixed = 1 means only rate X */ - /* value = X, fixed = 0 means all rates lower equal X */ - - if (target_rate == -1) { - fixed = 0; - mask = IEEE80211_DEFAULT_RATES_MASK; - /* Now we should reassociate */ - goto apply; - } - - mask = 0; - fixed = wrqu->bitrate.fixed; - - if (target_rate == 1000000 || !fixed) - mask |= IEEE80211_CCK_RATE_1MB_MASK; - if (target_rate == 1000000) - goto apply; - - if (target_rate == 2000000 || !fixed) - mask |= IEEE80211_CCK_RATE_2MB_MASK; - if (target_rate == 2000000) - goto apply; - - if (target_rate == 5500000 || !fixed) - mask |= IEEE80211_CCK_RATE_5MB_MASK; - if (target_rate == 5500000) - goto apply; - - if (target_rate == 6000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_6MB_MASK; - if (target_rate == 6000000) - goto apply; - - if (target_rate == 9000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_9MB_MASK; - if (target_rate == 9000000) - goto apply; - - if (target_rate == 11000000 || !fixed) - mask |= IEEE80211_CCK_RATE_11MB_MASK; - if (target_rate == 11000000) - goto apply; - - if (target_rate == 12000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_12MB_MASK; - if (target_rate == 12000000) - goto apply; - - if (target_rate == 18000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_18MB_MASK; - if (target_rate == 18000000) - goto apply; - - if (target_rate == 24000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_24MB_MASK; - if (target_rate == 24000000) - goto apply; - - if (target_rate == 36000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_36MB_MASK; - if (target_rate == 36000000) - goto apply; - - if (target_rate == 48000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_48MB_MASK; - if (target_rate == 48000000) - goto apply; - - if (target_rate == 54000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_54MB_MASK; - if (target_rate == 54000000) - goto apply; - - IPW_DEBUG_WX("invalid rate specified, returning error\n"); - return -EINVAL; - - apply: - IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", - mask, fixed ? "fixed" : "sub-rates"); - mutex_lock(&priv->mutex); - if (mask == IEEE80211_DEFAULT_RATES_MASK) { - priv->config &= ~CFG_FIXED_RATE; - ipw_set_fixed_rate(priv, priv->ieee->mode); - } else - priv->config |= CFG_FIXED_RATE; - - if (priv->rates_mask == mask) { - IPW_DEBUG_WX("Mask set to current mask.\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - priv->rates_mask = mask; - - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - wrqu->bitrate.value = priv->last_rate; - wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0; - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); - return 0; -} - -static int ipw_wx_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - if (wrqu->rts.disabled || !wrqu->rts.fixed) - priv->rts_threshold = DEFAULT_RTS_THRESHOLD; - else { - if (wrqu->rts.value < MIN_RTS_THRESHOLD || - wrqu->rts.value > MAX_RTS_THRESHOLD) { - mutex_unlock(&priv->mutex); - return -EINVAL; - } - priv->rts_threshold = wrqu->rts.value; - } - - ipw_send_rts_threshold(priv, priv->rts_threshold); - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); - return 0; -} - -static int ipw_wx_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - wrqu->rts.value = priv->rts_threshold; - wrqu->rts.fixed = 0; /* no auto select */ - wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); - return 0; -} - -static int ipw_wx_set_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int err = 0; - - mutex_lock(&priv->mutex); - if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { - err = -EINPROGRESS; - goto out; - } - - if (!wrqu->power.fixed) - wrqu->power.value = IPW_TX_POWER_DEFAULT; - - if (wrqu->power.flags != IW_TXPOW_DBM) { - err = -EINVAL; - goto out; - } - - if ((wrqu->power.value > IPW_TX_POWER_MAX) || - (wrqu->power.value < IPW_TX_POWER_MIN)) { - err = -EINVAL; - goto out; - } - - priv->tx_power = wrqu->power.value; - err = ipw_set_tx_power(priv); - out: - mutex_unlock(&priv->mutex); - return err; -} - -static int ipw_wx_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - wrqu->power.value = priv->tx_power; - wrqu->power.fixed = 1; - wrqu->power.flags = IW_TXPOW_DBM; - wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; - mutex_unlock(&priv->mutex); - - IPW_DEBUG_WX("GET TX Power -> %s %d \n", - wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); - - return 0; -} - -static int ipw_wx_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - if (wrqu->frag.disabled || !wrqu->frag.fixed) - priv->ieee->fts = DEFAULT_FTS; - else { - if (wrqu->frag.value < MIN_FRAG_THRESHOLD || - wrqu->frag.value > MAX_FRAG_THRESHOLD) { - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - priv->ieee->fts = wrqu->frag.value & ~0x1; - } - - ipw_send_frag_threshold(priv, wrqu->frag.value); - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); - return 0; -} - -static int ipw_wx_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - wrqu->frag.value = priv->ieee->fts; - wrqu->frag.fixed = 0; /* no auto select */ - wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); - - return 0; -} - -static int ipw_wx_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) - return -EINVAL; - - if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) - return 0; - - if (wrqu->retry.value < 0 || wrqu->retry.value >= 255) - return -EINVAL; - - mutex_lock(&priv->mutex); - if (wrqu->retry.flags & IW_RETRY_SHORT) - priv->short_retry_limit = (u8) wrqu->retry.value; - else if (wrqu->retry.flags & IW_RETRY_LONG) - priv->long_retry_limit = (u8) wrqu->retry.value; - else { - priv->short_retry_limit = (u8) wrqu->retry.value; - priv->long_retry_limit = (u8) wrqu->retry.value; - } - - ipw_send_retry_limit(priv, priv->short_retry_limit, - priv->long_retry_limit); - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n", - priv->short_retry_limit, priv->long_retry_limit); - return 0; -} - -static int ipw_wx_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - mutex_lock(&priv->mutex); - wrqu->retry.disabled = 0; - - if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - if (wrqu->retry.flags & IW_RETRY_LONG) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - wrqu->retry.value = priv->long_retry_limit; - } else if (wrqu->retry.flags & IW_RETRY_SHORT) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; - wrqu->retry.value = priv->short_retry_limit; - } else { - wrqu->retry.flags = IW_RETRY_LIMIT; - wrqu->retry.value = priv->short_retry_limit; - } - mutex_unlock(&priv->mutex); - - IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value); - - return 0; -} - -static int ipw_wx_set_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct iw_scan_req *req = (struct iw_scan_req *)extra; - struct delayed_work *work = NULL; - - mutex_lock(&priv->mutex); - - priv->user_requested_scan = 1; - - if (wrqu->data.length == sizeof(struct iw_scan_req)) { - if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - int len = min((int)req->essid_len, - (int)sizeof(priv->direct_scan_ssid)); - memcpy(priv->direct_scan_ssid, req->essid, len); - priv->direct_scan_ssid_len = len; - work = &priv->request_direct_scan; - } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { - work = &priv->request_passive_scan; - } - } else { - /* Normal active broadcast scan */ - work = &priv->request_scan; - } - - mutex_unlock(&priv->mutex); - - IPW_DEBUG_WX("Start scan\n"); - - queue_delayed_work(priv->workqueue, work, 0); - - return 0; -} - -static int ipw_wx_get_scan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); -} - -static int ipw_wx_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int ret; - u32 cap = priv->capability; - - mutex_lock(&priv->mutex); - ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); - - /* In IBSS mode, we need to notify the firmware to update - * the beacon info after we changed the capability. */ - if (cap != priv->capability && - priv->ieee->iw_mode == IW_MODE_ADHOC && - priv->status & STATUS_ASSOCIATED) - ipw_disassociate(priv); - - mutex_unlock(&priv->mutex); - return ret; -} - -static int ipw_wx_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); -} - -static int ipw_wx_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int err; - mutex_lock(&priv->mutex); - if (wrqu->power.disabled) { - priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); - err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); - if (err) { - IPW_DEBUG_WX("failed setting power mode.\n"); - mutex_unlock(&priv->mutex); - return err; - } - IPW_DEBUG_WX("SET Power Management Mode -> off\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - switch (wrqu->power.flags & IW_POWER_MODE) { - case IW_POWER_ON: /* If not specified */ - case IW_POWER_MODE: /* If set all mask */ - case IW_POWER_ALL_R: /* If explicitly state all */ - break; - default: /* Otherwise we don't support it */ - IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", - wrqu->power.flags); - mutex_unlock(&priv->mutex); - return -EOPNOTSUPP; - } - - /* If the user hasn't specified a power management mode yet, default - * to BATTERY */ - if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC) - priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY; - else - priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; - - err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); - if (err) { - IPW_DEBUG_WX("failed setting power mode.\n"); - mutex_unlock(&priv->mutex); - return err; - } - - IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - if (!(priv->power_mode & IPW_POWER_ENABLED)) - wrqu->power.disabled = 1; - else - wrqu->power.disabled = 0; - - mutex_unlock(&priv->mutex); - IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); - - return 0; -} - -static int ipw_wx_set_powermode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int mode = *(int *)extra; - int err; - - mutex_lock(&priv->mutex); - if ((mode < 1) || (mode > IPW_POWER_LIMIT)) - mode = IPW_POWER_AC; - - if (IPW_POWER_LEVEL(priv->power_mode) != mode) { - err = ipw_send_power_mode(priv, mode); - if (err) { - IPW_DEBUG_WX("failed setting power mode.\n"); - mutex_unlock(&priv->mutex); - return err; - } - priv->power_mode = IPW_POWER_ENABLED | mode; - } - mutex_unlock(&priv->mutex); - return 0; -} - -#define MAX_WX_STRING 80 -static int ipw_wx_get_powermode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int level = IPW_POWER_LEVEL(priv->power_mode); - char *p = extra; - - p += snprintf(p, MAX_WX_STRING, "Power save level: %d ", level); - - switch (level) { - case IPW_POWER_AC: - p += snprintf(p, MAX_WX_STRING - (p - extra), "(AC)"); - break; - case IPW_POWER_BATTERY: - p += snprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)"); - break; - default: - p += snprintf(p, MAX_WX_STRING - (p - extra), - "(Timeout %dms, Period %dms)", - timeout_duration[level - 1] / 1000, - period_duration[level - 1] / 1000); - } - - if (!(priv->power_mode & IPW_POWER_ENABLED)) - p += snprintf(p, MAX_WX_STRING - (p - extra), " OFF"); - - wrqu->data.length = p - extra + 1; - - return 0; -} - -static int ipw_wx_set_wireless_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int mode = *(int *)extra; - u8 band = 0, modulation = 0; - - if (mode == 0 || mode & ~IEEE_MODE_MASK) { - IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); - return -EINVAL; - } - mutex_lock(&priv->mutex); - if (priv->adapter == IPW_2915ABG) { - priv->ieee->abg_true = 1; - if (mode & IEEE_A) { - band |= IEEE80211_52GHZ_BAND; - modulation |= IEEE80211_OFDM_MODULATION; - } else - priv->ieee->abg_true = 0; - } else { - if (mode & IEEE_A) { - IPW_WARNING("Attempt to set 2200BG into " - "802.11a mode\n"); - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - priv->ieee->abg_true = 0; - } - - if (mode & IEEE_B) { - band |= IEEE80211_24GHZ_BAND; - modulation |= IEEE80211_CCK_MODULATION; - } else - priv->ieee->abg_true = 0; - - if (mode & IEEE_G) { - band |= IEEE80211_24GHZ_BAND; - modulation |= IEEE80211_OFDM_MODULATION; - } else - priv->ieee->abg_true = 0; - - priv->ieee->mode = mode; - priv->ieee->freq_band = band; - priv->ieee->modulation = modulation; - init_supported_rates(priv, &priv->rates); - - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n"); - if (!ipw_disassociate(priv)) { - ipw_send_supported_rates(priv, &priv->rates); - ipw_associate(priv); - } - - /* Update the band LEDs */ - ipw_led_band_on(priv); - - IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", - mode & IEEE_A ? 'a' : '.', - mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_get_wireless_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - switch (priv->ieee->mode) { - case IEEE_A: - strncpy(extra, "802.11a (1)", MAX_WX_STRING); - break; - case IEEE_B: - strncpy(extra, "802.11b (2)", MAX_WX_STRING); - break; - case IEEE_A | IEEE_B: - strncpy(extra, "802.11ab (3)", MAX_WX_STRING); - break; - case IEEE_G: - strncpy(extra, "802.11g (4)", MAX_WX_STRING); - break; - case IEEE_A | IEEE_G: - strncpy(extra, "802.11ag (5)", MAX_WX_STRING); - break; - case IEEE_B | IEEE_G: - strncpy(extra, "802.11bg (6)", MAX_WX_STRING); - break; - case IEEE_A | IEEE_B | IEEE_G: - strncpy(extra, "802.11abg (7)", MAX_WX_STRING); - break; - default: - strncpy(extra, "unknown", MAX_WX_STRING); - break; - } - - IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); - - wrqu->data.length = strlen(extra) + 1; - mutex_unlock(&priv->mutex); - - return 0; -} - -static int ipw_wx_set_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int mode = *(int *)extra; - mutex_lock(&priv->mutex); - /* Switching from SHORT -> LONG requires a disassociation */ - if (mode == 1) { - if (!(priv->config & CFG_PREAMBLE_LONG)) { - priv->config |= CFG_PREAMBLE_LONG; - - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC - ("[re]association triggered due to preamble change.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - } - goto done; - } - - if (mode == 0) { - priv->config &= ~CFG_PREAMBLE_LONG; - goto done; - } - mutex_unlock(&priv->mutex); - return -EINVAL; - - done: - mutex_unlock(&priv->mutex); - return 0; -} - -static int ipw_wx_get_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - if (priv->config & CFG_PREAMBLE_LONG) - snprintf(wrqu->name, IFNAMSIZ, "long (1)"); - else - snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); - mutex_unlock(&priv->mutex); - return 0; -} - -#ifdef CONFIG_IPW2200_MONITOR -static int ipw_wx_set_monitor(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int *parms = (int *)extra; - int enable = (parms[0] > 0); - mutex_lock(&priv->mutex); - IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); - if (enable) { - if (priv->ieee->iw_mode != IW_MODE_MONITOR) { -#ifdef CONFIG_IPW2200_RADIOTAP - priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; -#else - priv->net_dev->type = ARPHRD_IEEE80211; -#endif - queue_work(priv->workqueue, &priv->adapter_restart); - } - - ipw_set_channel(priv, parms[1]); - } else { - if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - mutex_unlock(&priv->mutex); - return 0; - } - priv->net_dev->type = ARPHRD_ETHER; - queue_work(priv->workqueue, &priv->adapter_restart); - } - mutex_unlock(&priv->mutex); - return 0; -} - -#endif /* CONFIG_IPW2200_MONITOR */ - -static int ipw_wx_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - IPW_DEBUG_WX("RESET\n"); - queue_work(priv->workqueue, &priv->adapter_restart); - return 0; -} - -static int ipw_wx_sw_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - union iwreq_data wrqu_sec = { - .encoding = { - .flags = IW_ENCODE_DISABLED, - }, - }; - int ret; - - IPW_DEBUG_WX("SW_RESET\n"); - - mutex_lock(&priv->mutex); - - ret = ipw_sw_reset(priv, 2); - if (!ret) { - free_firmware(); - ipw_adapter_restart(priv); - } - - /* The SW reset bit might have been toggled on by the 'disable' - * module parameter, so take appropriate action */ - ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); - - mutex_unlock(&priv->mutex); - ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); - mutex_lock(&priv->mutex); - - if (!(priv->status & STATUS_RF_KILL_MASK)) { - /* Configuration likely changed -- force [re]association */ - IPW_DEBUG_ASSOC("[re]association triggered due to sw " - "reset.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - } - - mutex_unlock(&priv->mutex); - - return 0; -} - -/* Rebase the WE IOCTLs to zero for the handler array */ -#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] -static iw_handler ipw_wx_handlers[] = { - IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, - IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, - IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, - IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, - IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, - IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens, - IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens, - IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, - IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, - IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, - IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, - IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, - IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, - IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, - IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, - IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, - IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, - IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, - IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, - IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, - IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, - IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, - IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, - IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, - IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, - IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, - IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, - IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, - IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, - IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, - IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy, - IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, - IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, - IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, - IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie, - IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie, - IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme, - IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth, - IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth, - IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext, - IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext, -}; - -enum { - IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV, - IPW_PRIV_GET_POWER, - IPW_PRIV_SET_MODE, - IPW_PRIV_GET_MODE, - IPW_PRIV_SET_PREAMBLE, - IPW_PRIV_GET_PREAMBLE, - IPW_PRIV_RESET, - IPW_PRIV_SW_RESET, -#ifdef CONFIG_IPW2200_MONITOR - IPW_PRIV_SET_MONITOR, -#endif -}; - -static struct iw_priv_args ipw_priv_args[] = { - { - .cmd = IPW_PRIV_SET_POWER, - .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_power"}, - { - .cmd = IPW_PRIV_GET_POWER, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_power"}, - { - .cmd = IPW_PRIV_SET_MODE, - .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_mode"}, - { - .cmd = IPW_PRIV_GET_MODE, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_mode"}, - { - .cmd = IPW_PRIV_SET_PREAMBLE, - .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_preamble"}, - { - .cmd = IPW_PRIV_GET_PREAMBLE, - .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, - .name = "get_preamble"}, - { - IPW_PRIV_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, - { - IPW_PRIV_SW_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"}, -#ifdef CONFIG_IPW2200_MONITOR - { - IPW_PRIV_SET_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, -#endif /* CONFIG_IPW2200_MONITOR */ -}; - -static iw_handler ipw_priv_handler[] = { - ipw_wx_set_powermode, - ipw_wx_get_powermode, - ipw_wx_set_wireless_mode, - ipw_wx_get_wireless_mode, - ipw_wx_set_preamble, - ipw_wx_get_preamble, - ipw_wx_reset, - ipw_wx_sw_reset, -#ifdef CONFIG_IPW2200_MONITOR - ipw_wx_set_monitor, -#endif -}; - -static struct iw_handler_def ipw_wx_handler_def = { - .standard = ipw_wx_handlers, - .num_standard = ARRAY_SIZE(ipw_wx_handlers), - .num_private = ARRAY_SIZE(ipw_priv_handler), - .num_private_args = ARRAY_SIZE(ipw_priv_args), - .private = ipw_priv_handler, - .private_args = ipw_priv_args, - .get_wireless_stats = ipw_get_wireless_stats, -}; - -/* - * Get wireless statistics. - * Called by /proc/net/wireless - * Also called by SIOCGIWSTATS - */ -static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct iw_statistics *wstats; - - wstats = &priv->wstats; - - /* if hw is disabled, then ipw_get_ordinal() can't be called. - * netdev->get_wireless_stats seems to be called before fw is - * initialized. STATUS_ASSOCIATED will only be set if the hw is up - * and associated; if not associcated, the values are all meaningless - * anyway, so set them all to NULL and INVALID */ - if (!(priv->status & STATUS_ASSOCIATED)) { - wstats->miss.beacon = 0; - wstats->discard.retries = 0; - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = 7; - wstats->qual.updated |= IW_QUAL_NOISE_INVALID | - IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; - return wstats; - } - - wstats->qual.qual = priv->quality; - wstats->qual.level = priv->exp_avg_rssi; - wstats->qual.noise = priv->exp_avg_noise; - wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | - IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; - - wstats->miss.beacon = average_value(&priv->average_missed_beacons); - wstats->discard.retries = priv->last_tx_failures; - wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable; - -/* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len)) - goto fail_get_ordinal; - wstats->discard.retries += tx_retry; */ - - return wstats; -} - -/* net device stuff */ - -static void init_sys_config(struct ipw_sys_config *sys_config) -{ - memset(sys_config, 0, sizeof(struct ipw_sys_config)); - sys_config->bt_coexistence = 0; - sys_config->answer_broadcast_ssid_probe = 0; - sys_config->accept_all_data_frames = 0; - sys_config->accept_non_directed_frames = 1; - sys_config->exclude_unicast_unencrypted = 0; - sys_config->disable_unicast_decryption = 1; - sys_config->exclude_multicast_unencrypted = 0; - sys_config->disable_multicast_decryption = 1; - if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B) - antenna = CFG_SYS_ANTENNA_BOTH; - sys_config->antenna_diversity = antenna; - sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */ - sys_config->dot11g_auto_detection = 0; - sys_config->enable_cts_to_self = 0; - sys_config->bt_coexist_collision_thr = 0; - sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */ - sys_config->silence_threshold = 0x1e; -} - -static int ipw_net_open(struct net_device *dev) -{ - IPW_DEBUG_INFO("dev->open\n"); - netif_start_queue(dev); - return 0; -} - -static int ipw_net_stop(struct net_device *dev) -{ - IPW_DEBUG_INFO("dev->close\n"); - netif_stop_queue(dev); - return 0; -} - -/* -todo: - -modify to send one tfd per fragment instead of using chunking. otherwise -we need to heavily modify the ieee80211_skb_to_txb. -*/ - -static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, - int pri) -{ - struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *) - txb->fragments[0]->data; - int i = 0; - struct tfd_frame *tfd; -#ifdef CONFIG_IPW2200_QOS - int tx_id = ipw_get_tx_queue_number(priv, pri); - struct clx2_tx_queue *txq = &priv->txq[tx_id]; -#else - struct clx2_tx_queue *txq = &priv->txq[0]; -#endif - struct clx2_queue *q = &txq->q; - u8 id, hdr_len, unicast; - u16 remaining_bytes; - int fc; - - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - unicast = !is_multicast_ether_addr(hdr->addr1); - id = ipw_find_station(priv, hdr->addr1); - if (id == IPW_INVALID_STATION) { - id = ipw_add_station(priv, hdr->addr1); - if (id == IPW_INVALID_STATION) { - IPW_WARNING("Attempt to send data to " - "invalid cell: %pM\n", - hdr->addr1); - goto drop; - } - } - break; - - case IW_MODE_INFRA: - default: - unicast = !is_multicast_ether_addr(hdr->addr3); - id = 0; - break; - } - - tfd = &txq->bd[q->first_empty]; - txq->txb[q->first_empty] = txb; - memset(tfd, 0, sizeof(*tfd)); - tfd->u.data.station_number = id; - - tfd->control_flags.message_type = TX_FRAME_TYPE; - tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; - - tfd->u.data.cmd_id = DINO_CMD_TX; - tfd->u.data.len = cpu_to_le16(txb->payload_size); - remaining_bytes = txb->payload_size; - - if (priv->assoc_request.ieee_mode == IPW_B_MODE) - tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK; - else - tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM; - - if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) - tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; - - fc = le16_to_cpu(hdr->frame_ctl); - hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS); - - memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); - - if (likely(unicast)) - tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD; - - if (txb->encrypted && !priv->ieee->host_encrypt) { - switch (priv->ieee->sec.level) { - case SEC_LEVEL_3: - tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= - cpu_to_le16(IEEE80211_FCTL_PROTECTED); - /* XXX: ACK flag must be set for CCMP even if it - * is a multicast/broadcast packet, because CCMP - * group communication encrypted by GTK is - * actually done by the AP. */ - if (!unicast) - tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD; - - tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; - tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM; - tfd->u.data.key_index = 0; - tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE; - break; - case SEC_LEVEL_2: - tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= - cpu_to_le16(IEEE80211_FCTL_PROTECTED); - tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; - tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP; - tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE; - break; - case SEC_LEVEL_1: - tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= - cpu_to_le16(IEEE80211_FCTL_PROTECTED); - tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx; - if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <= - 40) - tfd->u.data.key_index |= DCT_WEP_KEY_64Bit; - else - tfd->u.data.key_index |= DCT_WEP_KEY_128Bit; - break; - case SEC_LEVEL_0: - break; - default: - printk(KERN_ERR "Unknow security level %d\n", - priv->ieee->sec.level); - break; - } - } else - /* No hardware encryption */ - tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP; - -#ifdef CONFIG_IPW2200_QOS - if (fc & IEEE80211_STYPE_QOS_DATA) - ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data)); -#endif /* CONFIG_IPW2200_QOS */ - - /* payload */ - tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2), - txb->nr_frags)); - IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n", - txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks)); - for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) { - IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n", - i, le32_to_cpu(tfd->u.data.num_chunks), - txb->fragments[i]->len - hdr_len); - IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n", - i, tfd->u.data.num_chunks, - txb->fragments[i]->len - hdr_len); - printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len, - txb->fragments[i]->len - hdr_len); - - tfd->u.data.chunk_ptr[i] = - cpu_to_le32(pci_map_single - (priv->pci_dev, - txb->fragments[i]->data + hdr_len, - txb->fragments[i]->len - hdr_len, - PCI_DMA_TODEVICE)); - tfd->u.data.chunk_len[i] = - cpu_to_le16(txb->fragments[i]->len - hdr_len); - } - - if (i != txb->nr_frags) { - struct sk_buff *skb; - u16 remaining_bytes = 0; - int j; - - for (j = i; j < txb->nr_frags; j++) - remaining_bytes += txb->fragments[j]->len - hdr_len; - - printk(KERN_INFO "Trying to reallocate for %d bytes\n", - remaining_bytes); - skb = alloc_skb(remaining_bytes, GFP_ATOMIC); - if (skb != NULL) { - tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); - for (j = i; j < txb->nr_frags; j++) { - int size = txb->fragments[j]->len - hdr_len; - - printk(KERN_INFO "Adding frag %d %d...\n", - j, size); - memcpy(skb_put(skb, size), - txb->fragments[j]->data + hdr_len, size); - } - dev_kfree_skb_any(txb->fragments[i]); - txb->fragments[i] = skb; - tfd->u.data.chunk_ptr[i] = - cpu_to_le32(pci_map_single - (priv->pci_dev, skb->data, - remaining_bytes, - PCI_DMA_TODEVICE)); - - le32_add_cpu(&tfd->u.data.num_chunks, 1); - } - } - - /* kick DMA */ - q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); - ipw_write32(priv, q->reg_w, q->first_empty); - - if (ipw_tx_queue_space(q) < q->high_mark) - netif_stop_queue(priv->net_dev); - - return NETDEV_TX_OK; - - drop: - IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); - ieee80211_txb_free(txb); - return NETDEV_TX_OK; -} - -static int ipw_net_is_queue_full(struct net_device *dev, int pri) -{ - struct ipw_priv *priv = ieee80211_priv(dev); -#ifdef CONFIG_IPW2200_QOS - int tx_id = ipw_get_tx_queue_number(priv, pri); - struct clx2_tx_queue *txq = &priv->txq[tx_id]; -#else - struct clx2_tx_queue *txq = &priv->txq[0]; -#endif /* CONFIG_IPW2200_QOS */ - - if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark) - return 1; - - return 0; -} - -#ifdef CONFIG_IPW2200_PROMISCUOUS -static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, - struct ieee80211_txb *txb) -{ - struct ieee80211_rx_stats dummystats; - struct ieee80211_hdr *hdr; - u8 n; - u16 filter = priv->prom_priv->filter; - int hdr_only = 0; - - if (filter & IPW_PROM_NO_TX) - return; - - memset(&dummystats, 0, sizeof(dummystats)); - - /* Filtering of fragment chains is done agains the first fragment */ - hdr = (void *)txb->fragments[0]->data; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { - if (filter & IPW_PROM_NO_MGMT) - return; - if (filter & IPW_PROM_MGMT_HEADER_ONLY) - hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { - if (filter & IPW_PROM_NO_CTL) - return; - if (filter & IPW_PROM_CTL_HEADER_ONLY) - hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { - if (filter & IPW_PROM_NO_DATA) - return; - if (filter & IPW_PROM_DATA_HEADER_ONLY) - hdr_only = 1; - } - - for(n=0; nnr_frags; ++n) { - struct sk_buff *src = txb->fragments[n]; - struct sk_buff *dst; - struct ieee80211_radiotap_header *rt_hdr; - int len; - - if (hdr_only) { - hdr = (void *)src->data; - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - } else - len = src->len; - - dst = alloc_skb( - len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); - if (!dst) continue; - - rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); - - rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; - rt_hdr->it_pad = 0; - rt_hdr->it_present = 0; /* after all, it's just an idea */ - rt_hdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL); - - *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16( - ieee80211chan2mhz(priv->channel)); - if (priv->channel > 14) /* 802.11a */ - *(__le16*)skb_put(dst, sizeof(u16)) = - cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ); - else if (priv->ieee->mode == IEEE_B) /* 802.11b */ - *(__le16*)skb_put(dst, sizeof(u16)) = - cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ); - else /* 802.11g */ - *(__le16*)skb_put(dst, sizeof(u16)) = - cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ); - - rt_hdr->it_len = cpu_to_le16(dst->len); - - skb_copy_from_linear_data(src, skb_put(dst, len), len); - - if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) - dev_kfree_skb_any(dst); - } -} -#endif - -static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, - struct net_device *dev, int pri) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - unsigned long flags; - int ret; - - IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); - spin_lock_irqsave(&priv->lock, flags); - -#ifdef CONFIG_IPW2200_PROMISCUOUS - if (rtap_iface && netif_running(priv->prom_net_dev)) - ipw_handle_promiscuous_tx(priv, txb); -#endif - - ret = ipw_tx_skb(priv, txb, pri); - if (ret == NETDEV_TX_OK) - __ipw_led_activity_on(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} - -static struct net_device_stats *ipw_net_get_stats(struct net_device *dev) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - - priv->ieee->stats.tx_packets = priv->tx_packets; - priv->ieee->stats.rx_packets = priv->rx_packets; - return &priv->ieee->stats; -} - -static void ipw_net_set_multicast_list(struct net_device *dev) -{ - -} - -static int ipw_net_set_mac_address(struct net_device *dev, void *p) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct sockaddr *addr = p; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - mutex_lock(&priv->mutex); - priv->config |= CFG_CUSTOM_MAC; - memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - printk(KERN_INFO "%s: Setting MAC to %pM\n", - priv->net_dev->name, priv->mac_addr); - queue_work(priv->workqueue, &priv->adapter_restart); - mutex_unlock(&priv->mutex); - return 0; -} - -static void ipw_ethtool_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct ipw_priv *p = ieee80211_priv(dev); - char vers[64]; - char date[32]; - u32 len; - - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - - len = sizeof(vers); - ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len); - len = sizeof(date); - ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len); - - snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)", - vers, date); - strcpy(info->bus_info, pci_name(p->pci_dev)); - info->eedump_len = IPW_EEPROM_IMAGE_SIZE; -} - -static u32 ipw_ethtool_get_link(struct net_device *dev) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - return (priv->status & STATUS_ASSOCIATED) != 0; -} - -static int ipw_ethtool_get_eeprom_len(struct net_device *dev) -{ - return IPW_EEPROM_IMAGE_SIZE; -} - -static int ipw_ethtool_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * bytes) -{ - struct ipw_priv *p = ieee80211_priv(dev); - - if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) - return -EINVAL; - mutex_lock(&p->mutex); - memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len); - mutex_unlock(&p->mutex); - return 0; -} - -static int ipw_ethtool_set_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * bytes) -{ - struct ipw_priv *p = ieee80211_priv(dev); - int i; - - if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) - return -EINVAL; - mutex_lock(&p->mutex); - memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); - for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) - ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]); - mutex_unlock(&p->mutex); - return 0; -} - -static const struct ethtool_ops ipw_ethtool_ops = { - .get_link = ipw_ethtool_get_link, - .get_drvinfo = ipw_ethtool_get_drvinfo, - .get_eeprom_len = ipw_ethtool_get_eeprom_len, - .get_eeprom = ipw_ethtool_get_eeprom, - .set_eeprom = ipw_ethtool_set_eeprom, -}; - -static irqreturn_t ipw_isr(int irq, void *data) -{ - struct ipw_priv *priv = data; - u32 inta, inta_mask; - - if (!priv) - return IRQ_NONE; - - spin_lock(&priv->irq_lock); - - if (!(priv->status & STATUS_INT_ENABLED)) { - /* IRQ is disabled */ - goto none; - } - - inta = ipw_read32(priv, IPW_INTA_RW); - inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); - - if (inta == 0xFFFFFFFF) { - /* Hardware disappeared */ - IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n"); - goto none; - } - - if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) { - /* Shared interrupt */ - goto none; - } - - /* tell the device to stop sending interrupts */ - __ipw_disable_interrupts(priv); - - /* ack current interrupts */ - inta &= (IPW_INTA_MASK_ALL & inta_mask); - ipw_write32(priv, IPW_INTA_RW, inta); - - /* Cache INTA value for our tasklet */ - priv->isr_inta = inta; - - tasklet_schedule(&priv->irq_tasklet); - - spin_unlock(&priv->irq_lock); - - return IRQ_HANDLED; - none: - spin_unlock(&priv->irq_lock); - return IRQ_NONE; -} - -static void ipw_rf_kill(void *adapter) -{ - struct ipw_priv *priv = adapter; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - if (rf_kill_active(priv)) { - IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); - if (priv->workqueue) - queue_delayed_work(priv->workqueue, - &priv->rf_kill, 2 * HZ); - goto exit_unlock; - } - - /* RF Kill is now disabled, so bring the device back up */ - - if (!(priv->status & STATUS_RF_KILL_MASK)) { - IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting " - "device\n"); - - /* we can not do an adapter restart while inside an irq lock */ - queue_work(priv->workqueue, &priv->adapter_restart); - } else - IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " - "enabled\n"); - - exit_unlock: - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void ipw_bg_rf_kill(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, rf_kill.work); - mutex_lock(&priv->mutex); - ipw_rf_kill(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_link_up(struct ipw_priv *priv) -{ - priv->last_seq_num = -1; - priv->last_frag_num = -1; - priv->last_packet_time = 0; - - netif_carrier_on(priv->net_dev); - - cancel_delayed_work(&priv->request_scan); - cancel_delayed_work(&priv->request_direct_scan); - cancel_delayed_work(&priv->request_passive_scan); - cancel_delayed_work(&priv->scan_event); - ipw_reset_stats(priv); - /* Ensure the rate is updated immediately */ - priv->last_rate = ipw_get_current_rate(priv); - ipw_gather_stats(priv); - ipw_led_link_up(priv); - notify_wx_assoc_event(priv); - - if (priv->config & CFG_BACKGROUND_SCAN) - queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); -} - -static void ipw_bg_link_up(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, link_up); - mutex_lock(&priv->mutex); - ipw_link_up(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_link_down(struct ipw_priv *priv) -{ - ipw_led_link_down(priv); - netif_carrier_off(priv->net_dev); - notify_wx_assoc_event(priv); - - /* Cancel any queued work ... */ - cancel_delayed_work(&priv->request_scan); - cancel_delayed_work(&priv->request_direct_scan); - cancel_delayed_work(&priv->request_passive_scan); - cancel_delayed_work(&priv->adhoc_check); - cancel_delayed_work(&priv->gather_stats); - - ipw_reset_stats(priv); - - if (!(priv->status & STATUS_EXIT_PENDING)) { - /* Queue up another scan... */ - queue_delayed_work(priv->workqueue, &priv->request_scan, 0); - } else - cancel_delayed_work(&priv->scan_event); -} - -static void ipw_bg_link_down(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, link_down); - mutex_lock(&priv->mutex); - ipw_link_down(priv); - mutex_unlock(&priv->mutex); -} - -static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) -{ - int ret = 0; - - priv->workqueue = create_workqueue(DRV_NAME); - init_waitqueue_head(&priv->wait_command_queue); - init_waitqueue_head(&priv->wait_state); - - INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check); - INIT_WORK(&priv->associate, ipw_bg_associate); - INIT_WORK(&priv->disassociate, ipw_bg_disassociate); - INIT_WORK(&priv->system_config, ipw_system_config); - INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish); - INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart); - INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill); - INIT_WORK(&priv->up, ipw_bg_up); - INIT_WORK(&priv->down, ipw_bg_down); - INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); - INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan); - INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan); - INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event); - INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); - INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); - INIT_WORK(&priv->roam, ipw_bg_roam); - INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check); - INIT_WORK(&priv->link_up, ipw_bg_link_up); - INIT_WORK(&priv->link_down, ipw_bg_link_down); - INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on); - INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off); - INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off); - INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network); - -#ifdef CONFIG_IPW2200_QOS - INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate); -#endif /* CONFIG_IPW2200_QOS */ - - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - ipw_irq_tasklet, (unsigned long)priv); - - return ret; -} - -static void shim__set_security(struct net_device *dev, - struct ieee80211_security *sec) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int i; - for (i = 0; i < 4; i++) { - if (sec->flags & (1 << i)) { - priv->ieee->sec.encode_alg[i] = sec->encode_alg[i]; - priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; - if (sec->key_sizes[i] == 0) - priv->ieee->sec.flags &= ~(1 << i); - else { - memcpy(priv->ieee->sec.keys[i], sec->keys[i], - sec->key_sizes[i]); - priv->ieee->sec.flags |= (1 << i); - } - priv->status |= STATUS_SECURITY_UPDATED; - } else if (sec->level != SEC_LEVEL_1) - priv->ieee->sec.flags &= ~(1 << i); - } - - if (sec->flags & SEC_ACTIVE_KEY) { - if (sec->active_key <= 3) { - priv->ieee->sec.active_key = sec->active_key; - priv->ieee->sec.flags |= SEC_ACTIVE_KEY; - } else - priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; - priv->status |= STATUS_SECURITY_UPDATED; - } else - priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; - - if ((sec->flags & SEC_AUTH_MODE) && - (priv->ieee->sec.auth_mode != sec->auth_mode)) { - priv->ieee->sec.auth_mode = sec->auth_mode; - priv->ieee->sec.flags |= SEC_AUTH_MODE; - if (sec->auth_mode == WLAN_AUTH_SHARED_KEY) - priv->capability |= CAP_SHARED_KEY; - else - priv->capability &= ~CAP_SHARED_KEY; - priv->status |= STATUS_SECURITY_UPDATED; - } - - if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) { - priv->ieee->sec.flags |= SEC_ENABLED; - priv->ieee->sec.enabled = sec->enabled; - priv->status |= STATUS_SECURITY_UPDATED; - if (sec->enabled) - priv->capability |= CAP_PRIVACY_ON; - else - priv->capability &= ~CAP_PRIVACY_ON; - } - - if (sec->flags & SEC_ENCRYPT) - priv->ieee->sec.encrypt = sec->encrypt; - - if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { - priv->ieee->sec.level = sec->level; - priv->ieee->sec.flags |= SEC_LEVEL; - priv->status |= STATUS_SECURITY_UPDATED; - } - - if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) - ipw_set_hwcrypto_keys(priv); - - /* To match current functionality of ipw2100 (which works well w/ - * various supplicants, we don't force a disassociate if the - * privacy capability changes ... */ -#if 0 - if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) && - (((priv->assoc_request.capability & - cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) || - (!(priv->assoc_request.capability & - cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) { - IPW_DEBUG_ASSOC("Disassociating due to capability " - "change.\n"); - ipw_disassociate(priv); - } -#endif -} - -static int init_supported_rates(struct ipw_priv *priv, - struct ipw_supported_rates *rates) -{ - /* TODO: Mask out rates based on priv->rates_mask */ - - memset(rates, 0, sizeof(*rates)); - /* configure supported rates */ - switch (priv->ieee->freq_band) { - case IEEE80211_52GHZ_BAND: - rates->ieee_mode = IPW_A_MODE; - rates->purpose = IPW_RATE_CAPABILITIES; - ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_OFDM_DEFAULT_RATES_MASK); - break; - - default: /* Mixed or 2.4Ghz */ - rates->ieee_mode = IPW_G_MODE; - rates->purpose = IPW_RATE_CAPABILITIES; - ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_CCK_DEFAULT_RATES_MASK); - if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) { - ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_OFDM_DEFAULT_RATES_MASK); - } - break; - } - - return 0; -} - -static int ipw_config(struct ipw_priv *priv) -{ - /* This is only called from ipw_up, which resets/reloads the firmware - so, we don't need to first disable the card before we configure - it */ - if (ipw_set_tx_power(priv)) - goto error; - - /* initialize adapter address */ - if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr)) - goto error; - - /* set basic system config settings */ - init_sys_config(&priv->sys_config); - - /* Support Bluetooth if we have BT h/w on board, and user wants to. - * Does not support BT priority yet (don't abort or defer our Tx) */ - if (bt_coexist) { - unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY]; - - if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG) - priv->sys_config.bt_coexistence - |= CFG_BT_COEXISTENCE_SIGNAL_CHNL; - if (bt_caps & EEPROM_SKU_CAP_BT_OOB) - priv->sys_config.bt_coexistence - |= CFG_BT_COEXISTENCE_OOB; - } - -#ifdef CONFIG_IPW2200_PROMISCUOUS - if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { - priv->sys_config.accept_all_data_frames = 1; - priv->sys_config.accept_non_directed_frames = 1; - priv->sys_config.accept_all_mgmt_bcpr = 1; - priv->sys_config.accept_all_mgmt_frames = 1; - } -#endif - - if (priv->ieee->iw_mode == IW_MODE_ADHOC) - priv->sys_config.answer_broadcast_ssid_probe = 1; - else - priv->sys_config.answer_broadcast_ssid_probe = 0; - - if (ipw_send_system_config(priv)) - goto error; - - init_supported_rates(priv, &priv->rates); - if (ipw_send_supported_rates(priv, &priv->rates)) - goto error; - - /* Set request-to-send threshold */ - if (priv->rts_threshold) { - if (ipw_send_rts_threshold(priv, priv->rts_threshold)) - goto error; - } -#ifdef CONFIG_IPW2200_QOS - IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n"); - ipw_qos_activate(priv, NULL); -#endif /* CONFIG_IPW2200_QOS */ - - if (ipw_set_random_seed(priv)) - goto error; - - /* final state transition to the RUN state */ - if (ipw_send_host_complete(priv)) - goto error; - - priv->status |= STATUS_INIT; - - ipw_led_init(priv); - ipw_led_radio_on(priv); - priv->notif_missed_beacons = 0; - - /* Set hardware WEP key if it is configured. */ - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.level == SEC_LEVEL_1) && - !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) - ipw_set_hwcrypto_keys(priv); - - return 0; - - error: - return -EIO; -} - -/* - * NOTE: - * - * These tables have been tested in conjunction with the - * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters. - * - * Altering this values, using it on other hardware, or in geographies - * not intended for resale of the above mentioned Intel adapters has - * not been tested. - * - * Remember to update the table in README.ipw2200 when changing this - * table. - * - */ -static const struct ieee80211_geo ipw_geos[] = { - { /* Restricted */ - "---", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - }, - - { /* Custom US/Canada */ - "ZZF", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - .a_channels = 8, - .a = {{5180, 36}, - {5200, 40}, - {5220, 44}, - {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, - }, - - { /* Rest of World */ - "ZZD", - .bg_channels = 13, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}}, - }, - - { /* Custom USA & Europe & High */ - "ZZA", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - .a_channels = 13, - .a = {{5180, 36}, - {5200, 40}, - {5220, 44}, - {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149}, - {5765, 153}, - {5785, 157}, - {5805, 161}, - {5825, 165}}, - }, - - { /* Custom NA & Europe */ - "ZZB", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - .a_channels = 13, - .a = {{5180, 36}, - {5200, 40}, - {5220, 44}, - {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, - }, - - { /* Custom Japan */ - "ZZC", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - .a_channels = 4, - .a = {{5170, 34}, {5190, 38}, - {5210, 42}, {5230, 46}}, - }, - - { /* Custom */ - "ZZM", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - }, - - { /* Europe */ - "ZZE", - .bg_channels = 13, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}}, - .a_channels = 19, - .a = {{5180, 36}, - {5200, 40}, - {5220, 44}, - {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, - {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, - {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, - {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, - {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, - {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, - {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, - {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, - {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, - {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, - {5700, 140, IEEE80211_CH_PASSIVE_ONLY}}, - }, - - { /* Custom Japan */ - "ZZJ", - .bg_channels = 14, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}}, - .a_channels = 4, - .a = {{5170, 34}, {5190, 38}, - {5210, 42}, {5230, 46}}, - }, - - { /* Rest of World */ - "ZZR", - .bg_channels = 14, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY | - IEEE80211_CH_PASSIVE_ONLY}}, - }, - - { /* High Band */ - "ZZH", - .bg_channels = 13, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, - {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, - {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, - .a_channels = 4, - .a = {{5745, 149}, {5765, 153}, - {5785, 157}, {5805, 161}}, - }, - - { /* Custom Europe */ - "ZZG", - .bg_channels = 13, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, - {2467, 12}, {2472, 13}}, - .a_channels = 4, - .a = {{5180, 36}, {5200, 40}, - {5220, 44}, {5240, 48}}, - }, - - { /* Europe */ - "ZZK", - .bg_channels = 13, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}, - {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, - {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, - .a_channels = 24, - .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, - {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, - {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, - {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, - {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, - {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, - {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, - {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, - {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, - {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, - {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, - {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, - {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, - {5700, 140, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, - }, - - { /* Europe */ - "ZZL", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - .a_channels = 13, - .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, - {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, - {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, - {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, - } -}; - -#define MAX_HW_RESTARTS 5 -static int ipw_up(struct ipw_priv *priv) -{ - int rc, i, j; - - if (priv->status & STATUS_EXIT_PENDING) - return -EIO; - - if (cmdlog && !priv->cmdlog) { - priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog), - GFP_KERNEL); - if (priv->cmdlog == NULL) { - IPW_ERROR("Error allocating %d command log entries.\n", - cmdlog); - return -ENOMEM; - } else { - priv->cmdlog_len = cmdlog; - } - } - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - /* Load the microcode, firmware, and eeprom. - * Also start the clocks. */ - rc = ipw_load(priv); - if (rc) { - IPW_ERROR("Unable to load firmware: %d\n", rc); - return rc; - } - - ipw_init_ordinals(priv); - if (!(priv->config & CFG_CUSTOM_MAC)) - eeprom_parse_mac(priv, priv->mac_addr); - memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - - for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { - if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], - ipw_geos[j].name, 3)) - break; - } - if (j == ARRAY_SIZE(ipw_geos)) { - IPW_WARNING("SKU [%c%c%c] not recognized.\n", - priv->eeprom[EEPROM_COUNTRY_CODE + 0], - priv->eeprom[EEPROM_COUNTRY_CODE + 1], - priv->eeprom[EEPROM_COUNTRY_CODE + 2]); - j = 0; - } - if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { - IPW_WARNING("Could not set geography."); - return 0; - } - - if (priv->status & STATUS_RF_KILL_SW) { - IPW_WARNING("Radio disabled by module parameter.\n"); - return 0; - } else if (rf_kill_active(priv)) { - IPW_WARNING("Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - queue_delayed_work(priv->workqueue, &priv->rf_kill, - 2 * HZ); - return 0; - } - - rc = ipw_config(priv); - if (!rc) { - IPW_DEBUG_INFO("Configured device on count %i\n", i); - - /* If configure to try and auto-associate, kick - * off a scan. */ - queue_delayed_work(priv->workqueue, - &priv->request_scan, 0); - - return 0; - } - - IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc); - IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n", - i, MAX_HW_RESTARTS); - - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - ipw_down(priv); - } - - /* tried to restart and config the device for as long as our - * patience could withstand */ - IPW_ERROR("Unable to initialize device after %d attempts.\n", i); - - return -EIO; -} - -static void ipw_bg_up(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, up); - mutex_lock(&priv->mutex); - ipw_up(priv); - mutex_unlock(&priv->mutex); -} - -static void ipw_deinit(struct ipw_priv *priv) -{ - int i; - - if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_INFO("Aborting scan during shutdown.\n"); - ipw_abort_scan(priv); - } - - if (priv->status & STATUS_ASSOCIATED) { - IPW_DEBUG_INFO("Disassociating during shutdown.\n"); - ipw_disassociate(priv); - } - - ipw_led_shutdown(priv); - - /* Wait up to 1s for status to change to not scanning and not - * associated (disassociation can take a while for a ful 802.11 - * exchange */ - for (i = 1000; i && (priv->status & - (STATUS_DISASSOCIATING | - STATUS_ASSOCIATED | STATUS_SCANNING)); i--) - udelay(10); - - if (priv->status & (STATUS_DISASSOCIATING | - STATUS_ASSOCIATED | STATUS_SCANNING)) - IPW_DEBUG_INFO("Still associated or scanning...\n"); - else - IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i); - - /* Attempt to disable the card */ - ipw_send_card_disable(priv, 0); - - priv->status &= ~STATUS_INIT; -} - -static void ipw_down(struct ipw_priv *priv) -{ - int exit_pending = priv->status & STATUS_EXIT_PENDING; - - priv->status |= STATUS_EXIT_PENDING; - - if (ipw_is_init(priv)) - ipw_deinit(priv); - - /* Wipe out the EXIT_PENDING status bit if we are not actually - * exiting the module */ - if (!exit_pending) - priv->status &= ~STATUS_EXIT_PENDING; - - /* tell the device to stop sending interrupts */ - ipw_disable_interrupts(priv); - - /* Clear all bits but the RF Kill */ - priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING; - netif_carrier_off(priv->net_dev); - - ipw_stop_nic(priv); - - ipw_led_radio_off(priv); -} - -static void ipw_bg_down(struct work_struct *work) -{ - struct ipw_priv *priv = - container_of(work, struct ipw_priv, down); - mutex_lock(&priv->mutex); - ipw_down(priv); - mutex_unlock(&priv->mutex); -} - -/* Called by register_netdev() */ -static int ipw_net_init(struct net_device *dev) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - mutex_lock(&priv->mutex); - - if (ipw_up(priv)) { - mutex_unlock(&priv->mutex); - return -EIO; - } - - mutex_unlock(&priv->mutex); - return 0; -} - -/* PCI driver stuff */ -static struct pci_device_id card_ids[] = { - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ - {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ - - /* required last entry */ - {0,} -}; - -MODULE_DEVICE_TABLE(pci, card_ids); - -static struct attribute *ipw_sysfs_entries[] = { - &dev_attr_rf_kill.attr, - &dev_attr_direct_dword.attr, - &dev_attr_indirect_byte.attr, - &dev_attr_indirect_dword.attr, - &dev_attr_mem_gpio_reg.attr, - &dev_attr_command_event_reg.attr, - &dev_attr_nic_type.attr, - &dev_attr_status.attr, - &dev_attr_cfg.attr, - &dev_attr_error.attr, - &dev_attr_event_log.attr, - &dev_attr_cmd_log.attr, - &dev_attr_eeprom_delay.attr, - &dev_attr_ucode_version.attr, - &dev_attr_rtc.attr, - &dev_attr_scan_age.attr, - &dev_attr_led.attr, - &dev_attr_speed_scan.attr, - &dev_attr_net_stats.attr, - &dev_attr_channels.attr, -#ifdef CONFIG_IPW2200_PROMISCUOUS - &dev_attr_rtap_iface.attr, - &dev_attr_rtap_filter.attr, -#endif - NULL -}; - -static struct attribute_group ipw_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = ipw_sysfs_entries, -}; - -#ifdef CONFIG_IPW2200_PROMISCUOUS -static int ipw_prom_open(struct net_device *dev) -{ - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); - struct ipw_priv *priv = prom_priv->priv; - - IPW_DEBUG_INFO("prom dev->open\n"); - netif_carrier_off(dev); - - if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - priv->sys_config.accept_all_data_frames = 1; - priv->sys_config.accept_non_directed_frames = 1; - priv->sys_config.accept_all_mgmt_bcpr = 1; - priv->sys_config.accept_all_mgmt_frames = 1; - - ipw_send_system_config(priv); - } - - return 0; -} - -static int ipw_prom_stop(struct net_device *dev) -{ - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); - struct ipw_priv *priv = prom_priv->priv; - - IPW_DEBUG_INFO("prom dev->stop\n"); - - if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - priv->sys_config.accept_all_data_frames = 0; - priv->sys_config.accept_non_directed_frames = 0; - priv->sys_config.accept_all_mgmt_bcpr = 0; - priv->sys_config.accept_all_mgmt_frames = 0; - - ipw_send_system_config(priv); - } - - return 0; -} - -static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - IPW_DEBUG_INFO("prom dev->xmit\n"); - return -EOPNOTSUPP; -} - -static struct net_device_stats *ipw_prom_get_stats(struct net_device *dev) -{ - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); - return &prom_priv->ieee->stats; -} - -static int ipw_prom_alloc(struct ipw_priv *priv) -{ - int rc = 0; - - if (priv->prom_net_dev) - return -EPERM; - - priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); - if (priv->prom_net_dev == NULL) - return -ENOMEM; - - priv->prom_priv = ieee80211_priv(priv->prom_net_dev); - priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev); - priv->prom_priv->priv = priv; - - strcpy(priv->prom_net_dev->name, "rtap%d"); - memcpy(priv->prom_net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - - priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; - priv->prom_net_dev->open = ipw_prom_open; - priv->prom_net_dev->stop = ipw_prom_stop; - priv->prom_net_dev->get_stats = ipw_prom_get_stats; - priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit; - - priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR; - SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev); - - rc = register_netdev(priv->prom_net_dev); - if (rc) { - free_ieee80211(priv->prom_net_dev); - priv->prom_net_dev = NULL; - return rc; - } - - return 0; -} - -static void ipw_prom_free(struct ipw_priv *priv) -{ - if (!priv->prom_net_dev) - return; - - unregister_netdev(priv->prom_net_dev); - free_ieee80211(priv->prom_net_dev); - - priv->prom_net_dev = NULL; -} - -#endif - - -static int __devinit ipw_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int err = 0; - struct net_device *net_dev; - void __iomem *base; - u32 length, val; - struct ipw_priv *priv; - int i; - - net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); - if (net_dev == NULL) { - err = -ENOMEM; - goto out; - } - - priv = ieee80211_priv(net_dev); - priv->ieee = netdev_priv(net_dev); - - priv->net_dev = net_dev; - priv->pci_dev = pdev; - ipw_debug_level = debug; - spin_lock_init(&priv->irq_lock); - spin_lock_init(&priv->lock); - for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - - mutex_init(&priv->mutex); - if (pci_enable_device(pdev)) { - err = -ENODEV; - goto out_free_ieee80211; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (err) { - printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); - goto out_pci_disable_device; - } - - pci_set_drvdata(pdev, priv); - - err = pci_request_regions(pdev, DRV_NAME); - if (err) - goto out_pci_disable_device; - - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - - length = pci_resource_len(pdev, 0); - priv->hw_len = length; - - base = pci_ioremap_bar(pdev, 0); - if (!base) { - err = -ENODEV; - goto out_pci_release_regions; - } - - priv->hw_base = base; - IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length); - IPW_DEBUG_INFO("pci_resource_base = %p\n", base); - - err = ipw_setup_deferred_work(priv); - if (err) { - IPW_ERROR("Unable to setup deferred work\n"); - goto out_iounmap; - } - - ipw_sw_reset(priv, 1); - - err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv); - if (err) { - IPW_ERROR("Error allocating IRQ %d\n", pdev->irq); - goto out_destroy_workqueue; - } - - SET_NETDEV_DEV(net_dev, &pdev->dev); - - mutex_lock(&priv->mutex); - - priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; - priv->ieee->set_security = shim__set_security; - priv->ieee->is_queue_full = ipw_net_is_queue_full; - -#ifdef CONFIG_IPW2200_QOS - priv->ieee->is_qos_active = ipw_is_qos_active; - priv->ieee->handle_probe_response = ipw_handle_beacon; - priv->ieee->handle_beacon = ipw_handle_probe_response; - priv->ieee->handle_assoc_response = ipw_handle_assoc_response; -#endif /* CONFIG_IPW2200_QOS */ - - priv->ieee->perfect_rssi = -20; - priv->ieee->worst_rssi = -85; - - net_dev->open = ipw_net_open; - net_dev->stop = ipw_net_stop; - net_dev->init = ipw_net_init; - net_dev->get_stats = ipw_net_get_stats; - net_dev->set_multicast_list = ipw_net_set_multicast_list; - net_dev->set_mac_address = ipw_net_set_mac_address; - priv->wireless_data.spy_data = &priv->ieee->spy_data; - net_dev->wireless_data = &priv->wireless_data; - net_dev->wireless_handlers = &ipw_wx_handler_def; - net_dev->ethtool_ops = &ipw_ethtool_ops; - net_dev->irq = pdev->irq; - net_dev->base_addr = (unsigned long)priv->hw_base; - net_dev->mem_start = pci_resource_start(pdev, 0); - net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1; - - err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); - if (err) { - IPW_ERROR("failed to create sysfs device attributes\n"); - mutex_unlock(&priv->mutex); - goto out_release_irq; - } - - mutex_unlock(&priv->mutex); - err = register_netdev(net_dev); - if (err) { - IPW_ERROR("failed to register network device\n"); - goto out_remove_sysfs; - } - -#ifdef CONFIG_IPW2200_PROMISCUOUS - if (rtap_iface) { - err = ipw_prom_alloc(priv); - if (err) { - IPW_ERROR("Failed to register promiscuous network " - "device (error %d).\n", err); - unregister_netdev(priv->net_dev); - goto out_remove_sysfs; - } - } -#endif - - printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg " - "channels, %d 802.11a channels)\n", - priv->ieee->geo.name, priv->ieee->geo.bg_channels, - priv->ieee->geo.a_channels); - - return 0; - - out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); - out_release_irq: - free_irq(pdev->irq, priv); - out_destroy_workqueue: - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - out_iounmap: - iounmap(priv->hw_base); - out_pci_release_regions: - pci_release_regions(pdev); - out_pci_disable_device: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - out_free_ieee80211: - free_ieee80211(priv->net_dev); - out: - return err; -} - -static void __devexit ipw_pci_remove(struct pci_dev *pdev) -{ - struct ipw_priv *priv = pci_get_drvdata(pdev); - struct list_head *p, *q; - int i; - - if (!priv) - return; - - mutex_lock(&priv->mutex); - - priv->status |= STATUS_EXIT_PENDING; - ipw_down(priv); - sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); - - mutex_unlock(&priv->mutex); - - unregister_netdev(priv->net_dev); - - if (priv->rxq) { - ipw_rx_queue_free(priv, priv->rxq); - priv->rxq = NULL; - } - ipw_tx_queue_free(priv); - - if (priv->cmdlog) { - kfree(priv->cmdlog); - priv->cmdlog = NULL; - } - /* ipw_down will ensure that there is no more pending work - * in the workqueue's, so we can safely remove them now. */ - cancel_delayed_work(&priv->adhoc_check); - cancel_delayed_work(&priv->gather_stats); - cancel_delayed_work(&priv->request_scan); - cancel_delayed_work(&priv->request_direct_scan); - cancel_delayed_work(&priv->request_passive_scan); - cancel_delayed_work(&priv->scan_event); - cancel_delayed_work(&priv->rf_kill); - cancel_delayed_work(&priv->scan_check); - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - - /* Free MAC hash list for ADHOC */ - for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) { - list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { - list_del(p); - kfree(list_entry(p, struct ipw_ibss_seq, list)); - } - } - - kfree(priv->error); - priv->error = NULL; - -#ifdef CONFIG_IPW2200_PROMISCUOUS - ipw_prom_free(priv); -#endif - - free_irq(pdev->irq, priv); - iounmap(priv->hw_base); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - free_ieee80211(priv->net_dev); - free_firmware(); -} - -#ifdef CONFIG_PM -static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct ipw_priv *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->net_dev; - - printk(KERN_INFO "%s: Going into suspend...\n", dev->name); - - /* Take down the device; powers it off, etc. */ - ipw_down(priv); - - /* Remove the PRESENT state of the device */ - netif_device_detach(dev); - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -static int ipw_pci_resume(struct pci_dev *pdev) -{ - struct ipw_priv *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->net_dev; - int err; - u32 val; - - printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); - - pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - return err; - } - pci_restore_state(pdev); - - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries - * from interfering with C3 CPU state. pci_restore_state won't help - * here since it only restores the first 64 bytes pci config header. - */ - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - - /* Set the device back into the PRESENT state; this will also wake - * the queue of needed */ - netif_device_attach(dev); - - /* Bring the device back up */ - queue_work(priv->workqueue, &priv->up); - - return 0; -} -#endif - -static void ipw_pci_shutdown(struct pci_dev *pdev) -{ - struct ipw_priv *priv = pci_get_drvdata(pdev); - - /* Take down the device; powers it off, etc. */ - ipw_down(priv); - - pci_disable_device(pdev); -} - -/* driver initialization stuff */ -static struct pci_driver ipw_driver = { - .name = DRV_NAME, - .id_table = card_ids, - .probe = ipw_pci_probe, - .remove = __devexit_p(ipw_pci_remove), -#ifdef CONFIG_PM - .suspend = ipw_pci_suspend, - .resume = ipw_pci_resume, -#endif - .shutdown = ipw_pci_shutdown, -}; - -static int __init ipw_init(void) -{ - int ret; - - printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); - printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); - - ret = pci_register_driver(&ipw_driver); - if (ret) { - IPW_ERROR("Unable to initialize PCI module\n"); - return ret; - } - - ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level); - if (ret) { - IPW_ERROR("Unable to create driver sysfs file\n"); - pci_unregister_driver(&ipw_driver); - return ret; - } - - return ret; -} - -static void __exit ipw_exit(void) -{ - driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level); - pci_unregister_driver(&ipw_driver); -} - -module_param(disable, int, 0444); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); - -module_param(associate, int, 0444); -MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); - -module_param(auto_create, int, 0444); -MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); - -module_param(led, int, 0444); -MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)"); - -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "debug output mask"); - -module_param(channel, int, 0444); -MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); - -#ifdef CONFIG_IPW2200_PROMISCUOUS -module_param(rtap_iface, int, 0444); -MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)"); -#endif - -#ifdef CONFIG_IPW2200_QOS -module_param(qos_enable, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); - -module_param(qos_burst_enable, int, 0444); -MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode"); - -module_param(qos_no_ack_mask, int, 0444); -MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack"); - -module_param(burst_duration_CCK, int, 0444); -MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value"); - -module_param(burst_duration_OFDM, int, 0444); -MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); -#endif /* CONFIG_IPW2200_QOS */ - -#ifdef CONFIG_IPW2200_MONITOR -module_param(mode, int, 0444); -MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); -#else -module_param(mode, int, 0444); -MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); -#endif - -module_param(bt_coexist, int, 0444); -MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)"); - -module_param(hwcrypto, int, 0444); -MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)"); - -module_param(cmdlog, int, 0444); -MODULE_PARM_DESC(cmdlog, - "allocate a ring buffer for logging firmware commands"); - -module_param(roaming, int, 0444); -MODULE_PARM_DESC(roaming, "enable roaming support (default on)"); - -module_param(antenna, int, 0444); -MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)"); - -module_exit(ipw_exit); -module_init(ipw_init); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h deleted file mode 100644 index 0a84d52..0000000 --- a/drivers/net/wireless/ipw2200.h +++ /dev/null @@ -1,2011 +0,0 @@ -/****************************************************************************** - - Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - 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; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - James P. Ketrenos - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -******************************************************************************/ - -#ifndef __ipw2200_h__ -#define __ipw2200_h__ - -#define WEXT_USECHANNELS 1 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#define DRV_NAME "ipw2200" - -#include - -/* Authentication and Association States */ -enum connection_manager_assoc_states { - CMAS_INIT = 0, - CMAS_TX_AUTH_SEQ_1, - CMAS_RX_AUTH_SEQ_2, - CMAS_AUTH_SEQ_1_PASS, - CMAS_AUTH_SEQ_1_FAIL, - CMAS_TX_AUTH_SEQ_3, - CMAS_RX_AUTH_SEQ_4, - CMAS_AUTH_SEQ_2_PASS, - CMAS_AUTH_SEQ_2_FAIL, - CMAS_AUTHENTICATED, - CMAS_TX_ASSOC, - CMAS_RX_ASSOC_RESP, - CMAS_ASSOCIATED, - CMAS_LAST -}; - -#define IPW_WAIT (1<<0) -#define IPW_QUIET (1<<1) -#define IPW_ROAMING (1<<2) - -#define IPW_POWER_MODE_CAM 0x00 //(always on) -#define IPW_POWER_INDEX_1 0x01 -#define IPW_POWER_INDEX_2 0x02 -#define IPW_POWER_INDEX_3 0x03 -#define IPW_POWER_INDEX_4 0x04 -#define IPW_POWER_INDEX_5 0x05 -#define IPW_POWER_AC 0x06 -#define IPW_POWER_BATTERY 0x07 -#define IPW_POWER_LIMIT 0x07 -#define IPW_POWER_MASK 0x0F -#define IPW_POWER_ENABLED 0x10 -#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK) - -#define IPW_CMD_HOST_COMPLETE 2 -#define IPW_CMD_POWER_DOWN 4 -#define IPW_CMD_SYSTEM_CONFIG 6 -#define IPW_CMD_MULTICAST_ADDRESS 7 -#define IPW_CMD_SSID 8 -#define IPW_CMD_ADAPTER_ADDRESS 11 -#define IPW_CMD_PORT_TYPE 12 -#define IPW_CMD_RTS_THRESHOLD 15 -#define IPW_CMD_FRAG_THRESHOLD 16 -#define IPW_CMD_POWER_MODE 17 -#define IPW_CMD_WEP_KEY 18 -#define IPW_CMD_TGI_TX_KEY 19 -#define IPW_CMD_SCAN_REQUEST 20 -#define IPW_CMD_ASSOCIATE 21 -#define IPW_CMD_SUPPORTED_RATES 22 -#define IPW_CMD_SCAN_ABORT 23 -#define IPW_CMD_TX_FLUSH 24 -#define IPW_CMD_QOS_PARAMETERS 25 -#define IPW_CMD_SCAN_REQUEST_EXT 26 -#define IPW_CMD_DINO_CONFIG 30 -#define IPW_CMD_RSN_CAPABILITIES 31 -#define IPW_CMD_RX_KEY 32 -#define IPW_CMD_CARD_DISABLE 33 -#define IPW_CMD_SEED_NUMBER 34 -#define IPW_CMD_TX_POWER 35 -#define IPW_CMD_COUNTRY_INFO 36 -#define IPW_CMD_AIRONET_INFO 37 -#define IPW_CMD_AP_TX_POWER 38 -#define IPW_CMD_CCKM_INFO 39 -#define IPW_CMD_CCX_VER_INFO 40 -#define IPW_CMD_SET_CALIBRATION 41 -#define IPW_CMD_SENSITIVITY_CALIB 42 -#define IPW_CMD_RETRY_LIMIT 51 -#define IPW_CMD_IPW_PRE_POWER_DOWN 58 -#define IPW_CMD_VAP_BEACON_TEMPLATE 60 -#define IPW_CMD_VAP_DTIM_PERIOD 61 -#define IPW_CMD_EXT_SUPPORTED_RATES 62 -#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63 -#define IPW_CMD_VAP_QUIET_INTERVALS 64 -#define IPW_CMD_VAP_CHANNEL_SWITCH 65 -#define IPW_CMD_VAP_MANDATORY_CHANNELS 66 -#define IPW_CMD_VAP_CELL_PWR_LIMIT 67 -#define IPW_CMD_VAP_CF_PARAM_SET 68 -#define IPW_CMD_VAP_SET_BEACONING_STATE 69 -#define IPW_CMD_MEASUREMENT 80 -#define IPW_CMD_POWER_CAPABILITY 81 -#define IPW_CMD_SUPPORTED_CHANNELS 82 -#define IPW_CMD_TPC_REPORT 83 -#define IPW_CMD_WME_INFO 84 -#define IPW_CMD_PRODUCTION_COMMAND 85 -#define IPW_CMD_LINKSYS_EOU_INFO 90 - -#define RFD_SIZE 4 -#define NUM_TFD_CHUNKS 6 - -#define TX_QUEUE_SIZE 32 -#define RX_QUEUE_SIZE 32 - -#define DINO_CMD_WEP_KEY 0x08 -#define DINO_CMD_TX 0x0B -#define DCT_ANTENNA_A 0x01 -#define DCT_ANTENNA_B 0x02 - -#define IPW_A_MODE 0 -#define IPW_B_MODE 1 -#define IPW_G_MODE 2 - -/* - * TX Queue Flag Definitions - */ - -/* tx wep key definition */ -#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00 -#define DCT_WEP_KEY_64Bit 0x40 -#define DCT_WEP_KEY_128Bit 0x80 -#define DCT_WEP_KEY_128bitIV 0xC0 -#define DCT_WEP_KEY_SIZE_MASK 0xC0 - -#define DCT_WEP_KEY_INDEX_MASK 0x0F -#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20 - -/* abort attempt if mgmt frame is rx'd */ -#define DCT_FLAG_ABORT_MGMT 0x01 - -/* require CTS */ -#define DCT_FLAG_CTS_REQUIRED 0x02 - -/* use short preamble */ -#define DCT_FLAG_LONG_PREAMBLE 0x00 -#define DCT_FLAG_SHORT_PREAMBLE 0x04 - -/* RTS/CTS first */ -#define DCT_FLAG_RTS_REQD 0x08 - -/* dont calculate duration field */ -#define DCT_FLAG_DUR_SET 0x10 - -/* even if MAC WEP set (allows pre-encrypt) */ -#define DCT_FLAG_NO_WEP 0x20 - -/* overwrite TSF field */ -#define DCT_FLAG_TSF_REQD 0x40 - -/* ACK rx is expected to follow */ -#define DCT_FLAG_ACK_REQD 0x80 - -/* TX flags extension */ -#define DCT_FLAG_EXT_MODE_CCK 0x01 -#define DCT_FLAG_EXT_MODE_OFDM 0x00 - -#define DCT_FLAG_EXT_SECURITY_WEP 0x00 -#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP -#define DCT_FLAG_EXT_SECURITY_CKIP 0x04 -#define DCT_FLAG_EXT_SECURITY_CCM 0x08 -#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C -#define DCT_FLAG_EXT_SECURITY_MASK 0x0C - -#define DCT_FLAG_EXT_QOS_ENABLED 0x10 - -#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00 -#define DCT_FLAG_EXT_HC_SIFS 0x20 -#define DCT_FLAG_EXT_HC_PIFS 0x40 - -#define TX_RX_TYPE_MASK 0xFF -#define TX_FRAME_TYPE 0x00 -#define TX_HOST_COMMAND_TYPE 0x01 -#define RX_FRAME_TYPE 0x09 -#define RX_HOST_NOTIFICATION_TYPE 0x03 -#define RX_HOST_CMD_RESPONSE_TYPE 0x04 -#define RX_TX_FRAME_RESPONSE_TYPE 0x05 -#define TFD_NEED_IRQ_MASK 0x04 - -#define HOST_CMD_DINO_CONFIG 30 - -#define HOST_NOTIFICATION_STATUS_ASSOCIATED 10 -#define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11 -#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12 -#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13 -#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14 -#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15 -#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16 -#define HOST_NOTIFICATION_STATUS_BEACON_STATE 17 -#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18 -#define HOST_NOTIFICATION_TX_STATUS 19 -#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20 -#define HOST_NOTIFICATION_MEASUREMENT_STARTED 21 -#define HOST_NOTIFICATION_MEASUREMENT_ENDED 22 -#define HOST_NOTIFICATION_CHANNEL_SWITCHED 23 -#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24 -#define HOST_NOTIFICATION_NOISE_STATS 25 -#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30 -#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 - -#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 -#define IPW_MB_ROAMING_THRESHOLD_MIN 1 -#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 -#define IPW_MB_ROAMING_THRESHOLD_MAX 30 -#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 3*IPW_MB_ROAMING_THRESHOLD_DEFAULT -#define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300 - -#define MACADRR_BYTE_LEN 6 - -#define DCR_TYPE_AP 0x01 -#define DCR_TYPE_WLAP 0x02 -#define DCR_TYPE_MU_ESS 0x03 -#define DCR_TYPE_MU_IBSS 0x04 -#define DCR_TYPE_MU_PIBSS 0x05 -#define DCR_TYPE_SNIFFER 0x06 -#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS - -/* QoS definitions */ - -#define CW_MIN_OFDM 15 -#define CW_MAX_OFDM 1023 -#define CW_MIN_CCK 31 -#define CW_MAX_CCK 1023 - -#define QOS_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) -#define QOS_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) -#define QOS_TX2_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1) -#define QOS_TX3_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1) - -#define QOS_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) -#define QOS_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) -#define QOS_TX2_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1) -#define QOS_TX3_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/4 - 1) - -#define QOS_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) -#define QOS_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) -#define QOS_TX2_CW_MAX_OFDM cpu_to_le16(CW_MIN_OFDM) -#define QOS_TX3_CW_MAX_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1) - -#define QOS_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) -#define QOS_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) -#define QOS_TX2_CW_MAX_CCK cpu_to_le16(CW_MIN_CCK) -#define QOS_TX3_CW_MAX_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1) - -#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE) -#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE) -#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE) -#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE) - -#define QOS_TX0_ACM 0 -#define QOS_TX1_ACM 0 -#define QOS_TX2_ACM 0 -#define QOS_TX3_ACM 0 - -#define QOS_TX0_TXOP_LIMIT_CCK 0 -#define QOS_TX1_TXOP_LIMIT_CCK 0 -#define QOS_TX2_TXOP_LIMIT_CCK cpu_to_le16(6016) -#define QOS_TX3_TXOP_LIMIT_CCK cpu_to_le16(3264) - -#define QOS_TX0_TXOP_LIMIT_OFDM 0 -#define QOS_TX1_TXOP_LIMIT_OFDM 0 -#define QOS_TX2_TXOP_LIMIT_OFDM cpu_to_le16(3008) -#define QOS_TX3_TXOP_LIMIT_OFDM cpu_to_le16(1504) - -#define DEF_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) -#define DEF_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) -#define DEF_TX2_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) -#define DEF_TX3_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) - -#define DEF_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) -#define DEF_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) -#define DEF_TX2_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) -#define DEF_TX3_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) - -#define DEF_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) -#define DEF_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) -#define DEF_TX2_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) -#define DEF_TX3_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) - -#define DEF_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) -#define DEF_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) -#define DEF_TX2_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) -#define DEF_TX3_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) - -#define DEF_TX0_AIFS 0 -#define DEF_TX1_AIFS 0 -#define DEF_TX2_AIFS 0 -#define DEF_TX3_AIFS 0 - -#define DEF_TX0_ACM 0 -#define DEF_TX1_ACM 0 -#define DEF_TX2_ACM 0 -#define DEF_TX3_ACM 0 - -#define DEF_TX0_TXOP_LIMIT_CCK 0 -#define DEF_TX1_TXOP_LIMIT_CCK 0 -#define DEF_TX2_TXOP_LIMIT_CCK 0 -#define DEF_TX3_TXOP_LIMIT_CCK 0 - -#define DEF_TX0_TXOP_LIMIT_OFDM 0 -#define DEF_TX1_TXOP_LIMIT_OFDM 0 -#define DEF_TX2_TXOP_LIMIT_OFDM 0 -#define DEF_TX3_TXOP_LIMIT_OFDM 0 - -#define QOS_QOS_SETS 3 -#define QOS_PARAM_SET_ACTIVE 0 -#define QOS_PARAM_SET_DEF_CCK 1 -#define QOS_PARAM_SET_DEF_OFDM 2 - -#define CTRL_QOS_NO_ACK (0x0020) - -#define IPW_TX_QUEUE_1 1 -#define IPW_TX_QUEUE_2 2 -#define IPW_TX_QUEUE_3 3 -#define IPW_TX_QUEUE_4 4 - -/* QoS sturctures */ -struct ipw_qos_info { - int qos_enable; - struct ieee80211_qos_parameters *def_qos_parm_OFDM; - struct ieee80211_qos_parameters *def_qos_parm_CCK; - u32 burst_duration_CCK; - u32 burst_duration_OFDM; - u16 qos_no_ack_mask; - int burst_enable; -}; - -/**************************************************************/ -/** - * Generic queue structure - * - * Contains common data for Rx and Tx queues - */ -struct clx2_queue { - int n_bd; /**< number of BDs in this queue */ - int first_empty; /**< 1-st empty entry (index) */ - int last_used; /**< last used entry (index) */ - u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */ - u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */ - dma_addr_t dma_addr; /**< physical addr for BD's */ - int low_mark; /**< low watermark, resume queue if free space more than this */ - int high_mark; /**< high watermark, stop queue if free space less than this */ -} __attribute__ ((packed)); /* XXX */ - -struct machdr32 { - __le16 frame_ctl; - __le16 duration; // watch out for endians! - u8 addr1[MACADRR_BYTE_LEN]; - u8 addr2[MACADRR_BYTE_LEN]; - u8 addr3[MACADRR_BYTE_LEN]; - __le16 seq_ctrl; // more endians! - u8 addr4[MACADRR_BYTE_LEN]; - __le16 qos_ctrl; -} __attribute__ ((packed)); - -struct machdr30 { - __le16 frame_ctl; - __le16 duration; // watch out for endians! - u8 addr1[MACADRR_BYTE_LEN]; - u8 addr2[MACADRR_BYTE_LEN]; - u8 addr3[MACADRR_BYTE_LEN]; - __le16 seq_ctrl; // more endians! - u8 addr4[MACADRR_BYTE_LEN]; -} __attribute__ ((packed)); - -struct machdr26 { - __le16 frame_ctl; - __le16 duration; // watch out for endians! - u8 addr1[MACADRR_BYTE_LEN]; - u8 addr2[MACADRR_BYTE_LEN]; - u8 addr3[MACADRR_BYTE_LEN]; - __le16 seq_ctrl; // more endians! - __le16 qos_ctrl; -} __attribute__ ((packed)); - -struct machdr24 { - __le16 frame_ctl; - __le16 duration; // watch out for endians! - u8 addr1[MACADRR_BYTE_LEN]; - u8 addr2[MACADRR_BYTE_LEN]; - u8 addr3[MACADRR_BYTE_LEN]; - __le16 seq_ctrl; // more endians! -} __attribute__ ((packed)); - -// TX TFD with 32 byte MAC Header -struct tx_tfd_32 { - struct machdr32 mchdr; // 32 - __le32 uivplaceholder[2]; // 8 -} __attribute__ ((packed)); - -// TX TFD with 30 byte MAC Header -struct tx_tfd_30 { - struct machdr30 mchdr; // 30 - u8 reserved[2]; // 2 - __le32 uivplaceholder[2]; // 8 -} __attribute__ ((packed)); - -// tx tfd with 26 byte mac header -struct tx_tfd_26 { - struct machdr26 mchdr; // 26 - u8 reserved1[2]; // 2 - __le32 uivplaceholder[2]; // 8 - u8 reserved2[4]; // 4 -} __attribute__ ((packed)); - -// tx tfd with 24 byte mac header -struct tx_tfd_24 { - struct machdr24 mchdr; // 24 - __le32 uivplaceholder[2]; // 8 - u8 reserved[8]; // 8 -} __attribute__ ((packed)); - -#define DCT_WEP_KEY_FIELD_LENGTH 16 - -struct tfd_command { - u8 index; - u8 length; - __le16 reserved; - u8 payload[0]; -} __attribute__ ((packed)); - -struct tfd_data { - /* Header */ - __le32 work_area_ptr; - u8 station_number; /* 0 for BSS */ - u8 reserved1; - __le16 reserved2; - - /* Tx Parameters */ - u8 cmd_id; - u8 seq_num; - __le16 len; - u8 priority; - u8 tx_flags; - u8 tx_flags_ext; - u8 key_index; - u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH]; - u8 rate; - u8 antenna; - __le16 next_packet_duration; - __le16 next_frag_len; - __le16 back_off_counter; //////txop; - u8 retrylimit; - __le16 cwcurrent; - u8 reserved3; - - /* 802.11 MAC Header */ - union { - struct tx_tfd_24 tfd_24; - struct tx_tfd_26 tfd_26; - struct tx_tfd_30 tfd_30; - struct tx_tfd_32 tfd_32; - } tfd; - - /* Payload DMA info */ - __le32 num_chunks; - __le32 chunk_ptr[NUM_TFD_CHUNKS]; - __le16 chunk_len[NUM_TFD_CHUNKS]; -} __attribute__ ((packed)); - -struct txrx_control_flags { - u8 message_type; - u8 rx_seq_num; - u8 control_bits; - u8 reserved; -} __attribute__ ((packed)); - -#define TFD_SIZE 128 -#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags)) - -struct tfd_frame { - struct txrx_control_flags control_flags; - union { - struct tfd_data data; - struct tfd_command cmd; - u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH]; - } u; -} __attribute__ ((packed)); - -typedef void destructor_func(const void *); - -/** - * Tx Queue for DMA. Queue consists of circular buffer of - * BD's and required locking structures. - */ -struct clx2_tx_queue { - struct clx2_queue q; - struct tfd_frame *bd; - struct ieee80211_txb **txb; -}; - -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 32 -#define RX_LOW_WATERMARK 8 - -#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 -#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 -#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 - -// Used for passing to driver number of successes and failures per rate -struct rate_histogram { - union { - __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; - __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; - __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; - } success; - union { - __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; - __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; - __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; - } failed; -} __attribute__ ((packed)); - -/* statistics command response */ -struct ipw_cmd_stats { - u8 cmd_id; - u8 seq_num; - __le16 good_sfd; - __le16 bad_plcp; - __le16 wrong_bssid; - __le16 valid_mpdu; - __le16 bad_mac_header; - __le16 reserved_frame_types; - __le16 rx_ina; - __le16 bad_crc32; - __le16 invalid_cts; - __le16 invalid_acks; - __le16 long_distance_ina_fina; - __le16 dsp_silence_unreachable; - __le16 accumulated_rssi; - __le16 rx_ovfl_frame_tossed; - __le16 rssi_silence_threshold; - __le16 rx_ovfl_frame_supplied; - __le16 last_rx_frame_signal; - __le16 last_rx_frame_noise; - __le16 rx_autodetec_no_ofdm; - __le16 rx_autodetec_no_barker; - __le16 reserved; -} __attribute__ ((packed)); - -struct notif_channel_result { - u8 channel_num; - struct ipw_cmd_stats stats; - u8 uReserved; -} __attribute__ ((packed)); - -#define SCAN_COMPLETED_STATUS_COMPLETE 1 -#define SCAN_COMPLETED_STATUS_ABORTED 2 - -struct notif_scan_complete { - u8 scan_type; - u8 num_channels; - u8 status; - u8 reserved; -} __attribute__ ((packed)); - -struct notif_frag_length { - __le16 frag_length; - __le16 reserved; -} __attribute__ ((packed)); - -struct notif_beacon_state { - __le32 state; - __le32 number; -} __attribute__ ((packed)); - -struct notif_tgi_tx_key { - u8 key_state; - u8 security_type; - u8 station_index; - u8 reserved; -} __attribute__ ((packed)); - -#define SILENCE_OVER_THRESH (1) -#define SILENCE_UNDER_THRESH (2) - -struct notif_link_deterioration { - struct ipw_cmd_stats stats; - u8 rate; - u8 modulation; - struct rate_histogram histogram; - u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */ - __le16 silence_count; -} __attribute__ ((packed)); - -struct notif_association { - u8 state; -} __attribute__ ((packed)); - -struct notif_authenticate { - u8 state; - struct machdr24 addr; - __le16 status; -} __attribute__ ((packed)); - -struct notif_calibration { - u8 data[104]; -} __attribute__ ((packed)); - -struct notif_noise { - __le32 value; -} __attribute__ ((packed)); - -struct ipw_rx_notification { - u8 reserved[8]; - u8 subtype; - u8 flags; - __le16 size; - union { - struct notif_association assoc; - struct notif_authenticate auth; - struct notif_channel_result channel_result; - struct notif_scan_complete scan_complete; - struct notif_frag_length frag_len; - struct notif_beacon_state beacon_state; - struct notif_tgi_tx_key tgi_tx_key; - struct notif_link_deterioration link_deterioration; - struct notif_calibration calibration; - struct notif_noise noise; - u8 raw[0]; - } u; -} __attribute__ ((packed)); - -struct ipw_rx_frame { - __le32 reserved1; - u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER - u8 received_channel; // The channel that this frame was received on. - // Note that for .11b this does not have to be - // the same as the channel that it was sent. - // Filled by LMAC - u8 frameStatus; - u8 rate; - u8 rssi; - u8 agc; - u8 rssi_dbm; - __le16 signal; - __le16 noise; - u8 antennaAndPhy; - u8 control; // control bit should be on in bg - u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate - // is identical) - u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen - __le16 length; - u8 data[0]; -} __attribute__ ((packed)); - -struct ipw_rx_header { - u8 message_type; - u8 rx_seq_num; - u8 control_bits; - u8 reserved; -} __attribute__ ((packed)); - -struct ipw_rx_packet { - struct ipw_rx_header header; - union { - struct ipw_rx_frame frame; - struct ipw_rx_notification notification; - } u; -} __attribute__ ((packed)); - -#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12 -#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \ - sizeof(struct ipw_rx_frame)) - -struct ipw_rx_mem_buffer { - dma_addr_t dma_addr; - struct sk_buff *skb; - struct list_head list; -}; /* Not transferred over network, so not __attribute__ ((packed)) */ - -struct ipw_rx_queue { - struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 processed; /* Internal index to last handled Rx packet */ - u32 read; /* Shared index to newest available Rx buffer */ - u32 write; /* Shared index to oldest written Rx packet */ - u32 free_count; /* Number of pre-allocated buffers in rx_free */ - /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */ - struct list_head rx_free; /* Own an SKBs */ - struct list_head rx_used; /* No SKB allocated */ - spinlock_t lock; -}; /* Not transferred over network, so not __attribute__ ((packed)) */ - -struct alive_command_responce { - u8 alive_command; - u8 sequence_number; - __le16 software_revision; - u8 device_identifier; - u8 reserved1[5]; - __le16 reserved2; - __le16 reserved3; - __le16 clock_settle_time; - __le16 powerup_settle_time; - __le16 reserved4; - u8 time_stamp[5]; /* month, day, year, hours, minutes */ - u8 ucode_valid; -} __attribute__ ((packed)); - -#define IPW_MAX_RATES 12 - -struct ipw_rates { - u8 num_rates; - u8 rates[IPW_MAX_RATES]; -} __attribute__ ((packed)); - -struct command_block { - unsigned int control; - u32 source_addr; - u32 dest_addr; - unsigned int status; -} __attribute__ ((packed)); - -#define CB_NUMBER_OF_ELEMENTS_SMALL 64 -struct fw_image_desc { - unsigned long last_cb_index; - unsigned long current_cb_index; - struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL]; - void *v_addr; - unsigned long p_addr; - unsigned long len; -}; - -struct ipw_sys_config { - u8 bt_coexistence; - u8 reserved1; - u8 answer_broadcast_ssid_probe; - u8 accept_all_data_frames; - u8 accept_non_directed_frames; - u8 exclude_unicast_unencrypted; - u8 disable_unicast_decryption; - u8 exclude_multicast_unencrypted; - u8 disable_multicast_decryption; - u8 antenna_diversity; - u8 pass_crc_to_host; - u8 dot11g_auto_detection; - u8 enable_cts_to_self; - u8 enable_multicast_filtering; - u8 bt_coexist_collision_thr; - u8 silence_threshold; - u8 accept_all_mgmt_bcpr; - u8 accept_all_mgmt_frames; - u8 pass_noise_stats_to_host; - u8 reserved3; -} __attribute__ ((packed)); - -struct ipw_multicast_addr { - u8 num_of_multicast_addresses; - u8 reserved[3]; - u8 mac1[6]; - u8 mac2[6]; - u8 mac3[6]; - u8 mac4[6]; -} __attribute__ ((packed)); - -#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */ -#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */ - -#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00 -#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20 -#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30 - -#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */ -#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */ -#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */ -#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */ -//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */ - -struct ipw_wep_key { - u8 cmd_id; - u8 seq_num; - u8 key_index; - u8 key_size; - u8 key[16]; -} __attribute__ ((packed)); - -struct ipw_tgi_tx_key { - u8 key_id; - u8 security_type; - u8 station_index; - u8 flags; - u8 key[16]; - __le32 tx_counter[2]; -} __attribute__ ((packed)); - -#define IPW_SCAN_CHANNELS 54 - -struct ipw_scan_request { - u8 scan_type; - __le16 dwell_time; - u8 channels_list[IPW_SCAN_CHANNELS]; - u8 channels_reserved[3]; -} __attribute__ ((packed)); - -enum { - IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0, - IPW_SCAN_PASSIVE_FULL_DWELL_SCAN, - IPW_SCAN_ACTIVE_DIRECT_SCAN, - IPW_SCAN_ACTIVE_BROADCAST_SCAN, - IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN, - IPW_SCAN_TYPES -}; - -struct ipw_scan_request_ext { - __le32 full_scan_index; - u8 channels_list[IPW_SCAN_CHANNELS]; - u8 scan_type[IPW_SCAN_CHANNELS / 2]; - u8 reserved; - __le16 dwell_time[IPW_SCAN_TYPES]; -} __attribute__ ((packed)); - -static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) -{ - if (index % 2) - return scan->scan_type[index / 2] & 0x0F; - else - return (scan->scan_type[index / 2] & 0xF0) >> 4; -} - -static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan, - u8 index, u8 scan_type) -{ - if (index % 2) - scan->scan_type[index / 2] = - (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F); - else - scan->scan_type[index / 2] = - (scan->scan_type[index / 2] & 0x0F) | - ((scan_type & 0x0F) << 4); -} - -struct ipw_associate { - u8 channel; -#ifdef __LITTLE_ENDIAN_BITFIELD - u8 auth_type:4, auth_key:4; -#else - u8 auth_key:4, auth_type:4; -#endif - u8 assoc_type; - u8 reserved; - __le16 policy_support; - u8 preamble_length; - u8 ieee_mode; - u8 bssid[ETH_ALEN]; - __le32 assoc_tsf_msw; - __le32 assoc_tsf_lsw; - __le16 capability; - __le16 listen_interval; - __le16 beacon_interval; - u8 dest[ETH_ALEN]; - __le16 atim_window; - u8 smr; - u8 reserved1; - __le16 reserved2; -} __attribute__ ((packed)); - -struct ipw_supported_rates { - u8 ieee_mode; - u8 num_rates; - u8 purpose; - u8 reserved; - u8 supported_rates[IPW_MAX_RATES]; -} __attribute__ ((packed)); - -struct ipw_rts_threshold { - __le16 rts_threshold; - __le16 reserved; -} __attribute__ ((packed)); - -struct ipw_frag_threshold { - __le16 frag_threshold; - __le16 reserved; -} __attribute__ ((packed)); - -struct ipw_retry_limit { - u8 short_retry_limit; - u8 long_retry_limit; - __le16 reserved; -} __attribute__ ((packed)); - -struct ipw_dino_config { - __le32 dino_config_addr; - __le16 dino_config_size; - u8 dino_response; - u8 reserved; -} __attribute__ ((packed)); - -struct ipw_aironet_info { - u8 id; - u8 length; - __le16 reserved; -} __attribute__ ((packed)); - -struct ipw_rx_key { - u8 station_index; - u8 key_type; - u8 key_id; - u8 key_flag; - u8 key[16]; - u8 station_address[6]; - u8 key_index; - u8 reserved; -} __attribute__ ((packed)); - -struct ipw_country_channel_info { - u8 first_channel; - u8 no_channels; - s8 max_tx_power; -} __attribute__ ((packed)); - -struct ipw_country_info { - u8 id; - u8 length; - u8 country_str[3]; - struct ipw_country_channel_info groups[7]; -} __attribute__ ((packed)); - -struct ipw_channel_tx_power { - u8 channel_number; - s8 tx_power; -} __attribute__ ((packed)); - -#define SCAN_ASSOCIATED_INTERVAL (HZ) -#define SCAN_INTERVAL (HZ / 10) -#define MAX_A_CHANNELS 37 -#define MAX_B_CHANNELS 14 - -struct ipw_tx_power { - u8 num_channels; - u8 ieee_mode; - struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS]; -} __attribute__ ((packed)); - -struct ipw_rsn_capabilities { - u8 id; - u8 length; - __le16 version; -} __attribute__ ((packed)); - -struct ipw_sensitivity_calib { - __le16 beacon_rssi_raw; - __le16 reserved; -} __attribute__ ((packed)); - -/** - * Host command structure. - * - * On input, the following fields should be filled: - * - cmd - * - len - * - status_len - * - param (if needed) - * - * On output, - * - \a status contains status; - * - \a param filled with status parameters. - */ -struct ipw_cmd { /* XXX */ - u32 cmd; /**< Host command */ - u32 status;/**< Status */ - u32 status_len; - /**< How many 32 bit parameters in the status */ - u32 len; /**< incoming parameters length, bytes */ - /** - * command parameters. - * There should be enough space for incoming and - * outcoming parameters. - * Incoming parameters listed 1-st, followed by outcoming params. - * nParams=(len+3)/4+status_len - */ - u32 param[0]; -} __attribute__ ((packed)); - -#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */ - -#define STATUS_INT_ENABLED (1<<1) -#define STATUS_RF_KILL_HW (1<<2) -#define STATUS_RF_KILL_SW (1<<3) -#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW) - -#define STATUS_INIT (1<<5) -#define STATUS_AUTH (1<<6) -#define STATUS_ASSOCIATED (1<<7) -#define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED) - -#define STATUS_ASSOCIATING (1<<8) -#define STATUS_DISASSOCIATING (1<<9) -#define STATUS_ROAMING (1<<10) -#define STATUS_EXIT_PENDING (1<<11) -#define STATUS_DISASSOC_PENDING (1<<12) -#define STATUS_STATE_PENDING (1<<13) - -#define STATUS_DIRECT_SCAN_PENDING (1<<19) -#define STATUS_SCAN_PENDING (1<<20) -#define STATUS_SCANNING (1<<21) -#define STATUS_SCAN_ABORTING (1<<22) -#define STATUS_SCAN_FORCED (1<<23) - -#define STATUS_LED_LINK_ON (1<<24) -#define STATUS_LED_ACT_ON (1<<25) - -#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */ -#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */ -#define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */ - -#define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */ - -#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ -#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ -#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ -#define CFG_CUSTOM_MAC (1<<3) -#define CFG_PREAMBLE_LONG (1<<4) -#define CFG_ADHOC_PERSIST (1<<5) -#define CFG_ASSOCIATE (1<<6) -#define CFG_FIXED_RATE (1<<7) -#define CFG_ADHOC_CREATE (1<<8) -#define CFG_NO_LED (1<<9) -#define CFG_BACKGROUND_SCAN (1<<10) -#define CFG_SPEED_SCAN (1<<11) -#define CFG_NET_STATS (1<<12) - -#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ -#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ - -#define MAX_STATIONS 32 -#define IPW_INVALID_STATION (0xff) - -struct ipw_station_entry { - u8 mac_addr[ETH_ALEN]; - u8 reserved; - u8 support_mode; -}; - -#define AVG_ENTRIES 8 -struct average { - s16 entries[AVG_ENTRIES]; - u8 pos; - u8 init; - s32 sum; -}; - -#define MAX_SPEED_SCAN 100 -#define IPW_IBSS_MAC_HASH_SIZE 31 - -struct ipw_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - -struct ipw_error_elem { /* XXX */ - u32 desc; - u32 time; - u32 blink1; - u32 blink2; - u32 link1; - u32 link2; - u32 data; -}; - -struct ipw_event { /* XXX */ - u32 event; - u32 time; - u32 data; -} __attribute__ ((packed)); - -struct ipw_fw_error { /* XXX */ - unsigned long jiffies; - u32 status; - u32 config; - u32 elem_len; - u32 log_len; - struct ipw_error_elem *elem; - struct ipw_event *log; - u8 payload[0]; -} __attribute__ ((packed)); - -#ifdef CONFIG_IPW2200_PROMISCUOUS - -enum ipw_prom_filter { - IPW_PROM_CTL_HEADER_ONLY = (1 << 0), - IPW_PROM_MGMT_HEADER_ONLY = (1 << 1), - IPW_PROM_DATA_HEADER_ONLY = (1 << 2), - IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */ - IPW_PROM_NO_TX = (1 << 4), - IPW_PROM_NO_RX = (1 << 5), - IPW_PROM_NO_CTL = (1 << 6), - IPW_PROM_NO_MGMT = (1 << 7), - IPW_PROM_NO_DATA = (1 << 8), -}; - -struct ipw_priv; -struct ipw_prom_priv { - struct ipw_priv *priv; - struct ieee80211_device *ieee; - enum ipw_prom_filter filter; - int tx_packets; - int rx_packets; -}; -#endif - -#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS) -/* Magic struct that slots into the radiotap header -- no reason - * to build this manually element by element, we can write it much - * more efficiently than we can parse it. ORDER MATTERS HERE - * - * When sent to us via the simulated Rx interface in sysfs, the entire - * structure is provided regardless of any bits unset. - */ -struct ipw_rt_hdr { - struct ieee80211_radiotap_header rt_hdr; - u64 rt_tsf; /* TSF */ /* XXX */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channel; /* channel in mhz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - u8 payload[0]; /* payload... */ -} __attribute__ ((packed)); -#endif - -struct ipw_priv { - /* ieee device used by generic ieee processing code */ - struct ieee80211_device *ieee; - - spinlock_t lock; - spinlock_t irq_lock; - struct mutex mutex; - - /* basic pci-network driver stuff */ - struct pci_dev *pci_dev; - struct net_device *net_dev; - -#ifdef CONFIG_IPW2200_PROMISCUOUS - /* Promiscuous mode */ - struct ipw_prom_priv *prom_priv; - struct net_device *prom_net_dev; -#endif - - /* pci hardware address support */ - void __iomem *hw_base; - unsigned long hw_len; - - struct fw_image_desc sram_desc; - - /* result of ucode download */ - struct alive_command_responce dino_alive; - - wait_queue_head_t wait_command_queue; - wait_queue_head_t wait_state; - - /* Rx and Tx DMA processing queues */ - struct ipw_rx_queue *rxq; - struct clx2_tx_queue txq_cmd; - struct clx2_tx_queue txq[4]; - u32 status; - u32 config; - u32 capability; - - struct average average_missed_beacons; - s16 exp_avg_rssi; - s16 exp_avg_noise; - u32 port_type; - int rx_bufs_min; /**< minimum number of bufs in Rx queue */ - int rx_pend_max; /**< maximum pending buffers for one IRQ */ - u32 hcmd_seq; /**< sequence number for hcmd */ - u32 disassociate_threshold; - u32 roaming_threshold; - - struct ipw_associate assoc_request; - struct ieee80211_network *assoc_network; - - unsigned long ts_scan_abort; - struct ipw_supported_rates rates; - struct ipw_rates phy[3]; /**< PHY restrictions, per band */ - struct ipw_rates supp; /**< software defined */ - struct ipw_rates extended; /**< use for corresp. IE, AP only */ - - struct notif_link_deterioration last_link_deterioration; /** for statistics */ - struct ipw_cmd *hcmd; /**< host command currently executed */ - - wait_queue_head_t hcmd_wq; /**< host command waits for execution */ - u32 tsf_bcn[2]; /**< TSF from latest beacon */ - - struct notif_calibration calib; /**< last calibration */ - - /* ordinal interface with firmware */ - u32 table0_addr; - u32 table0_len; - u32 table1_addr; - u32 table1_len; - u32 table2_addr; - u32 table2_len; - - /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; - u8 nick[IW_ESSID_MAX_SIZE]; - u16 rates_mask; - u8 channel; - struct ipw_sys_config sys_config; - u32 power_mode; - u8 bssid[ETH_ALEN]; - u16 rts_threshold; - u8 mac_addr[ETH_ALEN]; - u8 num_stations; - u8 stations[MAX_STATIONS][ETH_ALEN]; - u8 short_retry_limit; - u8 long_retry_limit; - - u32 notif_missed_beacons; - - /* Statistics and counters normalized with each association */ - u32 last_missed_beacons; - u32 last_tx_packets; - u32 last_rx_packets; - u32 last_tx_failures; - u32 last_rx_err; - u32 last_rate; - - u32 missed_adhoc_beacons; - u32 missed_beacons; - u32 rx_packets; - u32 tx_packets; - u32 quality; - - u8 speed_scan[MAX_SPEED_SCAN]; - u8 speed_scan_pos; - - u16 last_seq_num; - u16 last_frag_num; - unsigned long last_packet_time; - struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE]; - - /* eeprom */ - u8 eeprom[0x100]; /* 256 bytes of eeprom */ - u8 country[4]; - int eeprom_delay; - - struct iw_statistics wstats; - - struct iw_public_data wireless_data; - - int user_requested_scan; - u8 direct_scan_ssid[IW_ESSID_MAX_SIZE]; - u8 direct_scan_ssid_len; - - struct workqueue_struct *workqueue; - - struct delayed_work adhoc_check; - struct work_struct associate; - struct work_struct disassociate; - struct work_struct system_config; - struct work_struct rx_replenish; - struct delayed_work request_scan; - struct delayed_work request_direct_scan; - struct delayed_work request_passive_scan; - struct delayed_work scan_event; - struct work_struct adapter_restart; - struct delayed_work rf_kill; - struct work_struct up; - struct work_struct down; - struct delayed_work gather_stats; - struct work_struct abort_scan; - struct work_struct roam; - struct delayed_work scan_check; - struct work_struct link_up; - struct work_struct link_down; - - struct tasklet_struct irq_tasklet; - - /* LED related variables and work_struct */ - u8 nic_type; - u32 led_activity_on; - u32 led_activity_off; - u32 led_association_on; - u32 led_association_off; - u32 led_ofdm_on; - u32 led_ofdm_off; - - struct delayed_work led_link_on; - struct delayed_work led_link_off; - struct delayed_work led_act_off; - struct work_struct merge_networks; - - struct ipw_cmd_log *cmdlog; - int cmdlog_len; - int cmdlog_pos; - -#define IPW_2200BG 1 -#define IPW_2915ABG 2 - u8 adapter; - - s8 tx_power; - -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif - - struct ipw_fw_error *error; - - /* network state */ - - /* Used to pass the current INTA value from ISR to Tasklet */ - u32 isr_inta; - - /* QoS */ - struct ipw_qos_info qos_data; - struct work_struct qos_activate; - /*********************************/ - - /* debugging info */ - u32 indirect_dword; - u32 direct_dword; - u32 indirect_byte; -}; /*ipw_priv */ - -/* debug macros */ - -/* Debug and printf string expansion helpers for printing bitfields */ -#define BIT_FMT8 "%c%c%c%c-%c%c%c%c" -#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8 -#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16 - -#define BITC(x,y) (((x>>y)&1)?'1':'0') -#define BIT_ARG8(x) \ -BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\ -BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0) - -#define BIT_ARG16(x) \ -BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\ -BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\ -BIT_ARG8(x) - -#define BIT_ARG32(x) \ -BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\ -BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\ -BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\ -BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\ -BIT_ARG16(x) - - -#define IPW_DEBUG(level, fmt, args...) \ -do { if (ipw_debug_level & (level)) \ - printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) - -#ifdef CONFIG_IPW2200_DEBUG -#define IPW_LL_DEBUG(level, fmt, args...) \ -do { if (ipw_debug_level & (level)) \ - printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) -#else -#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0) -#endif /* CONFIG_IPW2200_DEBUG */ - -/* - * To use the debug system; - * - * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: - * - * #define IPW_DL_xxxx VALUE - * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) - * - * You then need to either add a IPW_xxxx_DEBUG() macro definition for your - * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want - * to send output to that classification. - * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/ipw/debug_level - * - * you simply need to add your entry to the ipw_debug_levels array. - * - * If you do not see debug_level in /proc/net/ipw then you do not have - * CONFIG_IPW2200_DEBUG defined in your kernel configuration - * - */ - -#define IPW_DL_ERROR (1<<0) -#define IPW_DL_WARNING (1<<1) -#define IPW_DL_INFO (1<<2) -#define IPW_DL_WX (1<<3) -#define IPW_DL_HOST_COMMAND (1<<5) -#define IPW_DL_STATE (1<<6) - -#define IPW_DL_NOTIF (1<<10) -#define IPW_DL_SCAN (1<<11) -#define IPW_DL_ASSOC (1<<12) -#define IPW_DL_DROP (1<<13) -#define IPW_DL_IOCTL (1<<14) - -#define IPW_DL_MANAGE (1<<15) -#define IPW_DL_FW (1<<16) -#define IPW_DL_RF_KILL (1<<17) -#define IPW_DL_FW_ERRORS (1<<18) - -#define IPW_DL_LED (1<<19) - -#define IPW_DL_ORD (1<<20) - -#define IPW_DL_FRAG (1<<21) -#define IPW_DL_WEP (1<<22) -#define IPW_DL_TX (1<<23) -#define IPW_DL_RX (1<<24) -#define IPW_DL_ISR (1<<25) -#define IPW_DL_FW_INFO (1<<26) -#define IPW_DL_IO (1<<27) -#define IPW_DL_TRACE (1<<28) - -#define IPW_DL_STATS (1<<29) -#define IPW_DL_MERGE (1<<30) -#define IPW_DL_QOS (1<<31) - -#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) -#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) -#define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a) - -#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a) -#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a) -#define IPW_DEBUG_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a) -#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a) -#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a) -#define IPW_DEBUG_ISR(f, a...) IPW_LL_DEBUG(IPW_DL_ISR, f, ## a) -#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a) -#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a) -#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a) -#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a) -#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a) -#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a) -#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a) -#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a) -#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a) -#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a) -#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a) -#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a) -#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) -#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) -#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a) -#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a) -#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a) - -#include - -/* -* Register bit definitions -*/ - -#define IPW_INTA_RW 0x00000008 -#define IPW_INTA_MASK_R 0x0000000C -#define IPW_INDIRECT_ADDR 0x00000010 -#define IPW_INDIRECT_DATA 0x00000014 -#define IPW_AUTOINC_ADDR 0x00000018 -#define IPW_AUTOINC_DATA 0x0000001C -#define IPW_RESET_REG 0x00000020 -#define IPW_GP_CNTRL_RW 0x00000024 - -#define IPW_READ_INT_REGISTER 0xFF4 - -#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004 - -#define IPW_REGISTER_DOMAIN1_END 0x00001000 -#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4 - -#define IPW_SHARED_LOWER_BOUND 0x00000200 -#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80 - -#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000 -#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000 - -#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29) -#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001 -#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002 - -/* - * RESET Register Bit Indexes - */ -#define CBD_RESET_REG_PRINCETON_RESET (1<<0) -#define IPW_START_STANDBY (1<<2) -#define IPW_ACTIVITY_LED (1<<4) -#define IPW_ASSOCIATED_LED (1<<5) -#define IPW_OFDM_LED (1<<6) -#define IPW_RESET_REG_SW_RESET (1<<7) -#define IPW_RESET_REG_MASTER_DISABLED (1<<8) -#define IPW_RESET_REG_STOP_MASTER (1<<9) -#define IPW_GATE_ODMA (1<<25) -#define IPW_GATE_IDMA (1<<26) -#define IPW_ARC_KESHET_CONFIG (1<<27) -#define IPW_GATE_ADMA (1<<29) - -#define IPW_CSR_CIS_UPPER_BOUND 0x00000200 -#define IPW_DOMAIN_0_END 0x1000 -#define CLX_MEM_BAR_SIZE 0x1000 - -/* Dino/baseband control registers bits */ - -#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */ -#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */ -#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */ -#define IPW_BASEBAND_CONTROL_STATUS 0X00200000 -#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004 -#define IPW_BASEBAND_RX_FIFO_READ 0X00200004 -#define IPW_BASEBAND_CONTROL_STORE 0X00200010 - -#define IPW_INTERNAL_CMD_EVENT 0X00300004 -#define IPW_BASEBAND_POWER_DOWN 0x00000001 - -#define IPW_MEM_HALT_AND_RESET 0x003000e0 - -/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */ -#define IPW_BIT_HALT_RESET_ON 0x80000000 -#define IPW_BIT_HALT_RESET_OFF 0x00000000 - -#define CB_LAST_VALID 0x20000000 -#define CB_INT_ENABLED 0x40000000 -#define CB_VALID 0x80000000 -#define CB_SRC_LE 0x08000000 -#define CB_DEST_LE 0x04000000 -#define CB_SRC_AUTOINC 0x00800000 -#define CB_SRC_IO_GATED 0x00400000 -#define CB_DEST_AUTOINC 0x00080000 -#define CB_SRC_SIZE_LONG 0x00200000 -#define CB_DEST_SIZE_LONG 0x00020000 - -/* DMA DEFINES */ - -#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000 -#define DMA_CB_STOP_AND_ABORT 0x00000C00 -#define DMA_CB_START 0x00000100 - -#define IPW_SHARED_SRAM_SIZE 0x00030000 -#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000 -#define CB_MAX_LENGTH 0x1FFF - -#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18 -#define IPW_EEPROM_IMAGE_SIZE 0x100 - -/* DMA defs */ -#define IPW_DMA_I_CURRENT_CB 0x003000D0 -#define IPW_DMA_O_CURRENT_CB 0x003000D4 -#define IPW_DMA_I_DMA_CONTROL 0x003000A4 -#define IPW_DMA_I_CB_BASE 0x003000A0 - -#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200 -#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204 -#define IPW_TX_QUEUE_0_BD_BASE 0x00000208 -#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C) -#define IPW_TX_QUEUE_1_BD_BASE 0x00000210 -#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214 -#define IPW_TX_QUEUE_2_BD_BASE 0x00000218 -#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C) -#define IPW_TX_QUEUE_3_BD_BASE 0x00000220 -#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224 -#define IPW_RX_BD_BASE 0x00000240 -#define IPW_RX_BD_SIZE 0x00000244 -#define IPW_RFDS_TABLE_LOWER 0x00000500 - -#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280 -#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284 -#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288 -#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C) -#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290 -#define IPW_RX_READ_INDEX (0x000002A0) - -#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) -#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84) -#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88) -#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C) -#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90) -#define IPW_RX_WRITE_INDEX (0x00000FA0) - -/* - * EEPROM Related Definitions - */ - -#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814) -#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818) -#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C) -#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820) -#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0) - -#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C) -#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C) -#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C) -#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10) -#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14) -#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18) - -#define MSB 1 -#define LSB 0 -#define WORD_TO_BYTE(_word) ((_word) * sizeof(u16)) - -#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \ - ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) ) - -/* EEPROM access by BYTE */ -#define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */ -#define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */ -#define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */ -#define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */ -#define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */ -#define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */ -#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */ -#define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */ -#define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */ -#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ - -/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */ -#define EEPROM_NIC_TYPE_0 0 -#define EEPROM_NIC_TYPE_1 1 -#define EEPROM_NIC_TYPE_2 2 -#define EEPROM_NIC_TYPE_3 3 -#define EEPROM_NIC_TYPE_4 4 - -/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */ -#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */ -#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */ -#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */ - -#define FW_MEM_REG_LOWER_BOUND 0x00300000 -#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) -#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) -#define EEPROM_BIT_SK (1<<0) -#define EEPROM_BIT_CS (1<<1) -#define EEPROM_BIT_DI (1<<2) -#define EEPROM_BIT_DO (1<<4) - -#define EEPROM_CMD_READ 0x2 - -/* Interrupts masks */ -#define IPW_INTA_NONE 0x00000000 - -#define IPW_INTA_BIT_RX_TRANSFER 0x00000002 -#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010 -#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020 - -//Inta Bits for CF -#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800 -#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000 -#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000 -#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000 -#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000 - -#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000 - -#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000 -#define IPW_INTA_BIT_POWER_DOWN 0x00200000 - -#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000 -#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000 -#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000 -#define IPW_INTA_BIT_FATAL_ERROR 0x40000000 -#define IPW_INTA_BIT_PARITY_ERROR 0x80000000 - -/* Interrupts enabled at init time. */ -#define IPW_INTA_MASK_ALL \ - (IPW_INTA_BIT_TX_QUEUE_1 | \ - IPW_INTA_BIT_TX_QUEUE_2 | \ - IPW_INTA_BIT_TX_QUEUE_3 | \ - IPW_INTA_BIT_TX_QUEUE_4 | \ - IPW_INTA_BIT_TX_CMD_QUEUE | \ - IPW_INTA_BIT_RX_TRANSFER | \ - IPW_INTA_BIT_FATAL_ERROR | \ - IPW_INTA_BIT_PARITY_ERROR | \ - IPW_INTA_BIT_STATUS_CHANGE | \ - IPW_INTA_BIT_FW_INITIALIZATION_DONE | \ - IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \ - IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \ - IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \ - IPW_INTA_BIT_POWER_DOWN | \ - IPW_INTA_BIT_RF_KILL_DONE ) - -/* FW event log definitions */ -#define EVENT_ELEM_SIZE (3 * sizeof(u32)) -#define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16)) - -/* FW error log definitions */ -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) -#define ERROR_START_OFFSET (1 * sizeof(u32)) - -/* TX power level (dbm) */ -#define IPW_TX_POWER_MIN -12 -#define IPW_TX_POWER_MAX 20 -#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX - -enum { - IPW_FW_ERROR_OK = 0, - IPW_FW_ERROR_FAIL, - IPW_FW_ERROR_MEMORY_UNDERFLOW, - IPW_FW_ERROR_MEMORY_OVERFLOW, - IPW_FW_ERROR_BAD_PARAM, - IPW_FW_ERROR_BAD_CHECKSUM, - IPW_FW_ERROR_NMI_INTERRUPT, - IPW_FW_ERROR_BAD_DATABASE, - IPW_FW_ERROR_ALLOC_FAIL, - IPW_FW_ERROR_DMA_UNDERRUN, - IPW_FW_ERROR_DMA_STATUS, - IPW_FW_ERROR_DINO_ERROR, - IPW_FW_ERROR_EEPROM_ERROR, - IPW_FW_ERROR_SYSASSERT, - IPW_FW_ERROR_FATAL_ERROR -}; - -#define AUTH_OPEN 0 -#define AUTH_SHARED_KEY 1 -#define AUTH_LEAP 2 -#define AUTH_IGNORE 3 - -#define HC_ASSOCIATE 0 -#define HC_REASSOCIATE 1 -#define HC_DISASSOCIATE 2 -#define HC_IBSS_START 3 -#define HC_IBSS_RECONF 4 -#define HC_DISASSOC_QUIET 5 - -#define HC_QOS_SUPPORT_ASSOC cpu_to_le16(0x01) - -#define IPW_RATE_CAPABILITIES 1 -#define IPW_RATE_CONNECT 0 - -/* - * Rate values and masks - */ -#define IPW_TX_RATE_1MB 0x0A -#define IPW_TX_RATE_2MB 0x14 -#define IPW_TX_RATE_5MB 0x37 -#define IPW_TX_RATE_6MB 0x0D -#define IPW_TX_RATE_9MB 0x0F -#define IPW_TX_RATE_11MB 0x6E -#define IPW_TX_RATE_12MB 0x05 -#define IPW_TX_RATE_18MB 0x07 -#define IPW_TX_RATE_24MB 0x09 -#define IPW_TX_RATE_36MB 0x0B -#define IPW_TX_RATE_48MB 0x01 -#define IPW_TX_RATE_54MB 0x03 - -#define IPW_ORD_TABLE_ID_MASK 0x0000FF00 -#define IPW_ORD_TABLE_VALUE_MASK 0x000000FF - -#define IPW_ORD_TABLE_0_MASK 0x0000F000 -#define IPW_ORD_TABLE_1_MASK 0x0000F100 -#define IPW_ORD_TABLE_2_MASK 0x0000F200 -#define IPW_ORD_TABLE_3_MASK 0x0000F300 -#define IPW_ORD_TABLE_4_MASK 0x0000F400 -#define IPW_ORD_TABLE_5_MASK 0x0000F500 -#define IPW_ORD_TABLE_6_MASK 0x0000F600 -#define IPW_ORD_TABLE_7_MASK 0x0000F700 - -/* - * Table 0 Entries (all entries are 32 bits) - */ -enum { - IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1, - IPW_ORD_STAT_FRAG_TRESHOLD, - IPW_ORD_STAT_RTS_THRESHOLD, - IPW_ORD_STAT_TX_HOST_REQUESTS, - IPW_ORD_STAT_TX_HOST_COMPLETE, - IPW_ORD_STAT_TX_DIR_DATA, - IPW_ORD_STAT_TX_DIR_DATA_B_1, - IPW_ORD_STAT_TX_DIR_DATA_B_2, - IPW_ORD_STAT_TX_DIR_DATA_B_5_5, - IPW_ORD_STAT_TX_DIR_DATA_B_11, - /* Hole */ - - IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19, - IPW_ORD_STAT_TX_DIR_DATA_G_2, - IPW_ORD_STAT_TX_DIR_DATA_G_5_5, - IPW_ORD_STAT_TX_DIR_DATA_G_6, - IPW_ORD_STAT_TX_DIR_DATA_G_9, - IPW_ORD_STAT_TX_DIR_DATA_G_11, - IPW_ORD_STAT_TX_DIR_DATA_G_12, - IPW_ORD_STAT_TX_DIR_DATA_G_18, - IPW_ORD_STAT_TX_DIR_DATA_G_24, - IPW_ORD_STAT_TX_DIR_DATA_G_36, - IPW_ORD_STAT_TX_DIR_DATA_G_48, - IPW_ORD_STAT_TX_DIR_DATA_G_54, - IPW_ORD_STAT_TX_NON_DIR_DATA, - IPW_ORD_STAT_TX_NON_DIR_DATA_B_1, - IPW_ORD_STAT_TX_NON_DIR_DATA_B_2, - IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5, - IPW_ORD_STAT_TX_NON_DIR_DATA_B_11, - /* Hole */ - - IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_2, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_6, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_9, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_11, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_12, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_18, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_24, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_36, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_48, - IPW_ORD_STAT_TX_NON_DIR_DATA_G_54, - IPW_ORD_STAT_TX_RETRY, - IPW_ORD_STAT_TX_FAILURE, - IPW_ORD_STAT_RX_ERR_CRC, - IPW_ORD_STAT_RX_ERR_ICV, - IPW_ORD_STAT_RX_NO_BUFFER, - IPW_ORD_STAT_FULL_SCANS, - IPW_ORD_STAT_PARTIAL_SCANS, - IPW_ORD_STAT_TGH_ABORTED_SCANS, - IPW_ORD_STAT_TX_TOTAL_BYTES, - IPW_ORD_STAT_CURR_RSSI_RAW, - IPW_ORD_STAT_RX_BEACON, - IPW_ORD_STAT_MISSED_BEACONS, - IPW_ORD_TABLE_0_LAST -}; - -#define IPW_RSSI_TO_DBM 112 - -/* Table 1 Entries - */ -enum { - IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1, -}; - -/* - * Table 2 Entries - * - * FW_VERSION: 16 byte string - * FW_DATE: 16 byte string (only 14 bytes used) - * UCODE_VERSION: 4 byte version code - * UCODE_DATE: 5 bytes code code - * ADDAPTER_MAC: 6 byte MAC address - * RTC: 4 byte clock - */ -enum { - IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1, - IPW_ORD_STAT_FW_DATE, - IPW_ORD_STAT_UCODE_VERSION, - IPW_ORD_STAT_UCODE_DATE, - IPW_ORD_STAT_ADAPTER_MAC, - IPW_ORD_STAT_RTC, - IPW_ORD_TABLE_2_LAST -}; - -/* Table 3 */ -enum { - IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0, - IPW_ORD_STAT_TX_PACKET_FAILURE, - IPW_ORD_STAT_TX_PACKET_SUCCESS, - IPW_ORD_STAT_TX_PACKET_ABORTED, - IPW_ORD_TABLE_3_LAST -}; - -/* Table 4 */ -enum { - IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK -}; - -/* Table 5 */ -enum { - IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK, - IPW_ORD_STAT_AP_ASSNS, - IPW_ORD_STAT_ROAM, - IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS, - IPW_ORD_STAT_ROAM_CAUSE_UNASSOC, - IPW_ORD_STAT_ROAM_CAUSE_RSSI, - IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY, - IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE, - IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX, - IPW_ORD_STAT_LINK_UP, - IPW_ORD_STAT_LINK_DOWN, - IPW_ORD_ANTENNA_DIVERSITY, - IPW_ORD_CURR_FREQ, - IPW_ORD_TABLE_5_LAST -}; - -/* Table 6 */ -enum { - IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK, - IPW_ORD_CURR_BSSID, - IPW_ORD_CURR_SSID, - IPW_ORD_TABLE_6_LAST -}; - -/* Table 7 */ -enum { - IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK, - IPW_ORD_STAT_PERCENT_TX_RETRIES, - IPW_ORD_STAT_PERCENT_LINK_QUALITY, - IPW_ORD_STAT_CURR_RSSI_DBM, - IPW_ORD_TABLE_7_LAST -}; - -#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410) -#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414) -#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500) -#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180) -#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184) -#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188) -#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C) - -struct ipw_fixed_rate { - __le16 tx_rates; - __le16 reserved; -} __attribute__ ((packed)); - -#define IPW_INDIRECT_ADDR_MASK (~0x3ul) - -struct host_cmd { - u8 cmd; - u8 len; - u16 reserved; - u32 *param; -} __attribute__ ((packed)); /* XXX */ - -struct cmdlog_host_cmd { - u8 cmd; - u8 len; - __le16 reserved; - char param[124]; -} __attribute__ ((packed)); - -struct ipw_cmd_log { - unsigned long jiffies; - int retcode; - struct cmdlog_host_cmd cmd; -}; - -/* SysConfig command parameters ... */ -/* bt_coexistence param */ -#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */ -#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */ -#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */ -#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */ -#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */ - -/* clear-to-send to self param */ -#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00 -#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x01 -#define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN - -/* Antenna diversity param (h/w can select best antenna, based on signal) */ -#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */ -#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */ -#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */ -#define CFG_SYS_ANTENNA_SLOW_DIV 0x02 /* consider background noise */ - -/* - * The definitions below were lifted off the ipw2100 driver, which only - * supports 'b' mode, so I'm sure these are not exactly correct. - * - * Somebody fix these!! - */ -#define REG_MIN_CHANNEL 0 -#define REG_MAX_CHANNEL 14 - -#define REG_CHANNEL_MASK 0x00003FFF -#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff - -#define IPW_MAX_CONFIG_RETRIES 10 - -#endif /* __ipw2200_h__ */ diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig new file mode 100644 index 0000000..67c57bf --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -0,0 +1,150 @@ +# +# Intel Centrino wireless drivers +# + +config IPW2100 + tristate "Intel PRO/Wireless 2100 Network Connection" + depends on PCI && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select LIB80211 + select IEEE80211 + ---help--- + A driver for the Intel PRO/Wireless 2100 Network + Connection 802.11b wireless network adapter. + + See for information on + the capabilities currently enabled in this driver and for tips + for debugging issues and problems. + + In order to use this driver, you will need a firmware image for it. + You can obtain the firmware from + . Once you have the firmware image, you + will need to place it in /lib/firmware. + + You will also very likely need the Wireless Tools in order to + configure your card: + + . + + It is recommended that you compile this driver as a module (M) + rather than built-in (Y). This driver requires firmware at device + initialization time, and when built-in this typically happens + before the filesystem is accessible (hence firmware will be + unavailable and initialization will fail). If you do choose to build + this driver into your kernel image, you can avoid this problem by + including the firmware and a firmware loader in an initramfs. + +config IPW2100_MONITOR + bool "Enable promiscuous mode" + depends on IPW2100 + ---help--- + Enables promiscuous/monitor mode support for the ipw2100 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW2100_DEBUG + bool "Enable full debugging output in IPW2100 module." + depends on IPW2100 + ---help--- + This option will enable debug tracing output for the IPW2100. + + This will result in the kernel module being ~60k larger. You can + control which debug output is sent to the kernel log by setting the + value in + + /sys/bus/pci/drivers/ipw2100/debug_level + + This entry will only exist if this option is enabled. + + If you are not trying to debug or develop the IPW2100 driver, you + most likely want to say N here. + +config IPW2200 + tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" + depends on PCI && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select LIB80211 + select IEEE80211 + ---help--- + A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network + Connection adapters. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging issues and problems. + + In order to use this driver, you will need a firmware image for it. + You can obtain the firmware from + . See the above referenced README.ipw2200 + for information on where to install the firmware images. + + You will also very likely need the Wireless Tools in order to + configure your card: + + . + + It is recommended that you compile this driver as a module (M) + rather than built-in (Y). This driver requires firmware at device + initialization time, and when built-in this typically happens + before the filesystem is accessible (hence firmware will be + unavailable and initialization will fail). If you do choose to build + this driver into your kernel image, you can avoid this problem by + including the firmware and a firmware loader in an initramfs. + +config IPW2200_MONITOR + bool "Enable promiscuous mode" + depends on IPW2200 + ---help--- + Enables promiscuous/monitor mode support for the ipw2200 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW2200_RADIOTAP + bool "Enable radiotap format 802.11 raw packet support" + depends on IPW2200_MONITOR + +config IPW2200_PROMISCUOUS + bool "Enable creation of a RF radiotap promiscuous interface" + depends on IPW2200_MONITOR + select IPW2200_RADIOTAP + ---help--- + Enables the creation of a second interface prefixed 'rtap'. + This second interface will provide every received in radiotap + format. + + This is useful for performing wireless network analysis while + maintaining an active association. + + Example usage: + + % modprobe ipw2200 rtap_iface=1 + % ifconfig rtap0 up + % tethereal -i rtap0 + + If you do not specify 'rtap_iface=1' as a module parameter then + the rtap interface will not be created and you will need to turn + it on via sysfs: + + % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface + +config IPW2200_QOS + bool "Enable QoS support" + depends on IPW2200 && EXPERIMENTAL + +config IPW2200_DEBUG + bool "Enable full debugging output in IPW2200 module." + depends on IPW2200 + ---help--- + This option will enable low level debug tracing output for IPW2200. + + Note, normal debug code is already compiled in. This low level + debug option enables debug on hot paths (e.g Tx, Rx, ISR) and + will result in the kernel module being ~70 larger. Most users + will typically not need this high verbosity debug information. + + If you are not sure, say N here. + diff --git a/drivers/net/wireless/ipw2x00/Makefile b/drivers/net/wireless/ipw2x00/Makefile new file mode 100644 index 0000000..dbc0d81 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the Intel Centrino wireless drivers +# + +obj-$(CONFIG_IPW2100) += ipw2100.o +obj-$(CONFIG_IPW2200) += ipw2200.o diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c new file mode 100644 index 0000000..2d2044d --- /dev/null +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -0,0 +1,8649 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + + Portions of this file are based on the sample_* files provided by Wireless + Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes + + + Portions of this file are based on the Host AP project, + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and + ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c + available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox + +******************************************************************************/ +/* + + Initial driver on which this is based was developed by Janusz Gorycki, + Maciej Urbaniak, and Maciej Sosnowski. + + Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak. + +Theory of Operation + +Tx - Commands and Data + +Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs) +Each TBD contains a pointer to the physical (dma_addr_t) address of data being +sent to the firmware as well as the length of the data. + +The host writes to the TBD queue at the WRITE index. The WRITE index points +to the _next_ packet to be written and is advanced when after the TBD has been +filled. + +The firmware pulls from the TBD queue at the READ index. The READ index points +to the currently being read entry, and is advanced once the firmware is +done with a packet. + +When data is sent to the firmware, the first TBD is used to indicate to the +firmware if a Command or Data is being sent. If it is Command, all of the +command information is contained within the physical address referred to by the +TBD. If it is Data, the first TBD indicates the type of data packet, number +of fragments, etc. The next TBD then referrs to the actual packet location. + +The Tx flow cycle is as follows: + +1) ipw2100_tx() is called by kernel with SKB to transmit +2) Packet is move from the tx_free_list and appended to the transmit pending + list (tx_pend_list) +3) work is scheduled to move pending packets into the shared circular queue. +4) when placing packet in the circular queue, the incoming SKB is DMA mapped + to a physical address. That address is entered into a TBD. Two TBDs are + filled out. The first indicating a data packet, the second referring to the + actual payload data. +5) the packet is removed from tx_pend_list and placed on the end of the + firmware pending list (fw_pend_list) +6) firmware is notified that the WRITE index has +7) Once the firmware has processed the TBD, INTA is triggered. +8) For each Tx interrupt received from the firmware, the READ index is checked + to see which TBDs are done being processed. +9) For each TBD that has been processed, the ISR pulls the oldest packet + from the fw_pend_list. +10)The packet structure contained in the fw_pend_list is then used + to unmap the DMA address and to free the SKB originally passed to the driver + from the kernel. +11)The packet structure is placed onto the tx_free_list + +The above steps are the same for commands, only the msg_free_list/msg_pend_list +are used instead of tx_free_list/tx_pend_list + +... + +Critical Sections / Locking : + +There are two locks utilized. The first is the low level lock (priv->low_lock) +that protects the following: + +- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows: + + tx_free_list : Holds pre-allocated Tx buffers. + TAIL modified in __ipw2100_tx_process() + HEAD modified in ipw2100_tx() + + tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring + TAIL modified ipw2100_tx() + HEAD modified by ipw2100_tx_send_data() + + msg_free_list : Holds pre-allocated Msg (Command) buffers + TAIL modified in __ipw2100_tx_process() + HEAD modified in ipw2100_hw_send_command() + + msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring + TAIL modified in ipw2100_hw_send_command() + HEAD modified in ipw2100_tx_send_commands() + + The flow of data on the TX side is as follows: + + MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST + TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST + + The methods that work on the TBD ring are protected via priv->low_lock. + +- The internal data state of the device itself +- Access to the firmware read/write indexes for the BD queues + and associated logic + +All external entry functions are locked with the priv->action_lock to ensure +that only one external action is invoked at a time. + + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ipw2100.h" + +#define IPW2100_VERSION "git-1.2.2" + +#define DRV_NAME "ipw2100" +#define DRV_VERSION IPW2100_VERSION +#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" + +/* Debugging stuff */ +#ifdef CONFIG_IPW2100_DEBUG +#define IPW2100_RX_DEBUG /* Reception debugging */ +#endif + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +static int debug = 0; +static int mode = 0; +static int channel = 0; +static int associate = 0; +static int disable = 0; +#ifdef CONFIG_PM +static struct ipw2100_fw ipw2100_firmware; +#endif + +#include +module_param(debug, int, 0444); +module_param(mode, int, 0444); +module_param(channel, int, 0444); +module_param(associate, int, 0444); +module_param(disable, int, 0444); + +MODULE_PARM_DESC(debug, "debug level"); +MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); +MODULE_PARM_DESC(channel, "channel"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); + +static u32 ipw2100_debug_level = IPW_DL_NONE; + +#ifdef CONFIG_IPW2100_DEBUG +#define IPW_DEBUG(level, message...) \ +do { \ + if (ipw2100_debug_level & (level)) { \ + printk(KERN_DEBUG "ipw2100: %c %s ", \ + in_interrupt() ? 'I' : 'U', __func__); \ + printk(message); \ + } \ +} while (0) +#else +#define IPW_DEBUG(level, message...) do {} while (0) +#endif /* CONFIG_IPW2100_DEBUG */ + +#ifdef CONFIG_IPW2100_DEBUG +static const char *command_types[] = { + "undefined", + "unused", /* HOST_ATTENTION */ + "HOST_COMPLETE", + "unused", /* SLEEP */ + "unused", /* HOST_POWER_DOWN */ + "unused", + "SYSTEM_CONFIG", + "unused", /* SET_IMR */ + "SSID", + "MANDATORY_BSSID", + "AUTHENTICATION_TYPE", + "ADAPTER_ADDRESS", + "PORT_TYPE", + "INTERNATIONAL_MODE", + "CHANNEL", + "RTS_THRESHOLD", + "FRAG_THRESHOLD", + "POWER_MODE", + "TX_RATES", + "BASIC_TX_RATES", + "WEP_KEY_INFO", + "unused", + "unused", + "unused", + "unused", + "WEP_KEY_INDEX", + "WEP_FLAGS", + "ADD_MULTICAST", + "CLEAR_ALL_MULTICAST", + "BEACON_INTERVAL", + "ATIM_WINDOW", + "CLEAR_STATISTICS", + "undefined", + "undefined", + "undefined", + "undefined", + "TX_POWER_INDEX", + "undefined", + "undefined", + "undefined", + "undefined", + "undefined", + "undefined", + "BROADCAST_SCAN", + "CARD_DISABLE", + "PREFERRED_BSSID", + "SET_SCAN_OPTIONS", + "SCAN_DWELL_TIME", + "SWEEP_TABLE", + "AP_OR_STATION_TABLE", + "GROUP_ORDINALS", + "SHORT_RETRY_LIMIT", + "LONG_RETRY_LIMIT", + "unused", /* SAVE_CALIBRATION */ + "unused", /* RESTORE_CALIBRATION */ + "undefined", + "undefined", + "undefined", + "HOST_PRE_POWER_DOWN", + "unused", /* HOST_INTERRUPT_COALESCING */ + "undefined", + "CARD_DISABLE_PHY_OFF", + "MSDU_TX_RATES" "undefined", + "undefined", + "SET_STATION_STAT_BITS", + "CLEAR_STATIONS_STAT_BITS", + "LEAP_ROGUE_MODE", + "SET_SECURITY_INFORMATION", + "DISASSOCIATION_BSSID", + "SET_WPA_ASS_IE" +}; +#endif + +/* Pre-decl until we get the code solid and then we can clean it up */ +static void ipw2100_tx_send_commands(struct ipw2100_priv *priv); +static void ipw2100_tx_send_data(struct ipw2100_priv *priv); +static int ipw2100_adapter_setup(struct ipw2100_priv *priv); + +static void ipw2100_queues_initialize(struct ipw2100_priv *priv); +static void ipw2100_queues_free(struct ipw2100_priv *priv); +static int ipw2100_queues_allocate(struct ipw2100_priv *priv); + +static int ipw2100_fw_download(struct ipw2100_priv *priv, + struct ipw2100_fw *fw); +static int ipw2100_get_firmware(struct ipw2100_priv *priv, + struct ipw2100_fw *fw); +static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, + size_t max); +static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, + size_t max); +static void ipw2100_release_firmware(struct ipw2100_priv *priv, + struct ipw2100_fw *fw); +static int ipw2100_ucode_download(struct ipw2100_priv *priv, + struct ipw2100_fw *fw); +static void ipw2100_wx_event_work(struct work_struct *work); +static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev); +static struct iw_handler_def ipw2100_wx_handler_def; + +static inline void read_register(struct net_device *dev, u32 reg, u32 * val) +{ + *val = readl((void __iomem *)(dev->base_addr + reg)); + IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val); +} + +static inline void write_register(struct net_device *dev, u32 reg, u32 val) +{ + writel(val, (void __iomem *)(dev->base_addr + reg)); + IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val); +} + +static inline void read_register_word(struct net_device *dev, u32 reg, + u16 * val) +{ + *val = readw((void __iomem *)(dev->base_addr + reg)); + IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val); +} + +static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val) +{ + *val = readb((void __iomem *)(dev->base_addr + reg)); + IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val); +} + +static inline void write_register_word(struct net_device *dev, u32 reg, u16 val) +{ + writew(val, (void __iomem *)(dev->base_addr + reg)); + IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val); +} + +static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val) +{ + writeb(val, (void __iomem *)(dev->base_addr + reg)); + IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val); +} + +static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val) +{ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); + read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); +} + +static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val) +{ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); + write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); +} + +static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val) +{ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); + read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); +} + +static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val) +{ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); + write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); +} + +static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val) +{ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); + read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); +} + +static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val) +{ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); + write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); +} + +static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr) +{ + write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, + addr & IPW_REG_INDIRECT_ADDR_MASK); +} + +static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val) +{ + write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val); +} + +static void write_nic_memory(struct net_device *dev, u32 addr, u32 len, + const u8 * buf) +{ + u32 aligned_addr; + u32 aligned_len; + u32 dif_len; + u32 i; + + /* read first nibble byte by byte */ + aligned_addr = addr & (~0x3); + dif_len = addr - aligned_addr; + if (dif_len) { + /* Start reading at aligned_addr + dif_len */ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + aligned_addr); + for (i = dif_len; i < 4; i++, buf++) + write_register_byte(dev, + IPW_REG_INDIRECT_ACCESS_DATA + i, + *buf); + + len -= dif_len; + aligned_addr += 4; + } + + /* read DWs through autoincrement registers */ + write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr); + aligned_len = len & (~0x3); + for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) + write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf); + + /* copy the last nibble */ + dif_len = len - aligned_len; + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); + for (i = 0; i < dif_len; i++, buf++) + write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, + *buf); +} + +static void read_nic_memory(struct net_device *dev, u32 addr, u32 len, + u8 * buf) +{ + u32 aligned_addr; + u32 aligned_len; + u32 dif_len; + u32 i; + + /* read first nibble byte by byte */ + aligned_addr = addr & (~0x3); + dif_len = addr - aligned_addr; + if (dif_len) { + /* Start reading at aligned_addr + dif_len */ + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, + aligned_addr); + for (i = dif_len; i < 4; i++, buf++) + read_register_byte(dev, + IPW_REG_INDIRECT_ACCESS_DATA + i, + buf); + + len -= dif_len; + aligned_addr += 4; + } + + /* read DWs through autoincrement registers */ + write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr); + aligned_len = len & (~0x3); + for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) + read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf); + + /* copy the last nibble */ + dif_len = len - aligned_len; + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); + for (i = 0; i < dif_len; i++, buf++) + read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf); +} + +static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev) +{ + return (dev->base_addr && + (readl + ((void __iomem *)(dev->base_addr + + IPW_REG_DOA_DEBUG_AREA_START)) + == IPW_DATA_DOA_DEBUG_VALUE)); +} + +static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, + void *val, u32 * len) +{ + struct ipw2100_ordinals *ordinals = &priv->ordinals; + u32 addr; + u32 field_info; + u16 field_len; + u16 field_count; + u32 total_length; + + if (ordinals->table1_addr == 0) { + printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals " + "before they have been loaded.\n"); + return -EINVAL; + } + + if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { + if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) { + *len = IPW_ORD_TAB_1_ENTRY_SIZE; + + printk(KERN_WARNING DRV_NAME + ": ordinal buffer length too small, need %zd\n", + IPW_ORD_TAB_1_ENTRY_SIZE); + + return -EINVAL; + } + + read_nic_dword(priv->net_dev, + ordinals->table1_addr + (ord << 2), &addr); + read_nic_dword(priv->net_dev, addr, val); + + *len = IPW_ORD_TAB_1_ENTRY_SIZE; + + return 0; + } + + if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) { + + ord -= IPW_START_ORD_TAB_2; + + /* get the address of statistic */ + read_nic_dword(priv->net_dev, + ordinals->table2_addr + (ord << 3), &addr); + + /* get the second DW of statistics ; + * two 16-bit words - first is length, second is count */ + read_nic_dword(priv->net_dev, + ordinals->table2_addr + (ord << 3) + sizeof(u32), + &field_info); + + /* get each entry length */ + field_len = *((u16 *) & field_info); + + /* get number of entries */ + field_count = *(((u16 *) & field_info) + 1); + + /* abort if no enought memory */ + total_length = field_len * field_count; + if (total_length > *len) { + *len = total_length; + return -EINVAL; + } + + *len = total_length; + if (!total_length) + return 0; + + /* read the ordinal data from the SRAM */ + read_nic_memory(priv->net_dev, addr, total_length, val); + + return 0; + } + + printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor " + "in table 2\n", ord); + + return -EINVAL; +} + +static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val, + u32 * len) +{ + struct ipw2100_ordinals *ordinals = &priv->ordinals; + u32 addr; + + if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { + if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) { + *len = IPW_ORD_TAB_1_ENTRY_SIZE; + IPW_DEBUG_INFO("wrong size\n"); + return -EINVAL; + } + + read_nic_dword(priv->net_dev, + ordinals->table1_addr + (ord << 2), &addr); + + write_nic_dword(priv->net_dev, addr, *val); + + *len = IPW_ORD_TAB_1_ENTRY_SIZE; + + return 0; + } + + IPW_DEBUG_INFO("wrong table\n"); + if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) + return -EINVAL; + + return -EINVAL; +} + +static char *snprint_line(char *buf, size_t count, + const u8 * data, u32 len, u32 ofs) +{ + int out, i, j, l; + char c; + + out = snprintf(buf, count, "%08X", ofs); + + for (l = 0, i = 0; i < 2; i++) { + out += snprintf(buf + out, count - out, " "); + for (j = 0; j < 8 && l < len; j++, l++) + out += snprintf(buf + out, count - out, "%02X ", + data[(i * 8 + j)]); + for (; j < 8; j++) + out += snprintf(buf + out, count - out, " "); + } + + out += snprintf(buf + out, count - out, " "); + for (l = 0, i = 0; i < 2; i++) { + out += snprintf(buf + out, count - out, " "); + for (j = 0; j < 8 && l < len; j++, l++) { + c = data[(i * 8 + j)]; + if (!isascii(c) || !isprint(c)) + c = '.'; + + out += snprintf(buf + out, count - out, "%c", c); + } + + for (; j < 8; j++) + out += snprintf(buf + out, count - out, " "); + } + + return buf; +} + +static void printk_buf(int level, const u8 * data, u32 len) +{ + char line[81]; + u32 ofs = 0; + if (!(ipw2100_debug_level & level)) + return; + + while (len) { + printk(KERN_DEBUG "%s\n", + snprint_line(line, sizeof(line), &data[ofs], + min(len, 16U), ofs)); + ofs += 16; + len -= min(len, 16U); + } +} + +#define MAX_RESET_BACKOFF 10 + +static void schedule_reset(struct ipw2100_priv *priv) +{ + unsigned long now = get_seconds(); + + /* If we haven't received a reset request within the backoff period, + * then we can reset the backoff interval so this reset occurs + * immediately */ + if (priv->reset_backoff && + (now - priv->last_reset > priv->reset_backoff)) + priv->reset_backoff = 0; + + priv->last_reset = get_seconds(); + + if (!(priv->status & STATUS_RESET_PENDING)) { + IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n", + priv->net_dev->name, priv->reset_backoff); + netif_carrier_off(priv->net_dev); + netif_stop_queue(priv->net_dev); + priv->status |= STATUS_RESET_PENDING; + if (priv->reset_backoff) + queue_delayed_work(priv->workqueue, &priv->reset_work, + priv->reset_backoff * HZ); + else + queue_delayed_work(priv->workqueue, &priv->reset_work, + 0); + + if (priv->reset_backoff < MAX_RESET_BACKOFF) + priv->reset_backoff++; + + wake_up_interruptible(&priv->wait_command_queue); + } else + IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n", + priv->net_dev->name); + +} + +#define HOST_COMPLETE_TIMEOUT (2 * HZ) +static int ipw2100_hw_send_command(struct ipw2100_priv *priv, + struct host_command *cmd) +{ + struct list_head *element; + struct ipw2100_tx_packet *packet; + unsigned long flags; + int err = 0; + + IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", + command_types[cmd->host_command], cmd->host_command, + cmd->host_command_length); + printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters, + cmd->host_command_length); + + spin_lock_irqsave(&priv->low_lock, flags); + + if (priv->fatal_error) { + IPW_DEBUG_INFO + ("Attempt to send command while hardware in fatal error condition.\n"); + err = -EIO; + goto fail_unlock; + } + + if (!(priv->status & STATUS_RUNNING)) { + IPW_DEBUG_INFO + ("Attempt to send command while hardware is not running.\n"); + err = -EIO; + goto fail_unlock; + } + + if (priv->status & STATUS_CMD_ACTIVE) { + IPW_DEBUG_INFO + ("Attempt to send command while another command is pending.\n"); + err = -EBUSY; + goto fail_unlock; + } + + if (list_empty(&priv->msg_free_list)) { + IPW_DEBUG_INFO("no available msg buffers\n"); + goto fail_unlock; + } + + priv->status |= STATUS_CMD_ACTIVE; + priv->messages_sent++; + + element = priv->msg_free_list.next; + + packet = list_entry(element, struct ipw2100_tx_packet, list); + packet->jiffy_start = jiffies; + + /* initialize the firmware command packet */ + packet->info.c_struct.cmd->host_command_reg = cmd->host_command; + packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1; + packet->info.c_struct.cmd->host_command_len_reg = + cmd->host_command_length; + packet->info.c_struct.cmd->sequence = cmd->host_command_sequence; + + memcpy(packet->info.c_struct.cmd->host_command_params_reg, + cmd->host_command_parameters, + sizeof(packet->info.c_struct.cmd->host_command_params_reg)); + + list_del(element); + DEC_STAT(&priv->msg_free_stat); + + list_add_tail(element, &priv->msg_pend_list); + INC_STAT(&priv->msg_pend_stat); + + ipw2100_tx_send_commands(priv); + ipw2100_tx_send_data(priv); + + spin_unlock_irqrestore(&priv->low_lock, flags); + + /* + * We must wait for this command to complete before another + * command can be sent... but if we wait more than 3 seconds + * then there is a problem. + */ + + err = + wait_event_interruptible_timeout(priv->wait_command_queue, + !(priv-> + status & STATUS_CMD_ACTIVE), + HOST_COMPLETE_TIMEOUT); + + if (err == 0) { + IPW_DEBUG_INFO("Command completion failed out after %dms.\n", + 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); + priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT; + priv->status &= ~STATUS_CMD_ACTIVE; + schedule_reset(priv); + return -EIO; + } + + if (priv->fatal_error) { + printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n", + priv->net_dev->name); + return -EIO; + } + + /* !!!!! HACK TEST !!!!! + * When lots of debug trace statements are enabled, the driver + * doesn't seem to have as many firmware restart cycles... + * + * As a test, we're sticking in a 1/100s delay here */ + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); + + return 0; + + fail_unlock: + spin_unlock_irqrestore(&priv->low_lock, flags); + + return err; +} + +/* + * Verify the values and data access of the hardware + * No locks needed or used. No functions called. + */ +static int ipw2100_verify(struct ipw2100_priv *priv) +{ + u32 data1, data2; + u32 address; + + u32 val1 = 0x76543210; + u32 val2 = 0xFEDCBA98; + + /* Domain 0 check - all values should be DOA_DEBUG */ + for (address = IPW_REG_DOA_DEBUG_AREA_START; + address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) { + read_register(priv->net_dev, address, &data1); + if (data1 != IPW_DATA_DOA_DEBUG_VALUE) + return -EIO; + } + + /* Domain 1 check - use arbitrary read/write compare */ + for (address = 0; address < 5; address++) { + /* The memory area is not used now */ + write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, + val1); + write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, + val2); + read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, + &data1); + read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, + &data2); + if (val1 == data1 && val2 == data2) + return 0; + } + + return -EIO; +} + +/* + * + * Loop until the CARD_DISABLED bit is the same value as the + * supplied parameter + * + * TODO: See if it would be more efficient to do a wait/wake + * cycle and have the completion event trigger the wakeup + * + */ +#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli +static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state) +{ + int i; + u32 card_state; + u32 len = sizeof(card_state); + int err; + + for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) { + err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED, + &card_state, &len); + if (err) { + IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal " + "failed.\n"); + return 0; + } + + /* We'll break out if either the HW state says it is + * in the state we want, or if HOST_COMPLETE command + * finishes */ + if ((card_state == state) || + ((priv->status & STATUS_ENABLED) ? + IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) { + if (state == IPW_HW_STATE_ENABLED) + priv->status |= STATUS_ENABLED; + else + priv->status &= ~STATUS_ENABLED; + + return 0; + } + + udelay(50); + } + + IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n", + state ? "DISABLED" : "ENABLED"); + return -EIO; +} + +/********************************************************************* + Procedure : sw_reset_and_clock + Purpose : Asserts s/w reset, asserts clock initialization + and waits for clock stabilization + ********************************************************************/ +static int sw_reset_and_clock(struct ipw2100_priv *priv) +{ + int i; + u32 r; + + // assert s/w reset + write_register(priv->net_dev, IPW_REG_RESET_REG, + IPW_AUX_HOST_RESET_REG_SW_RESET); + + // wait for clock stabilization + for (i = 0; i < 1000; i++) { + udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY); + + // check clock ready bit + read_register(priv->net_dev, IPW_REG_RESET_REG, &r); + if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET) + break; + } + + if (i == 1000) + return -EIO; // TODO: better error value + + /* set "initialization complete" bit to move adapter to + * D0 state */ + write_register(priv->net_dev, IPW_REG_GP_CNTRL, + IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE); + + /* wait for clock stabilization */ + for (i = 0; i < 10000; i++) { + udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4); + + /* check clock ready bit */ + read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); + if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY) + break; + } + + if (i == 10000) + return -EIO; /* TODO: better error value */ + + /* set D0 standby bit */ + read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); + write_register(priv->net_dev, IPW_REG_GP_CNTRL, + r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); + + return 0; +} + +/********************************************************************* + Procedure : ipw2100_download_firmware + Purpose : Initiaze adapter after power on. + The sequence is: + 1. assert s/w reset first! + 2. awake clocks & wait for clock stabilization + 3. hold ARC (don't ask me why...) + 4. load Dino ucode and reset/clock init again + 5. zero-out shared mem + 6. download f/w + *******************************************************************/ +static int ipw2100_download_firmware(struct ipw2100_priv *priv) +{ + u32 address; + int err; + +#ifndef CONFIG_PM + /* Fetch the firmware and microcode */ + struct ipw2100_fw ipw2100_firmware; +#endif + + if (priv->fatal_error) { + IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after " + "fatal error %d. Interface must be brought down.\n", + priv->net_dev->name, priv->fatal_error); + return -EINVAL; + } +#ifdef CONFIG_PM + if (!ipw2100_firmware.version) { + err = ipw2100_get_firmware(priv, &ipw2100_firmware); + if (err) { + IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", + priv->net_dev->name, err); + priv->fatal_error = IPW2100_ERR_FW_LOAD; + goto fail; + } + } +#else + err = ipw2100_get_firmware(priv, &ipw2100_firmware); + if (err) { + IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", + priv->net_dev->name, err); + priv->fatal_error = IPW2100_ERR_FW_LOAD; + goto fail; + } +#endif + priv->firmware_version = ipw2100_firmware.version; + + /* s/w reset and clock stabilization */ + err = sw_reset_and_clock(priv); + if (err) { + IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n", + priv->net_dev->name, err); + goto fail; + } + + err = ipw2100_verify(priv); + if (err) { + IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n", + priv->net_dev->name, err); + goto fail; + } + + /* Hold ARC */ + write_nic_dword(priv->net_dev, + IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000); + + /* allow ARC to run */ + write_register(priv->net_dev, IPW_REG_RESET_REG, 0); + + /* load microcode */ + err = ipw2100_ucode_download(priv, &ipw2100_firmware); + if (err) { + printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n", + priv->net_dev->name, err); + goto fail; + } + + /* release ARC */ + write_nic_dword(priv->net_dev, + IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000); + + /* s/w reset and clock stabilization (again!!!) */ + err = sw_reset_and_clock(priv); + if (err) { + printk(KERN_ERR DRV_NAME + ": %s: sw_reset_and_clock failed: %d\n", + priv->net_dev->name, err); + goto fail; + } + + /* load f/w */ + err = ipw2100_fw_download(priv, &ipw2100_firmware); + if (err) { + IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n", + priv->net_dev->name, err); + goto fail; + } +#ifndef CONFIG_PM + /* + * When the .resume method of the driver is called, the other + * part of the system, i.e. the ide driver could still stay in + * the suspend stage. This prevents us from loading the firmware + * from the disk. --YZ + */ + + /* free any storage allocated for firmware image */ + ipw2100_release_firmware(priv, &ipw2100_firmware); +#endif + + /* zero out Domain 1 area indirectly (Si requirement) */ + for (address = IPW_HOST_FW_SHARED_AREA0; + address < IPW_HOST_FW_SHARED_AREA0_END; address += 4) + write_nic_dword(priv->net_dev, address, 0); + for (address = IPW_HOST_FW_SHARED_AREA1; + address < IPW_HOST_FW_SHARED_AREA1_END; address += 4) + write_nic_dword(priv->net_dev, address, 0); + for (address = IPW_HOST_FW_SHARED_AREA2; + address < IPW_HOST_FW_SHARED_AREA2_END; address += 4) + write_nic_dword(priv->net_dev, address, 0); + for (address = IPW_HOST_FW_SHARED_AREA3; + address < IPW_HOST_FW_SHARED_AREA3_END; address += 4) + write_nic_dword(priv->net_dev, address, 0); + for (address = IPW_HOST_FW_INTERRUPT_AREA; + address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4) + write_nic_dword(priv->net_dev, address, 0); + + return 0; + + fail: + ipw2100_release_firmware(priv, &ipw2100_firmware); + return err; +} + +static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv) +{ + if (priv->status & STATUS_INT_ENABLED) + return; + priv->status |= STATUS_INT_ENABLED; + write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK); +} + +static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv) +{ + if (!(priv->status & STATUS_INT_ENABLED)) + return; + priv->status &= ~STATUS_INT_ENABLED; + write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0); +} + +static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv) +{ + struct ipw2100_ordinals *ord = &priv->ordinals; + + IPW_DEBUG_INFO("enter\n"); + + read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1, + &ord->table1_addr); + + read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2, + &ord->table2_addr); + + read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size); + read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size); + + ord->table2_size &= 0x0000FFFF; + + IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size); + IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size); + IPW_DEBUG_INFO("exit\n"); +} + +static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv) +{ + u32 reg = 0; + /* + * Set GPIO 3 writable by FW; GPIO 1 writable + * by driver and enable clock + */ + reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE | + IPW_BIT_GPIO_LED_OFF); + write_register(priv->net_dev, IPW_REG_GPIO, reg); +} + +static int rf_kill_active(struct ipw2100_priv *priv) +{ +#define MAX_RF_KILL_CHECKS 5 +#define RF_KILL_CHECK_DELAY 40 + + unsigned short value = 0; + u32 reg = 0; + int i; + + if (!(priv->hw_features & HW_FEATURE_RFKILL)) { + priv->status &= ~STATUS_RF_KILL_HW; + return 0; + } + + for (i = 0; i < MAX_RF_KILL_CHECKS; i++) { + udelay(RF_KILL_CHECK_DELAY); + read_register(priv->net_dev, IPW_REG_GPIO, ®); + value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1); + } + + if (value == 0) + priv->status |= STATUS_RF_KILL_HW; + else + priv->status &= ~STATUS_RF_KILL_HW; + + return (value == 0); +} + +static int ipw2100_get_hw_features(struct ipw2100_priv *priv) +{ + u32 addr, len; + u32 val; + + /* + * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1 + */ + len = sizeof(addr); + if (ipw2100_get_ordinal + (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) { + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + return -EIO; + } + + IPW_DEBUG_INFO("EEPROM address: %08X\n", addr); + + /* + * EEPROM version is the byte at offset 0xfd in firmware + * We read 4 bytes, then shift out the byte we actually want */ + read_nic_dword(priv->net_dev, addr + 0xFC, &val); + priv->eeprom_version = (val >> 24) & 0xFF; + IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version); + + /* + * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware + * + * notice that the EEPROM bit is reverse polarity, i.e. + * bit = 0 signifies HW RF kill switch is supported + * bit = 1 signifies HW RF kill switch is NOT supported + */ + read_nic_dword(priv->net_dev, addr + 0x20, &val); + if (!((val >> 24) & 0x01)) + priv->hw_features |= HW_FEATURE_RFKILL; + + IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n", + (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not "); + + return 0; +} + +/* + * Start firmware execution after power on and intialization + * The sequence is: + * 1. Release ARC + * 2. Wait for f/w initialization completes; + */ +static int ipw2100_start_adapter(struct ipw2100_priv *priv) +{ + int i; + u32 inta, inta_mask, gpio; + + IPW_DEBUG_INFO("enter\n"); + + if (priv->status & STATUS_RUNNING) + return 0; + + /* + * Initialize the hw - drive adapter to DO state by setting + * init_done bit. Wait for clk_ready bit and Download + * fw & dino ucode + */ + if (ipw2100_download_firmware(priv)) { + printk(KERN_ERR DRV_NAME + ": %s: Failed to power on the adapter.\n", + priv->net_dev->name); + return -EIO; + } + + /* Clear the Tx, Rx and Msg queues and the r/w indexes + * in the firmware RBD and TBD ring queue */ + ipw2100_queues_initialize(priv); + + ipw2100_hw_set_gpio(priv); + + /* TODO -- Look at disabling interrupts here to make sure none + * get fired during FW initialization */ + + /* Release ARC - clear reset bit */ + write_register(priv->net_dev, IPW_REG_RESET_REG, 0); + + /* wait for f/w intialization complete */ + IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); + i = 5000; + do { + schedule_timeout_uninterruptible(msecs_to_jiffies(40)); + /* Todo... wait for sync command ... */ + + read_register(priv->net_dev, IPW_REG_INTA, &inta); + + /* check "init done" bit */ + if (inta & IPW2100_INTA_FW_INIT_DONE) { + /* reset "init done" bit */ + write_register(priv->net_dev, IPW_REG_INTA, + IPW2100_INTA_FW_INIT_DONE); + break; + } + + /* check error conditions : we check these after the firmware + * check so that if there is an error, the interrupt handler + * will see it and the adapter will be reset */ + if (inta & + (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) { + /* clear error conditions */ + write_register(priv->net_dev, IPW_REG_INTA, + IPW2100_INTA_FATAL_ERROR | + IPW2100_INTA_PARITY_ERROR); + } + } while (--i); + + /* Clear out any pending INTAs since we aren't supposed to have + * interrupts enabled at this point... */ + read_register(priv->net_dev, IPW_REG_INTA, &inta); + read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); + inta &= IPW_INTERRUPT_MASK; + /* Clear out any pending interrupts */ + if (inta & inta_mask) + write_register(priv->net_dev, IPW_REG_INTA, inta); + + IPW_DEBUG_FW("f/w initialization complete: %s\n", + i ? "SUCCESS" : "FAILED"); + + if (!i) { + printk(KERN_WARNING DRV_NAME + ": %s: Firmware did not initialize.\n", + priv->net_dev->name); + return -EIO; + } + + /* allow firmware to write to GPIO1 & GPIO3 */ + read_register(priv->net_dev, IPW_REG_GPIO, &gpio); + + gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK); + + write_register(priv->net_dev, IPW_REG_GPIO, gpio); + + /* Ready to receive commands */ + priv->status |= STATUS_RUNNING; + + /* The adapter has been reset; we are not associated */ + priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); + + IPW_DEBUG_INFO("exit\n"); + + return 0; +} + +static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv) +{ + if (!priv->fatal_error) + return; + + priv->fatal_errors[priv->fatal_index++] = priv->fatal_error; + priv->fatal_index %= IPW2100_ERROR_QUEUE; + priv->fatal_error = 0; +} + +/* NOTE: Our interrupt is disabled when this method is called */ +static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) +{ + u32 reg; + int i; + + IPW_DEBUG_INFO("Power cycling the hardware.\n"); + + ipw2100_hw_set_gpio(priv); + + /* Step 1. Stop Master Assert */ + write_register(priv->net_dev, IPW_REG_RESET_REG, + IPW_AUX_HOST_RESET_REG_STOP_MASTER); + + /* Step 2. Wait for stop Master Assert + * (not more then 50us, otherwise ret error */ + i = 5; + do { + udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); + read_register(priv->net_dev, IPW_REG_RESET_REG, ®); + + if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) + break; + } while (--i); + + priv->status &= ~STATUS_RESET_PENDING; + + if (!i) { + IPW_DEBUG_INFO + ("exit - waited too long for master assert stop\n"); + return -EIO; + } + + write_register(priv->net_dev, IPW_REG_RESET_REG, + IPW_AUX_HOST_RESET_REG_SW_RESET); + + /* Reset any fatal_error conditions */ + ipw2100_reset_fatalerror(priv); + + /* At this point, the adapter is now stopped and disabled */ + priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING | + STATUS_ASSOCIATED | STATUS_ENABLED); + + return 0; +} + +/* + * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it + * + * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent. + * + * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of + * if STATUS_ASSN_LOST is sent. + */ +static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) +{ + +#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) + + struct host_command cmd = { + .host_command = CARD_DISABLE_PHY_OFF, + .host_command_sequence = 0, + .host_command_length = 0, + }; + int err, i; + u32 val1, val2; + + IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n"); + + /* Turn off the radio */ + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + + for (i = 0; i < 2500; i++) { + read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1); + read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2); + + if ((val1 & IPW2100_CONTROL_PHY_OFF) && + (val2 & IPW2100_COMMAND_PHY_OFF)) + return 0; + + schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY); + } + + return -EIO; +} + +static int ipw2100_enable_adapter(struct ipw2100_priv *priv) +{ + struct host_command cmd = { + .host_command = HOST_COMPLETE, + .host_command_sequence = 0, + .host_command_length = 0 + }; + int err = 0; + + IPW_DEBUG_HC("HOST_COMPLETE\n"); + + if (priv->status & STATUS_ENABLED) + return 0; + + mutex_lock(&priv->adapter_mutex); + + if (rf_kill_active(priv)) { + IPW_DEBUG_HC("Command aborted due to RF kill active.\n"); + goto fail_up; + } + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) { + IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n"); + goto fail_up; + } + + err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED); + if (err) { + IPW_DEBUG_INFO("%s: card not responding to init command.\n", + priv->net_dev->name); + goto fail_up; + } + + if (priv->stop_hang_check) { + priv->stop_hang_check = 0; + queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); + } + + fail_up: + mutex_unlock(&priv->adapter_mutex); + return err; +} + +static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) +{ +#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100)) + + struct host_command cmd = { + .host_command = HOST_PRE_POWER_DOWN, + .host_command_sequence = 0, + .host_command_length = 0, + }; + int err, i; + u32 reg; + + if (!(priv->status & STATUS_RUNNING)) + return 0; + + priv->status |= STATUS_STOPPING; + + /* We can only shut down the card if the firmware is operational. So, + * if we haven't reset since a fatal_error, then we can not send the + * shutdown commands. */ + if (!priv->fatal_error) { + /* First, make sure the adapter is enabled so that the PHY_OFF + * command can shut it down */ + ipw2100_enable_adapter(priv); + + err = ipw2100_hw_phy_off(priv); + if (err) + printk(KERN_WARNING DRV_NAME + ": Error disabling radio %d\n", err); + + /* + * If in D0-standby mode going directly to D3 may cause a + * PCI bus violation. Therefore we must change out of the D0 + * state. + * + * Sending the PREPARE_FOR_POWER_DOWN will restrict the + * hardware from going into standby mode and will transition + * out of D0-standby if it is already in that state. + * + * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the + * driver upon completion. Once received, the driver can + * proceed to the D3 state. + * + * Prepare for power down command to fw. This command would + * take HW out of D0-standby and prepare it for D3 state. + * + * Currently FW does not support event notification for this + * event. Therefore, skip waiting for it. Just wait a fixed + * 100ms + */ + IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n"); + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + printk(KERN_WARNING DRV_NAME ": " + "%s: Power down command failed: Error %d\n", + priv->net_dev->name, err); + else + schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY); + } + + priv->status &= ~STATUS_ENABLED; + + /* + * Set GPIO 3 writable by FW; GPIO 1 writable + * by driver and enable clock + */ + ipw2100_hw_set_gpio(priv); + + /* + * Power down adapter. Sequence: + * 1. Stop master assert (RESET_REG[9]=1) + * 2. Wait for stop master (RESET_REG[8]==1) + * 3. S/w reset assert (RESET_REG[7] = 1) + */ + + /* Stop master assert */ + write_register(priv->net_dev, IPW_REG_RESET_REG, + IPW_AUX_HOST_RESET_REG_STOP_MASTER); + + /* wait stop master not more than 50 usec. + * Otherwise return error. */ + for (i = 5; i > 0; i--) { + udelay(10); + + /* Check master stop bit */ + read_register(priv->net_dev, IPW_REG_RESET_REG, ®); + + if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) + break; + } + + if (i == 0) + printk(KERN_WARNING DRV_NAME + ": %s: Could now power down adapter.\n", + priv->net_dev->name); + + /* assert s/w reset */ + write_register(priv->net_dev, IPW_REG_RESET_REG, + IPW_AUX_HOST_RESET_REG_SW_RESET); + + priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING); + + return 0; +} + +static int ipw2100_disable_adapter(struct ipw2100_priv *priv) +{ + struct host_command cmd = { + .host_command = CARD_DISABLE, + .host_command_sequence = 0, + .host_command_length = 0 + }; + int err = 0; + + IPW_DEBUG_HC("CARD_DISABLE\n"); + + if (!(priv->status & STATUS_ENABLED)) + return 0; + + /* Make sure we clear the associated state */ + priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); + + if (!priv->stop_hang_check) { + priv->stop_hang_check = 1; + cancel_delayed_work(&priv->hang_check); + } + + mutex_lock(&priv->adapter_mutex); + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) { + printk(KERN_WARNING DRV_NAME + ": exit - failed to send CARD_DISABLE command\n"); + goto fail_up; + } + + err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED); + if (err) { + printk(KERN_WARNING DRV_NAME + ": exit - card failed to change to DISABLED\n"); + goto fail_up; + } + + IPW_DEBUG_INFO("TODO: implement scan state machine\n"); + + fail_up: + mutex_unlock(&priv->adapter_mutex); + return err; +} + +static int ipw2100_set_scan_options(struct ipw2100_priv *priv) +{ + struct host_command cmd = { + .host_command = SET_SCAN_OPTIONS, + .host_command_sequence = 0, + .host_command_length = 8 + }; + int err; + + IPW_DEBUG_INFO("enter\n"); + + IPW_DEBUG_SCAN("setting scan options\n"); + + cmd.host_command_parameters[0] = 0; + + if (!(priv->config & CFG_ASSOCIATE)) + cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE; + if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled) + cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL; + if (priv->config & CFG_PASSIVE_SCAN) + cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE; + + cmd.host_command_parameters[1] = priv->channel_mask; + + err = ipw2100_hw_send_command(priv, &cmd); + + IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n", + cmd.host_command_parameters[0]); + + return err; +} + +static int ipw2100_start_scan(struct ipw2100_priv *priv) +{ + struct host_command cmd = { + .host_command = BROADCAST_SCAN, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + IPW_DEBUG_HC("START_SCAN\n"); + + cmd.host_command_parameters[0] = 0; + + /* No scanning if in monitor mode */ + if (priv->ieee->iw_mode == IW_MODE_MONITOR) + return 1; + + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_SCAN("Scan requested while already in scan...\n"); + return 0; + } + + IPW_DEBUG_INFO("enter\n"); + + /* Not clearing here; doing so makes iwlist always return nothing... + * + * We should modify the table logic to use aging tables vs. clearing + * the table on each scan start. + */ + IPW_DEBUG_SCAN("starting scan\n"); + + priv->status |= STATUS_SCANNING; + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + priv->status &= ~STATUS_SCANNING; + + IPW_DEBUG_INFO("exit\n"); + + return err; +} + +static const struct ieee80211_geo ipw_geos[] = { + { /* Restricted */ + "---", + .bg_channels = 14, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14}}, + }, +}; + +static int ipw2100_up(struct ipw2100_priv *priv, int deferred) +{ + unsigned long flags; + int rc = 0; + u32 lock; + u32 ord_len = sizeof(lock); + + /* Quite if manually disabled. */ + if (priv->status & STATUS_RF_KILL_SW) { + IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable " + "switch\n", priv->net_dev->name); + return 0; + } + + /* the ipw2100 hardware really doesn't want power management delays + * longer than 175usec + */ + pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175); + + /* If the interrupt is enabled, turn it off... */ + spin_lock_irqsave(&priv->low_lock, flags); + ipw2100_disable_interrupts(priv); + + /* Reset any fatal_error conditions */ + ipw2100_reset_fatalerror(priv); + spin_unlock_irqrestore(&priv->low_lock, flags); + + if (priv->status & STATUS_POWERED || + (priv->status & STATUS_RESET_PENDING)) { + /* Power cycle the card ... */ + if (ipw2100_power_cycle_adapter(priv)) { + printk(KERN_WARNING DRV_NAME + ": %s: Could not cycle adapter.\n", + priv->net_dev->name); + rc = 1; + goto exit; + } + } else + priv->status |= STATUS_POWERED; + + /* Load the firmware, start the clocks, etc. */ + if (ipw2100_start_adapter(priv)) { + printk(KERN_ERR DRV_NAME + ": %s: Failed to start the firmware.\n", + priv->net_dev->name); + rc = 1; + goto exit; + } + + ipw2100_initialize_ordinals(priv); + + /* Determine capabilities of this particular HW configuration */ + if (ipw2100_get_hw_features(priv)) { + printk(KERN_ERR DRV_NAME + ": %s: Failed to determine HW features.\n", + priv->net_dev->name); + rc = 1; + goto exit; + } + + /* Initialize the geo */ + if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) { + printk(KERN_WARNING DRV_NAME "Could not set geo\n"); + return 0; + } + priv->ieee->freq_band = IEEE80211_24GHZ_BAND; + + lock = LOCK_NONE; + if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { + printk(KERN_ERR DRV_NAME + ": %s: Failed to clear ordinal lock.\n", + priv->net_dev->name); + rc = 1; + goto exit; + } + + priv->status &= ~STATUS_SCANNING; + + if (rf_kill_active(priv)) { + printk(KERN_INFO "%s: Radio is disabled by RF switch.\n", + priv->net_dev->name); + + if (priv->stop_rf_kill) { + priv->stop_rf_kill = 0; + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies_relative(HZ)); + } + + deferred = 1; + } + + /* Turn on the interrupt so that commands can be processed */ + ipw2100_enable_interrupts(priv); + + /* Send all of the commands that must be sent prior to + * HOST_COMPLETE */ + if (ipw2100_adapter_setup(priv)) { + printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n", + priv->net_dev->name); + rc = 1; + goto exit; + } + + if (!deferred) { + /* Enable the adapter - sends HOST_COMPLETE */ + if (ipw2100_enable_adapter(priv)) { + printk(KERN_ERR DRV_NAME ": " + "%s: failed in call to enable adapter.\n", + priv->net_dev->name); + ipw2100_hw_stop_adapter(priv); + rc = 1; + goto exit; + } + + /* Start a scan . . . */ + ipw2100_set_scan_options(priv); + ipw2100_start_scan(priv); + } + + exit: + return rc; +} + +/* Called by register_netdev() */ +static int ipw2100_net_init(struct net_device *dev) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ipw2100_up(priv, 1); +} + +static void ipw2100_down(struct ipw2100_priv *priv) +{ + unsigned long flags; + union iwreq_data wrqu = { + .ap_addr = { + .sa_family = ARPHRD_ETHER} + }; + int associated = priv->status & STATUS_ASSOCIATED; + + /* Kill the RF switch timer */ + if (!priv->stop_rf_kill) { + priv->stop_rf_kill = 1; + cancel_delayed_work(&priv->rf_kill); + } + + /* Kill the firmare hang check timer */ + if (!priv->stop_hang_check) { + priv->stop_hang_check = 1; + cancel_delayed_work(&priv->hang_check); + } + + /* Kill any pending resets */ + if (priv->status & STATUS_RESET_PENDING) + cancel_delayed_work(&priv->reset_work); + + /* Make sure the interrupt is on so that FW commands will be + * processed correctly */ + spin_lock_irqsave(&priv->low_lock, flags); + ipw2100_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->low_lock, flags); + + if (ipw2100_hw_stop_adapter(priv)) + printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n", + priv->net_dev->name); + + /* Do not disable the interrupt until _after_ we disable + * the adaptor. Otherwise the CARD_DISABLE command will never + * be ack'd by the firmware */ + spin_lock_irqsave(&priv->low_lock, flags); + ipw2100_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->low_lock, flags); + + pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", + PM_QOS_DEFAULT_VALUE); + + /* We have to signal any supplicant if we are disassociating */ + if (associated) + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); + + priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); + netif_carrier_off(priv->net_dev); + netif_stop_queue(priv->net_dev); +} + +static void ipw2100_reset_adapter(struct work_struct *work) +{ + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, reset_work.work); + unsigned long flags; + union iwreq_data wrqu = { + .ap_addr = { + .sa_family = ARPHRD_ETHER} + }; + int associated = priv->status & STATUS_ASSOCIATED; + + spin_lock_irqsave(&priv->low_lock, flags); + IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name); + priv->resets++; + priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); + priv->status |= STATUS_SECURITY_UPDATED; + + /* Force a power cycle even if interface hasn't been opened + * yet */ + cancel_delayed_work(&priv->reset_work); + priv->status |= STATUS_RESET_PENDING; + spin_unlock_irqrestore(&priv->low_lock, flags); + + mutex_lock(&priv->action_mutex); + /* stop timed checks so that they don't interfere with reset */ + priv->stop_hang_check = 1; + cancel_delayed_work(&priv->hang_check); + + /* We have to signal any supplicant if we are disassociating */ + if (associated) + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); + + ipw2100_up(priv, 0); + mutex_unlock(&priv->action_mutex); + +} + +static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) +{ + +#define MAC_ASSOCIATION_READ_DELAY (HZ) + int ret, len, essid_len; + char essid[IW_ESSID_MAX_SIZE]; + u32 txrate; + u32 chan; + char *txratename; + u8 bssid[ETH_ALEN]; + DECLARE_SSID_BUF(ssid); + + /* + * TBD: BSSID is usually 00:00:00:00:00:00 here and not + * an actual MAC of the AP. Seems like FW sets this + * address too late. Read it later and expose through + * /proc or schedule a later task to query and update + */ + + essid_len = IW_ESSID_MAX_SIZE; + ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, + essid, &essid_len); + if (ret) { + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + return; + } + + len = sizeof(u32); + ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len); + if (ret) { + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + return; + } + + len = sizeof(u32); + ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len); + if (ret) { + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + return; + } + len = ETH_ALEN; + ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); + if (ret) { + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + return; + } + memcpy(priv->ieee->bssid, bssid, ETH_ALEN); + + switch (txrate) { + case TX_RATE_1_MBIT: + txratename = "1Mbps"; + break; + case TX_RATE_2_MBIT: + txratename = "2Mbsp"; + break; + case TX_RATE_5_5_MBIT: + txratename = "5.5Mbps"; + break; + case TX_RATE_11_MBIT: + txratename = "11Mbps"; + break; + default: + IPW_DEBUG_INFO("Unknown rate: %d\n", txrate); + txratename = "unknown rate"; + break; + } + + IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", + priv->net_dev->name, print_ssid(ssid, essid, essid_len), + txratename, chan, bssid); + + /* now we copy read ssid into dev */ + if (!(priv->config & CFG_STATIC_ESSID)) { + priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->essid, essid, priv->essid_len); + } + priv->channel = chan; + memcpy(priv->bssid, bssid, ETH_ALEN); + + priv->status |= STATUS_ASSOCIATING; + priv->connect_start = get_seconds(); + + queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10); +} + +static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, + int length, int batch_mode) +{ + int ssid_len = min(length, IW_ESSID_MAX_SIZE); + struct host_command cmd = { + .host_command = SSID, + .host_command_sequence = 0, + .host_command_length = ssid_len + }; + int err; + DECLARE_SSID_BUF(ssid); + + IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len)); + + if (ssid_len) + memcpy(cmd.host_command_parameters, essid, ssid_len); + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to + * disable auto association -- so we cheat by setting a bogus SSID */ + if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) { + int i; + u8 *bogus = (u8 *) cmd.host_command_parameters; + for (i = 0; i < IW_ESSID_MAX_SIZE; i++) + bogus[i] = 0x18 + i; + cmd.host_command_length = IW_ESSID_MAX_SIZE; + } + + /* NOTE: We always send the SSID command even if the provided ESSID is + * the same as what we currently think is set. */ + + err = ipw2100_hw_send_command(priv, &cmd); + if (!err) { + memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len); + memcpy(priv->essid, essid, ssid_len); + priv->essid_len = ssid_len; + } + + if (!batch_mode) { + if (ipw2100_enable_adapter(priv)) + err = -EIO; + } + + return err; +} + +static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) +{ + DECLARE_SSID_BUF(ssid); + + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); + + priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); + + if (priv->status & STATUS_STOPPING) { + IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n"); + return; + } + + memset(priv->bssid, 0, ETH_ALEN); + memset(priv->ieee->bssid, 0, ETH_ALEN); + + netif_carrier_off(priv->net_dev); + netif_stop_queue(priv->net_dev); + + if (!(priv->status & STATUS_RUNNING)) + return; + + if (priv->status & STATUS_SECURITY_UPDATED) + queue_delayed_work(priv->workqueue, &priv->security_work, 0); + + queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0); +} + +static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) +{ + IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n", + priv->net_dev->name); + + /* RF_KILL is now enabled (else we wouldn't be here) */ + priv->status |= STATUS_RF_KILL_HW; + + /* Make sure the RF Kill check timer is running */ + priv->stop_rf_kill = 0; + cancel_delayed_work(&priv->rf_kill); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies_relative(HZ)); +} + +static void send_scan_event(void *data) +{ + struct ipw2100_priv *priv = data; + union iwreq_data wrqu; + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); +} + +static void ipw2100_scan_event_later(struct work_struct *work) +{ + send_scan_event(container_of(work, struct ipw2100_priv, + scan_event_later.work)); +} + +static void ipw2100_scan_event_now(struct work_struct *work) +{ + send_scan_event(container_of(work, struct ipw2100_priv, + scan_event_now)); +} + +static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) +{ + IPW_DEBUG_SCAN("scan complete\n"); + /* Age the scan results... */ + priv->ieee->scans++; + priv->status &= ~STATUS_SCANNING; + + /* Only userspace-requested scan completion events go out immediately */ + if (!priv->user_requested_scan) { + if (!delayed_work_pending(&priv->scan_event_later)) + queue_delayed_work(priv->workqueue, + &priv->scan_event_later, + round_jiffies_relative(msecs_to_jiffies(4000))); + } else { + priv->user_requested_scan = 0; + cancel_delayed_work(&priv->scan_event_later); + queue_work(priv->workqueue, &priv->scan_event_now); + } +} + +#ifdef CONFIG_IPW2100_DEBUG +#define IPW2100_HANDLER(v, f) { v, f, # v } +struct ipw2100_status_indicator { + int status; + void (*cb) (struct ipw2100_priv * priv, u32 status); + char *name; +}; +#else +#define IPW2100_HANDLER(v, f) { v, f } +struct ipw2100_status_indicator { + int status; + void (*cb) (struct ipw2100_priv * priv, u32 status); +}; +#endif /* CONFIG_IPW2100_DEBUG */ + +static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status) +{ + IPW_DEBUG_SCAN("Scanning...\n"); + priv->status |= STATUS_SCANNING; +} + +static const struct ipw2100_status_indicator status_handlers[] = { + IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL), + IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL), + IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated), + IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost), + IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL), + IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete), + IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL), + IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL), + IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill), + IPW2100_HANDLER(IPW_STATE_DISABLED, NULL), + IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL), + IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning), + IPW2100_HANDLER(-1, NULL) +}; + +static void isr_status_change(struct ipw2100_priv *priv, int status) +{ + int i; + + if (status == IPW_STATE_SCANNING && + priv->status & STATUS_ASSOCIATED && + !(priv->status & STATUS_SCANNING)) { + IPW_DEBUG_INFO("Scan detected while associated, with " + "no scan request. Restarting firmware.\n"); + + /* Wake up any sleeping jobs */ + schedule_reset(priv); + } + + for (i = 0; status_handlers[i].status != -1; i++) { + if (status == status_handlers[i].status) { + IPW_DEBUG_NOTIF("Status change: %s\n", + status_handlers[i].name); + if (status_handlers[i].cb) + status_handlers[i].cb(priv, status); + priv->wstats.status = status; + return; + } + } + + IPW_DEBUG_NOTIF("unknown status received: %04x\n", status); +} + +static void isr_rx_complete_command(struct ipw2100_priv *priv, + struct ipw2100_cmd_header *cmd) +{ +#ifdef CONFIG_IPW2100_DEBUG + if (cmd->host_command_reg < ARRAY_SIZE(command_types)) { + IPW_DEBUG_HC("Command completed '%s (%d)'\n", + command_types[cmd->host_command_reg], + cmd->host_command_reg); + } +#endif + if (cmd->host_command_reg == HOST_COMPLETE) + priv->status |= STATUS_ENABLED; + + if (cmd->host_command_reg == CARD_DISABLE) + priv->status &= ~STATUS_ENABLED; + + priv->status &= ~STATUS_CMD_ACTIVE; + + wake_up_interruptible(&priv->wait_command_queue); +} + +#ifdef CONFIG_IPW2100_DEBUG +static const char *frame_types[] = { + "COMMAND_STATUS_VAL", + "STATUS_CHANGE_VAL", + "P80211_DATA_VAL", + "P8023_DATA_VAL", + "HOST_NOTIFICATION_VAL" +}; +#endif + +static int ipw2100_alloc_skb(struct ipw2100_priv *priv, + struct ipw2100_rx_packet *packet) +{ + packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx)); + if (!packet->skb) + return -ENOMEM; + + packet->rxp = (struct ipw2100_rx *)packet->skb->data; + packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, + sizeof(struct ipw2100_rx), + PCI_DMA_FROMDEVICE); + /* NOTE: pci_map_single does not return an error code, and 0 is a valid + * dma_addr */ + + return 0; +} + +#define SEARCH_ERROR 0xffffffff +#define SEARCH_FAIL 0xfffffffe +#define SEARCH_SUCCESS 0xfffffff0 +#define SEARCH_DISCARD 0 +#define SEARCH_SNAPSHOT 1 + +#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff)) +static void ipw2100_snapshot_free(struct ipw2100_priv *priv) +{ + int i; + if (!priv->snapshot[0]) + return; + for (i = 0; i < 0x30; i++) + kfree(priv->snapshot[i]); + priv->snapshot[0] = NULL; +} + +#ifdef IPW2100_DEBUG_C3 +static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv) +{ + int i; + if (priv->snapshot[0]) + return 1; + for (i = 0; i < 0x30; i++) { + priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC); + if (!priv->snapshot[i]) { + IPW_DEBUG_INFO("%s: Error allocating snapshot " + "buffer %d\n", priv->net_dev->name, i); + while (i > 0) + kfree(priv->snapshot[--i]); + priv->snapshot[0] = NULL; + return 0; + } + } + + return 1; +} + +static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, + size_t len, int mode) +{ + u32 i, j; + u32 tmp; + u8 *s, *d; + u32 ret; + + s = in_buf; + if (mode == SEARCH_SNAPSHOT) { + if (!ipw2100_snapshot_alloc(priv)) + mode = SEARCH_DISCARD; + } + + for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) { + read_nic_dword(priv->net_dev, i, &tmp); + if (mode == SEARCH_SNAPSHOT) + *(u32 *) SNAPSHOT_ADDR(i) = tmp; + if (ret == SEARCH_FAIL) { + d = (u8 *) & tmp; + for (j = 0; j < 4; j++) { + if (*s != *d) { + s = in_buf; + continue; + } + + s++; + d++; + + if ((s - in_buf) == len) + ret = (i + j) - len + 1; + } + } else if (mode == SEARCH_DISCARD) + return ret; + } + + return ret; +} +#endif + +/* + * + * 0) Disconnect the SKB from the firmware (just unmap) + * 1) Pack the ETH header into the SKB + * 2) Pass the SKB to the network stack + * + * When packet is provided by the firmware, it contains the following: + * + * . ieee80211_hdr + * . ieee80211_snap_hdr + * + * The size of the constructed ethernet + * + */ +#ifdef IPW2100_RX_DEBUG +static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH]; +#endif + +static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) +{ +#ifdef IPW2100_DEBUG_C3 + struct ipw2100_status *status = &priv->status_queue.drv[i]; + u32 match, reg; + int j; +#endif + + IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n", + i * sizeof(struct ipw2100_status)); + +#ifdef IPW2100_DEBUG_C3 + /* Halt the fimrware so we can get a good image */ + write_register(priv->net_dev, IPW_REG_RESET_REG, + IPW_AUX_HOST_RESET_REG_STOP_MASTER); + j = 5; + do { + udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); + read_register(priv->net_dev, IPW_REG_RESET_REG, ®); + + if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) + break; + } while (j--); + + match = ipw2100_match_buf(priv, (u8 *) status, + sizeof(struct ipw2100_status), + SEARCH_SNAPSHOT); + if (match < SEARCH_SUCCESS) + IPW_DEBUG_INFO("%s: DMA status match in Firmware at " + "offset 0x%06X, length %d:\n", + priv->net_dev->name, match, + sizeof(struct ipw2100_status)); + else + IPW_DEBUG_INFO("%s: No DMA status match in " + "Firmware.\n", priv->net_dev->name); + + printk_buf((u8 *) priv->status_queue.drv, + sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH); +#endif + + priv->fatal_error = IPW2100_ERR_C3_CORRUPTION; + priv->ieee->stats.rx_errors++; + schedule_reset(priv); +} + +static void isr_rx(struct ipw2100_priv *priv, int i, + struct ieee80211_rx_stats *stats) +{ + struct ipw2100_status *status = &priv->status_queue.drv[i]; + struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; + + IPW_DEBUG_RX("Handler...\n"); + + if (unlikely(status->frame_size > skb_tailroom(packet->skb))) { + IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" + " Dropping.\n", + priv->net_dev->name, + status->frame_size, skb_tailroom(packet->skb)); + priv->ieee->stats.rx_errors++; + return; + } + + if (unlikely(!netif_running(priv->net_dev))) { + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && + !(priv->status & STATUS_ASSOCIATED))) { + IPW_DEBUG_DROP("Dropping packet while not associated.\n"); + priv->wstats.discard.misc++; + return; + } + + pci_unmap_single(priv->pci_dev, + packet->dma_addr, + sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + + skb_put(packet->skb, status->frame_size); + +#ifdef IPW2100_RX_DEBUG + /* Make a copy of the frame so we can dump it to the logs if + * ieee80211_rx fails */ + skb_copy_from_linear_data(packet->skb, packet_data, + min_t(u32, status->frame_size, + IPW_RX_NIC_BUFFER_LENGTH)); +#endif + + if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { +#ifdef IPW2100_RX_DEBUG + IPW_DEBUG_DROP("%s: Non consumed packet:\n", + priv->net_dev->name); + printk_buf(IPW_DL_DROP, packet_data, status->frame_size); +#endif + priv->ieee->stats.rx_errors++; + + /* ieee80211_rx failed, so it didn't free the SKB */ + dev_kfree_skb_any(packet->skb); + packet->skb = NULL; + } + + /* We need to allocate a new SKB and attach it to the RDB. */ + if (unlikely(ipw2100_alloc_skb(priv, packet))) { + printk(KERN_WARNING DRV_NAME ": " + "%s: Unable to allocate SKB onto RBD ring - disabling " + "adapter.\n", priv->net_dev->name); + /* TODO: schedule adapter shutdown */ + IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); + } + + /* Update the RDB entry */ + priv->rx_queue.drv[i].host_addr = packet->dma_addr; +} + +#ifdef CONFIG_IPW2100_MONITOR + +static void isr_rx_monitor(struct ipw2100_priv *priv, int i, + struct ieee80211_rx_stats *stats) +{ + struct ipw2100_status *status = &priv->status_queue.drv[i]; + struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; + + /* Magic struct that slots into the radiotap header -- no reason + * to build this manually element by element, we can write it much + * more efficiently than we can parse it. ORDER MATTERS HERE */ + struct ipw_rt_hdr { + struct ieee80211_radiotap_header rt_hdr; + s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ + } *ipw_rt; + + IPW_DEBUG_RX("Handler...\n"); + + if (unlikely(status->frame_size > skb_tailroom(packet->skb) - + sizeof(struct ipw_rt_hdr))) { + IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" + " Dropping.\n", + priv->net_dev->name, + status->frame_size, + skb_tailroom(packet->skb)); + priv->ieee->stats.rx_errors++; + return; + } + + if (unlikely(!netif_running(priv->net_dev))) { + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + if (unlikely(priv->config & CFG_CRC_CHECK && + status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { + IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); + priv->ieee->stats.rx_errors++; + return; + } + + pci_unmap_single(priv->pci_dev, packet->dma_addr, + sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), + packet->skb->data, status->frame_size); + + ipw_rt = (struct ipw_rt_hdr *) packet->skb->data; + + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ + ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */ + + ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); + + ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM; + + skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); + + if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { + priv->ieee->stats.rx_errors++; + + /* ieee80211_rx failed, so it didn't free the SKB */ + dev_kfree_skb_any(packet->skb); + packet->skb = NULL; + } + + /* We need to allocate a new SKB and attach it to the RDB. */ + if (unlikely(ipw2100_alloc_skb(priv, packet))) { + IPW_DEBUG_WARNING( + "%s: Unable to allocate SKB onto RBD ring - disabling " + "adapter.\n", priv->net_dev->name); + /* TODO: schedule adapter shutdown */ + IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); + } + + /* Update the RDB entry */ + priv->rx_queue.drv[i].host_addr = packet->dma_addr; +} + +#endif + +static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) +{ + struct ipw2100_status *status = &priv->status_queue.drv[i]; + struct ipw2100_rx *u = priv->rx_buffers[i].rxp; + u16 frame_type = status->status_fields & STATUS_TYPE_MASK; + + switch (frame_type) { + case COMMAND_STATUS_VAL: + return (status->frame_size != sizeof(u->rx_data.command)); + case STATUS_CHANGE_VAL: + return (status->frame_size != sizeof(u->rx_data.status)); + case HOST_NOTIFICATION_VAL: + return (status->frame_size < sizeof(u->rx_data.notification)); + case P80211_DATA_VAL: + case P8023_DATA_VAL: +#ifdef CONFIG_IPW2100_MONITOR + return 0; +#else + switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { + case IEEE80211_FTYPE_MGMT: + case IEEE80211_FTYPE_CTL: + return 0; + case IEEE80211_FTYPE_DATA: + return (status->frame_size > + IPW_MAX_802_11_PAYLOAD_LENGTH); + } +#endif + } + + return 1; +} + +/* + * ipw2100 interrupts are disabled at this point, and the ISR + * is the only code that calls this method. So, we do not need + * to play with any locks. + * + * RX Queue works as follows: + * + * Read index - firmware places packet in entry identified by the + * Read index and advances Read index. In this manner, + * Read index will always point to the next packet to + * be filled--but not yet valid. + * + * Write index - driver fills this entry with an unused RBD entry. + * This entry has not filled by the firmware yet. + * + * In between the W and R indexes are the RBDs that have been received + * but not yet processed. + * + * The process of handling packets will start at WRITE + 1 and advance + * until it reaches the READ index. + * + * The WRITE index is cached in the variable 'priv->rx_queue.next'. + * + */ +static void __ipw2100_rx_process(struct ipw2100_priv *priv) +{ + struct ipw2100_bd_queue *rxq = &priv->rx_queue; + struct ipw2100_status_queue *sq = &priv->status_queue; + struct ipw2100_rx_packet *packet; + u16 frame_type; + u32 r, w, i, s; + struct ipw2100_rx *u; + struct ieee80211_rx_stats stats = { + .mac_time = jiffies, + }; + + read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r); + read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w); + + if (r >= rxq->entries) { + IPW_DEBUG_RX("exit - bad read index\n"); + return; + } + + i = (rxq->next + 1) % rxq->entries; + s = i; + while (i != r) { + /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n", + r, rxq->next, i); */ + + packet = &priv->rx_buffers[i]; + + /* Sync the DMA for the STATUS buffer so CPU is sure to get + * the correct values */ + pci_dma_sync_single_for_cpu(priv->pci_dev, + sq->nic + + sizeof(struct ipw2100_status) * i, + sizeof(struct ipw2100_status), + PCI_DMA_FROMDEVICE); + + /* Sync the DMA for the RX buffer so CPU is sure to get + * the correct values */ + pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, + sizeof(struct ipw2100_rx), + PCI_DMA_FROMDEVICE); + + if (unlikely(ipw2100_corruption_check(priv, i))) { + ipw2100_corruption_detected(priv, i); + goto increment; + } + + u = packet->rxp; + frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK; + stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM; + stats.len = sq->drv[i].frame_size; + + stats.mask = 0; + if (stats.rssi != 0) + stats.mask |= IEEE80211_STATMASK_RSSI; + stats.freq = IEEE80211_24GHZ_BAND; + + IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n", + priv->net_dev->name, frame_types[frame_type], + stats.len); + + switch (frame_type) { + case COMMAND_STATUS_VAL: + /* Reset Rx watchdog */ + isr_rx_complete_command(priv, &u->rx_data.command); + break; + + case STATUS_CHANGE_VAL: + isr_status_change(priv, u->rx_data.status); + break; + + case P80211_DATA_VAL: + case P8023_DATA_VAL: +#ifdef CONFIG_IPW2100_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + isr_rx_monitor(priv, i, &stats); + break; + } +#endif + if (stats.len < sizeof(struct ieee80211_hdr_3addr)) + break; + switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(priv->ieee, + &u->rx_data.header, &stats); + break; + + case IEEE80211_FTYPE_CTL: + break; + + case IEEE80211_FTYPE_DATA: + isr_rx(priv, i, &stats); + break; + + } + break; + } + + increment: + /* clear status field associated with this RBD */ + rxq->drv[i].status.info.field = 0; + + i = (i + 1) % rxq->entries; + } + + if (i != s) { + /* backtrack one entry, wrapping to end if at 0 */ + rxq->next = (i ? i : rxq->entries) - 1; + + write_register(priv->net_dev, + IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next); + } +} + +/* + * __ipw2100_tx_process + * + * This routine will determine whether the next packet on + * the fw_pend_list has been processed by the firmware yet. + * + * If not, then it does nothing and returns. + * + * If so, then it removes the item from the fw_pend_list, frees + * any associated storage, and places the item back on the + * free list of its source (either msg_free_list or tx_free_list) + * + * TX Queue works as follows: + * + * Read index - points to the next TBD that the firmware will + * process. The firmware will read the data, and once + * done processing, it will advance the Read index. + * + * Write index - driver fills this entry with an constructed TBD + * entry. The Write index is not advanced until the + * packet has been configured. + * + * In between the W and R indexes are the TBDs that have NOT been + * processed. Lagging behind the R index are packets that have + * been processed but have not been freed by the driver. + * + * In order to free old storage, an internal index will be maintained + * that points to the next packet to be freed. When all used + * packets have been freed, the oldest index will be the same as the + * firmware's read index. + * + * The OLDEST index is cached in the variable 'priv->tx_queue.oldest' + * + * Because the TBD structure can not contain arbitrary data, the + * driver must keep an internal queue of cached allocations such that + * it can put that data back into the tx_free_list and msg_free_list + * for use by future command and data packets. + * + */ +static int __ipw2100_tx_process(struct ipw2100_priv *priv) +{ + struct ipw2100_bd_queue *txq = &priv->tx_queue; + struct ipw2100_bd *tbd; + struct list_head *element; + struct ipw2100_tx_packet *packet; + int descriptors_used; + int e, i; + u32 r, w, frag_num = 0; + + if (list_empty(&priv->fw_pend_list)) + return 0; + + element = priv->fw_pend_list.next; + + packet = list_entry(element, struct ipw2100_tx_packet, list); + tbd = &txq->drv[packet->index]; + + /* Determine how many TBD entries must be finished... */ + switch (packet->type) { + case COMMAND: + /* COMMAND uses only one slot; don't advance */ + descriptors_used = 1; + e = txq->oldest; + break; + + case DATA: + /* DATA uses two slots; advance and loop position. */ + descriptors_used = tbd->num_fragments; + frag_num = tbd->num_fragments - 1; + e = txq->oldest + frag_num; + e %= txq->entries; + break; + + default: + printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n", + priv->net_dev->name); + return 0; + } + + /* if the last TBD is not done by NIC yet, then packet is + * not ready to be released. + * + */ + read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX, + &r); + read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, + &w); + if (w != txq->next) + printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n", + priv->net_dev->name); + + /* + * txq->next is the index of the last packet written txq->oldest is + * the index of the r is the index of the next packet to be read by + * firmware + */ + + /* + * Quick graphic to help you visualize the following + * if / else statement + * + * ===>| s---->|=============== + * e>| + * | a | b | c | d | e | f | g | h | i | j | k | l + * r---->| + * w + * + * w - updated by driver + * r - updated by firmware + * s - start of oldest BD entry (txq->oldest) + * e - end of oldest BD entry + * + */ + if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) { + IPW_DEBUG_TX("exit - no processed packets ready to release.\n"); + return 0; + } + + list_del(element); + DEC_STAT(&priv->fw_pend_stat); + +#ifdef CONFIG_IPW2100_DEBUG + { + int i = txq->oldest; + IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, + &txq->drv[i], + (u32) (txq->nic + i * sizeof(struct ipw2100_bd)), + txq->drv[i].host_addr, txq->drv[i].buf_length); + + if (packet->type == DATA) { + i = (i + 1) % txq->entries; + + IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, + &txq->drv[i], + (u32) (txq->nic + i * + sizeof(struct ipw2100_bd)), + (u32) txq->drv[i].host_addr, + txq->drv[i].buf_length); + } + } +#endif + + switch (packet->type) { + case DATA: + if (txq->drv[txq->oldest].status.info.fields.txType != 0) + printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. " + "Expecting DATA TBD but pulled " + "something else: ids %d=%d.\n", + priv->net_dev->name, txq->oldest, packet->index); + + /* DATA packet; we have to unmap and free the SKB */ + for (i = 0; i < frag_num; i++) { + tbd = &txq->drv[(packet->index + 1 + i) % txq->entries]; + + IPW_DEBUG_TX("TX%d P=%08x L=%d\n", + (packet->index + 1 + i) % txq->entries, + tbd->host_addr, tbd->buf_length); + + pci_unmap_single(priv->pci_dev, + tbd->host_addr, + tbd->buf_length, PCI_DMA_TODEVICE); + } + + ieee80211_txb_free(packet->info.d_struct.txb); + packet->info.d_struct.txb = NULL; + + list_add_tail(element, &priv->tx_free_list); + INC_STAT(&priv->tx_free_stat); + + /* We have a free slot in the Tx queue, so wake up the + * transmit layer if it is stopped. */ + if (priv->status & STATUS_ASSOCIATED) + netif_wake_queue(priv->net_dev); + + /* A packet was processed by the hardware, so update the + * watchdog */ + priv->net_dev->trans_start = jiffies; + + break; + + case COMMAND: + if (txq->drv[txq->oldest].status.info.fields.txType != 1) + printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. " + "Expecting COMMAND TBD but pulled " + "something else: ids %d=%d.\n", + priv->net_dev->name, txq->oldest, packet->index); + +#ifdef CONFIG_IPW2100_DEBUG + if (packet->info.c_struct.cmd->host_command_reg < + ARRAY_SIZE(command_types)) + IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n", + command_types[packet->info.c_struct.cmd-> + host_command_reg], + packet->info.c_struct.cmd-> + host_command_reg, + packet->info.c_struct.cmd->cmd_status_reg); +#endif + + list_add_tail(element, &priv->msg_free_list); + INC_STAT(&priv->msg_free_stat); + break; + } + + /* advance oldest used TBD pointer to start of next entry */ + txq->oldest = (e + 1) % txq->entries; + /* increase available TBDs number */ + txq->available += descriptors_used; + SET_STAT(&priv->txq_stat, txq->available); + + IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n", + jiffies - packet->jiffy_start); + + return (!list_empty(&priv->fw_pend_list)); +} + +static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv) +{ + int i = 0; + + while (__ipw2100_tx_process(priv) && i < 200) + i++; + + if (i == 200) { + printk(KERN_WARNING DRV_NAME ": " + "%s: Driver is running slow (%d iters).\n", + priv->net_dev->name, i); + } +} + +static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) +{ + struct list_head *element; + struct ipw2100_tx_packet *packet; + struct ipw2100_bd_queue *txq = &priv->tx_queue; + struct ipw2100_bd *tbd; + int next = txq->next; + + while (!list_empty(&priv->msg_pend_list)) { + /* if there isn't enough space in TBD queue, then + * don't stuff a new one in. + * NOTE: 3 are needed as a command will take one, + * and there is a minimum of 2 that must be + * maintained between the r and w indexes + */ + if (txq->available <= 3) { + IPW_DEBUG_TX("no room in tx_queue\n"); + break; + } + + element = priv->msg_pend_list.next; + list_del(element); + DEC_STAT(&priv->msg_pend_stat); + + packet = list_entry(element, struct ipw2100_tx_packet, list); + + IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n", + &txq->drv[txq->next], + (void *)(txq->nic + txq->next * + sizeof(struct ipw2100_bd))); + + packet->index = txq->next; + + tbd = &txq->drv[txq->next]; + + /* initialize TBD */ + tbd->host_addr = packet->info.c_struct.cmd_phys; + tbd->buf_length = sizeof(struct ipw2100_cmd_header); + /* not marking number of fragments causes problems + * with f/w debug version */ + tbd->num_fragments = 1; + tbd->status.info.field = + IPW_BD_STATUS_TX_FRAME_COMMAND | + IPW_BD_STATUS_TX_INTERRUPT_ENABLE; + + /* update TBD queue counters */ + txq->next++; + txq->next %= txq->entries; + txq->available--; + DEC_STAT(&priv->txq_stat); + + list_add_tail(element, &priv->fw_pend_list); + INC_STAT(&priv->fw_pend_stat); + } + + if (txq->next != next) { + /* kick off the DMA by notifying firmware the + * write index has moved; make sure TBD stores are sync'd */ + wmb(); + write_register(priv->net_dev, + IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, + txq->next); + } +} + +/* + * ipw2100_tx_send_data + * + */ +static void ipw2100_tx_send_data(struct ipw2100_priv *priv) +{ + struct list_head *element; + struct ipw2100_tx_packet *packet; + struct ipw2100_bd_queue *txq = &priv->tx_queue; + struct ipw2100_bd *tbd; + int next = txq->next; + int i = 0; + struct ipw2100_data_header *ipw_hdr; + struct ieee80211_hdr_3addr *hdr; + + while (!list_empty(&priv->tx_pend_list)) { + /* if there isn't enough space in TBD queue, then + * don't stuff a new one in. + * NOTE: 4 are needed as a data will take two, + * and there is a minimum of 2 that must be + * maintained between the r and w indexes + */ + element = priv->tx_pend_list.next; + packet = list_entry(element, struct ipw2100_tx_packet, list); + + if (unlikely(1 + packet->info.d_struct.txb->nr_frags > + IPW_MAX_BDS)) { + /* TODO: Support merging buffers if more than + * IPW_MAX_BDS are used */ + IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. " + "Increase fragmentation level.\n", + priv->net_dev->name); + } + + if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) { + IPW_DEBUG_TX("no room in tx_queue\n"); + break; + } + + list_del(element); + DEC_STAT(&priv->tx_pend_stat); + + tbd = &txq->drv[txq->next]; + + packet->index = txq->next; + + ipw_hdr = packet->info.d_struct.data; + hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> + fragments[0]->data; + + if (priv->ieee->iw_mode == IW_MODE_INFRA) { + /* To DS: Addr1 = BSSID, Addr2 = SA, + Addr3 = DA */ + memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN); + memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN); + } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, + Addr3 = BSSID */ + memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN); + memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN); + } + + ipw_hdr->host_command_reg = SEND; + ipw_hdr->host_command_reg1 = 0; + + /* For now we only support host based encryption */ + ipw_hdr->needs_encryption = 0; + ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted; + if (packet->info.d_struct.txb->nr_frags > 1) + ipw_hdr->fragment_size = + packet->info.d_struct.txb->frag_size - + IEEE80211_3ADDR_LEN; + else + ipw_hdr->fragment_size = 0; + + tbd->host_addr = packet->info.d_struct.data_phys; + tbd->buf_length = sizeof(struct ipw2100_data_header); + tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags; + tbd->status.info.field = + IPW_BD_STATUS_TX_FRAME_802_3 | + IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; + txq->next++; + txq->next %= txq->entries; + + IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n", + packet->index, tbd->host_addr, tbd->buf_length); +#ifdef CONFIG_IPW2100_DEBUG + if (packet->info.d_struct.txb->nr_frags > 1) + IPW_DEBUG_FRAG("fragment Tx: %d frames\n", + packet->info.d_struct.txb->nr_frags); +#endif + + for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) { + tbd = &txq->drv[txq->next]; + if (i == packet->info.d_struct.txb->nr_frags - 1) + tbd->status.info.field = + IPW_BD_STATUS_TX_FRAME_802_3 | + IPW_BD_STATUS_TX_INTERRUPT_ENABLE; + else + tbd->status.info.field = + IPW_BD_STATUS_TX_FRAME_802_3 | + IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; + + tbd->buf_length = packet->info.d_struct.txb-> + fragments[i]->len - IEEE80211_3ADDR_LEN; + + tbd->host_addr = pci_map_single(priv->pci_dev, + packet->info.d_struct. + txb->fragments[i]-> + data + + IEEE80211_3ADDR_LEN, + tbd->buf_length, + PCI_DMA_TODEVICE); + + IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n", + txq->next, tbd->host_addr, + tbd->buf_length); + + pci_dma_sync_single_for_device(priv->pci_dev, + tbd->host_addr, + tbd->buf_length, + PCI_DMA_TODEVICE); + + txq->next++; + txq->next %= txq->entries; + } + + txq->available -= 1 + packet->info.d_struct.txb->nr_frags; + SET_STAT(&priv->txq_stat, txq->available); + + list_add_tail(element, &priv->fw_pend_list); + INC_STAT(&priv->fw_pend_stat); + } + + if (txq->next != next) { + /* kick off the DMA by notifying firmware the + * write index has moved; make sure TBD stores are sync'd */ + write_register(priv->net_dev, + IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, + txq->next); + } + return; +} + +static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) +{ + struct net_device *dev = priv->net_dev; + unsigned long flags; + u32 inta, tmp; + + spin_lock_irqsave(&priv->low_lock, flags); + ipw2100_disable_interrupts(priv); + + read_register(dev, IPW_REG_INTA, &inta); + + IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n", + (unsigned long)inta & IPW_INTERRUPT_MASK); + + priv->in_isr++; + priv->interrupts++; + + /* We do not loop and keep polling for more interrupts as this + * is frowned upon and doesn't play nicely with other potentially + * chained IRQs */ + IPW_DEBUG_ISR("INTA: 0x%08lX\n", + (unsigned long)inta & IPW_INTERRUPT_MASK); + + if (inta & IPW2100_INTA_FATAL_ERROR) { + printk(KERN_WARNING DRV_NAME + ": Fatal interrupt. Scheduling firmware restart.\n"); + priv->inta_other++; + write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR); + + read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error); + IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n", + priv->net_dev->name, priv->fatal_error); + + read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp); + IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n", + priv->net_dev->name, tmp); + + /* Wake up any sleeping jobs */ + schedule_reset(priv); + } + + if (inta & IPW2100_INTA_PARITY_ERROR) { + printk(KERN_ERR DRV_NAME + ": ***** PARITY ERROR INTERRUPT !!!! \n"); + priv->inta_other++; + write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR); + } + + if (inta & IPW2100_INTA_RX_TRANSFER) { + IPW_DEBUG_ISR("RX interrupt\n"); + + priv->rx_interrupts++; + + write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER); + + __ipw2100_rx_process(priv); + __ipw2100_tx_complete(priv); + } + + if (inta & IPW2100_INTA_TX_TRANSFER) { + IPW_DEBUG_ISR("TX interrupt\n"); + + priv->tx_interrupts++; + + write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER); + + __ipw2100_tx_complete(priv); + ipw2100_tx_send_commands(priv); + ipw2100_tx_send_data(priv); + } + + if (inta & IPW2100_INTA_TX_COMPLETE) { + IPW_DEBUG_ISR("TX complete\n"); + priv->inta_other++; + write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE); + + __ipw2100_tx_complete(priv); + } + + if (inta & IPW2100_INTA_EVENT_INTERRUPT) { + /* ipw2100_handle_event(dev); */ + priv->inta_other++; + write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT); + } + + if (inta & IPW2100_INTA_FW_INIT_DONE) { + IPW_DEBUG_ISR("FW init done interrupt\n"); + priv->inta_other++; + + read_register(dev, IPW_REG_INTA, &tmp); + if (tmp & (IPW2100_INTA_FATAL_ERROR | + IPW2100_INTA_PARITY_ERROR)) { + write_register(dev, IPW_REG_INTA, + IPW2100_INTA_FATAL_ERROR | + IPW2100_INTA_PARITY_ERROR); + } + + write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE); + } + + if (inta & IPW2100_INTA_STATUS_CHANGE) { + IPW_DEBUG_ISR("Status change interrupt\n"); + priv->inta_other++; + write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE); + } + + if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) { + IPW_DEBUG_ISR("slave host mode interrupt\n"); + priv->inta_other++; + write_register(dev, IPW_REG_INTA, + IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE); + } + + priv->in_isr--; + ipw2100_enable_interrupts(priv); + + spin_unlock_irqrestore(&priv->low_lock, flags); + + IPW_DEBUG_ISR("exit\n"); +} + +static irqreturn_t ipw2100_interrupt(int irq, void *data) +{ + struct ipw2100_priv *priv = data; + u32 inta, inta_mask; + + if (!data) + return IRQ_NONE; + + spin_lock(&priv->low_lock); + + /* We check to see if we should be ignoring interrupts before + * we touch the hardware. During ucode load if we try and handle + * an interrupt we can cause keyboard problems as well as cause + * the ucode to fail to initialize */ + if (!(priv->status & STATUS_INT_ENABLED)) { + /* Shared IRQ */ + goto none; + } + + read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); + read_register(priv->net_dev, IPW_REG_INTA, &inta); + + if (inta == 0xFFFFFFFF) { + /* Hardware disappeared */ + printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n"); + goto none; + } + + inta &= IPW_INTERRUPT_MASK; + + if (!(inta & inta_mask)) { + /* Shared interrupt */ + goto none; + } + + /* We disable the hardware interrupt here just to prevent unneeded + * calls to be made. We disable this again within the actual + * work tasklet, so if another part of the code re-enables the + * interrupt, that is fine */ + ipw2100_disable_interrupts(priv); + + tasklet_schedule(&priv->irq_tasklet); + spin_unlock(&priv->low_lock); + + return IRQ_HANDLED; + none: + spin_unlock(&priv->low_lock); + return IRQ_NONE; +} + +static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, + int pri) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct list_head *element; + struct ipw2100_tx_packet *packet; + unsigned long flags; + + spin_lock_irqsave(&priv->low_lock, flags); + + if (!(priv->status & STATUS_ASSOCIATED)) { + IPW_DEBUG_INFO("Can not transmit when not connected.\n"); + priv->ieee->stats.tx_carrier_errors++; + netif_stop_queue(dev); + goto fail_unlock; + } + + if (list_empty(&priv->tx_free_list)) + goto fail_unlock; + + element = priv->tx_free_list.next; + packet = list_entry(element, struct ipw2100_tx_packet, list); + + packet->info.d_struct.txb = txb; + + IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len); + printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len); + + packet->jiffy_start = jiffies; + + list_del(element); + DEC_STAT(&priv->tx_free_stat); + + list_add_tail(element, &priv->tx_pend_list); + INC_STAT(&priv->tx_pend_stat); + + ipw2100_tx_send_data(priv); + + spin_unlock_irqrestore(&priv->low_lock, flags); + return 0; + + fail_unlock: + netif_stop_queue(dev); + spin_unlock_irqrestore(&priv->low_lock, flags); + return 1; +} + +static int ipw2100_msg_allocate(struct ipw2100_priv *priv) +{ + int i, j, err = -EINVAL; + void *v; + dma_addr_t p; + + priv->msg_buffers = + (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE * + sizeof(struct + ipw2100_tx_packet), + GFP_KERNEL); + if (!priv->msg_buffers) { + printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg " + "buffers.\n", priv->net_dev->name); + return -ENOMEM; + } + + for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { + v = pci_alloc_consistent(priv->pci_dev, + sizeof(struct ipw2100_cmd_header), &p); + if (!v) { + printk(KERN_ERR DRV_NAME ": " + "%s: PCI alloc failed for msg " + "buffers.\n", priv->net_dev->name); + err = -ENOMEM; + break; + } + + memset(v, 0, sizeof(struct ipw2100_cmd_header)); + + priv->msg_buffers[i].type = COMMAND; + priv->msg_buffers[i].info.c_struct.cmd = + (struct ipw2100_cmd_header *)v; + priv->msg_buffers[i].info.c_struct.cmd_phys = p; + } + + if (i == IPW_COMMAND_POOL_SIZE) + return 0; + + for (j = 0; j < i; j++) { + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[j].info.c_struct.cmd, + priv->msg_buffers[j].info.c_struct. + cmd_phys); + } + + kfree(priv->msg_buffers); + priv->msg_buffers = NULL; + + return err; +} + +static int ipw2100_msg_initialize(struct ipw2100_priv *priv) +{ + int i; + + INIT_LIST_HEAD(&priv->msg_free_list); + INIT_LIST_HEAD(&priv->msg_pend_list); + + for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) + list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list); + SET_STAT(&priv->msg_free_stat, i); + + return 0; +} + +static void ipw2100_msg_free(struct ipw2100_priv *priv) +{ + int i; + + if (!priv->msg_buffers) + return; + + for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[i].info.c_struct.cmd, + priv->msg_buffers[i].info.c_struct. + cmd_phys); + } + + kfree(priv->msg_buffers); + priv->msg_buffers = NULL; +} + +static ssize_t show_pci(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev); + char *out = buf; + int i, j; + u32 val; + + for (i = 0; i < 16; i++) { + out += sprintf(out, "[%08X] ", i * 16); + for (j = 0; j < 16; j += 4) { + pci_read_config_dword(pci_dev, i * 16 + j, &val); + out += sprintf(out, "%08X ", val); + } + out += sprintf(out, "\n"); + } + + return out - buf; +} + +static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); + +static ssize_t show_cfg(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *p = d->driver_data; + return sprintf(buf, "0x%08x\n", (int)p->config); +} + +static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); + +static ssize_t show_status(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *p = d->driver_data; + return sprintf(buf, "0x%08x\n", (int)p->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +static ssize_t show_capability(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *p = d->driver_data; + return sprintf(buf, "0x%08x\n", (int)p->capability); +} + +static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL); + +#define IPW2100_REG(x) { IPW_ ##x, #x } +static const struct { + u32 addr; + const char *name; +} hw_data[] = { +IPW2100_REG(REG_GP_CNTRL), + IPW2100_REG(REG_GPIO), + IPW2100_REG(REG_INTA), + IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),}; +#define IPW2100_NIC(x, s) { x, #x, s } +static const struct { + u32 addr; + const char *name; + size_t size; +} nic_data[] = { +IPW2100_NIC(IPW2100_CONTROL_REG, 2), + IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),}; +#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d } +static const struct { + u8 index; + const char *name; + const char *desc; +} ord_data[] = { +IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), + IPW2100_ORD(STAT_TX_HOST_COMPLETE, + "successful Host Tx's (MSDU)"), + IPW2100_ORD(STAT_TX_DIR_DATA, + "successful Directed Tx's (MSDU)"), + IPW2100_ORD(STAT_TX_DIR_DATA1, + "successful Directed Tx's (MSDU) @ 1MB"), + IPW2100_ORD(STAT_TX_DIR_DATA2, + "successful Directed Tx's (MSDU) @ 2MB"), + IPW2100_ORD(STAT_TX_DIR_DATA5_5, + "successful Directed Tx's (MSDU) @ 5_5MB"), + IPW2100_ORD(STAT_TX_DIR_DATA11, + "successful Directed Tx's (MSDU) @ 11MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA1, + "successful Non_Directed Tx's (MSDU) @ 1MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA2, + "successful Non_Directed Tx's (MSDU) @ 2MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA5_5, + "successful Non_Directed Tx's (MSDU) @ 5.5MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA11, + "successful Non_Directed Tx's (MSDU) @ 11MB"), + IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"), + IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"), + IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"), + IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"), + IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"), + IPW2100_ORD(STAT_TX_ASSN_RESP, + "successful Association response Tx's"), + IPW2100_ORD(STAT_TX_REASSN, + "successful Reassociation Tx's"), + IPW2100_ORD(STAT_TX_REASSN_RESP, + "successful Reassociation response Tx's"), + IPW2100_ORD(STAT_TX_PROBE, + "probes successfully transmitted"), + IPW2100_ORD(STAT_TX_PROBE_RESP, + "probe responses successfully transmitted"), + IPW2100_ORD(STAT_TX_BEACON, "tx beacon"), + IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"), + IPW2100_ORD(STAT_TX_DISASSN, + "successful Disassociation TX"), + IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"), + IPW2100_ORD(STAT_TX_DEAUTH, + "successful Deauthentication TX"), + IPW2100_ORD(STAT_TX_TOTAL_BYTES, + "Total successful Tx data bytes"), + IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"), + IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"), + IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"), + IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"), + IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"), + IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"), + IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP, + "times max tries in a hop failed"), + IPW2100_ORD(STAT_TX_DISASSN_FAIL, + "times disassociation failed"), + IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"), + IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"), + IPW2100_ORD(STAT_RX_HOST, "packets passed to host"), + IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"), + IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"), + IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"), + IPW2100_ORD(STAT_RX_DIR_DATA5_5, + "directed packets at 5.5MB"), + IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"), + IPW2100_ORD(STAT_RX_NODIR_DATA1, + "nondirected packets at 1MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA2, + "nondirected packets at 2MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA5_5, + "nondirected packets at 5.5MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA11, + "nondirected packets at 11MB"), + IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"), + IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS, + "Rx CTS"), + IPW2100_ORD(STAT_RX_ACK, "Rx ACK"), + IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"), + IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"), + IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"), + IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"), + IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"), + IPW2100_ORD(STAT_RX_REASSN_RESP, + "Reassociation response Rx's"), + IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"), + IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"), + IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"), + IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"), + IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"), + IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"), + IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"), + IPW2100_ORD(STAT_RX_TOTAL_BYTES, + "Total rx data bytes received"), + IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"), + IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"), + IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"), + IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"), + IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"), + IPW2100_ORD(STAT_RX_DUPLICATE1, + "duplicate rx packets at 1MB"), + IPW2100_ORD(STAT_RX_DUPLICATE2, + "duplicate rx packets at 2MB"), + IPW2100_ORD(STAT_RX_DUPLICATE5_5, + "duplicate rx packets at 5.5MB"), + IPW2100_ORD(STAT_RX_DUPLICATE11, + "duplicate rx packets at 11MB"), + IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"), + IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"), + IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"), + IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"), + IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, + "rx frames with invalid protocol"), + IPW2100_ORD(SYS_BOOT_TIME, "Boot time"), + IPW2100_ORD(STAT_RX_NO_BUFFER, + "rx frames rejected due to no buffer"), + IPW2100_ORD(STAT_RX_MISSING_FRAG, + "rx frames dropped due to missing fragment"), + IPW2100_ORD(STAT_RX_ORPHAN_FRAG, + "rx frames dropped due to non-sequential fragment"), + IPW2100_ORD(STAT_RX_ORPHAN_FRAME, + "rx frames dropped due to unmatched 1st frame"), + IPW2100_ORD(STAT_RX_FRAG_AGEOUT, + "rx frames dropped due to uncompleted frame"), + IPW2100_ORD(STAT_RX_ICV_ERRORS, + "ICV errors during decryption"), + IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"), + IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"), + IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, + "poll response timeouts"), + IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, + "timeouts waiting for last {broad,multi}cast pkt"), + IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"), + IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"), + IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"), + IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"), + IPW2100_ORD(STAT_PERCENT_MISSED_BCNS, + "current calculation of % missed beacons"), + IPW2100_ORD(STAT_PERCENT_RETRIES, + "current calculation of % missed tx retries"), + IPW2100_ORD(ASSOCIATED_AP_PTR, + "0 if not associated, else pointer to AP table entry"), + IPW2100_ORD(AVAILABLE_AP_CNT, + "AP's decsribed in the AP table"), + IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"), + IPW2100_ORD(STAT_AP_ASSNS, "associations"), + IPW2100_ORD(STAT_ASSN_FAIL, "association failures"), + IPW2100_ORD(STAT_ASSN_RESP_FAIL, + "failures due to response fail"), + IPW2100_ORD(STAT_FULL_SCANS, "full scans"), + IPW2100_ORD(CARD_DISABLED, "Card Disabled"), + IPW2100_ORD(STAT_ROAM_INHIBIT, + "times roaming was inhibited due to activity"), + IPW2100_ORD(RSSI_AT_ASSN, + "RSSI of associated AP at time of association"), + IPW2100_ORD(STAT_ASSN_CAUSE1, + "reassociation: no probe response or TX on hop"), + IPW2100_ORD(STAT_ASSN_CAUSE2, + "reassociation: poor tx/rx quality"), + IPW2100_ORD(STAT_ASSN_CAUSE3, + "reassociation: tx/rx quality (excessive AP load"), + IPW2100_ORD(STAT_ASSN_CAUSE4, + "reassociation: AP RSSI level"), + IPW2100_ORD(STAT_ASSN_CAUSE5, + "reassociations due to load leveling"), + IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"), + IPW2100_ORD(STAT_AUTH_RESP_FAIL, + "times authentication response failed"), + IPW2100_ORD(STATION_TABLE_CNT, + "entries in association table"), + IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"), + IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"), + IPW2100_ORD(COUNTRY_CODE, + "IEEE country code as recv'd from beacon"), + IPW2100_ORD(COUNTRY_CHANNELS, + "channels suported by country"), + IPW2100_ORD(RESET_CNT, "adapter resets (warm)"), + IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"), + IPW2100_ORD(ANTENNA_DIVERSITY, + "TRUE if antenna diversity is disabled"), + IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"), + IPW2100_ORD(OUR_FREQ, + "current radio freq lower digits - channel ID"), + IPW2100_ORD(RTC_TIME, "current RTC time"), + IPW2100_ORD(PORT_TYPE, "operating mode"), + IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"), + IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"), + IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"), + IPW2100_ORD(BASIC_RATES, "basic tx rates"), + IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"), + IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"), + IPW2100_ORD(CAPABILITIES, + "Management frame capability field"), + IPW2100_ORD(AUTH_TYPE, "Type of authentication"), + IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"), + IPW2100_ORD(RTS_THRESHOLD, + "Min packet length for RTS handshaking"), + IPW2100_ORD(INT_MODE, "International mode"), + IPW2100_ORD(FRAGMENTATION_THRESHOLD, + "protocol frag threshold"), + IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, + "EEPROM offset in SRAM"), + IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, + "EEPROM size in SRAM"), + IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"), + IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, + "EEPROM IBSS 11b channel set"), + IPW2100_ORD(MAC_VERSION, "MAC Version"), + IPW2100_ORD(MAC_REVISION, "MAC Revision"), + IPW2100_ORD(RADIO_VERSION, "Radio Version"), + IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"), + IPW2100_ORD(UCODE_VERSION, "Ucode Version"),}; + +static ssize_t show_registers(struct device *d, struct device_attribute *attr, + char *buf) +{ + int i; + struct ipw2100_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + char *out = buf; + u32 val = 0; + + out += sprintf(out, "%30s [Address ] : Hex\n", "Register"); + + for (i = 0; i < ARRAY_SIZE(hw_data); i++) { + read_register(dev, hw_data[i].addr, &val); + out += sprintf(out, "%30s [%08X] : %08X\n", + hw_data[i].name, hw_data[i].addr, val); + } + + return out - buf; +} + +static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); + +static ssize_t show_hardware(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + char *out = buf; + int i; + + out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry"); + + for (i = 0; i < ARRAY_SIZE(nic_data); i++) { + u8 tmp8; + u16 tmp16; + u32 tmp32; + + switch (nic_data[i].size) { + case 1: + read_nic_byte(dev, nic_data[i].addr, &tmp8); + out += sprintf(out, "%30s [%08X] : %02X\n", + nic_data[i].name, nic_data[i].addr, + tmp8); + break; + case 2: + read_nic_word(dev, nic_data[i].addr, &tmp16); + out += sprintf(out, "%30s [%08X] : %04X\n", + nic_data[i].name, nic_data[i].addr, + tmp16); + break; + case 4: + read_nic_dword(dev, nic_data[i].addr, &tmp32); + out += sprintf(out, "%30s [%08X] : %08X\n", + nic_data[i].name, nic_data[i].addr, + tmp32); + break; + } + } + return out - buf; +} + +static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL); + +static ssize_t show_memory(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + static unsigned long loop = 0; + int len = 0; + u32 buffer[4]; + int i; + char line[81]; + + if (loop >= 0x30000) + loop = 0; + + /* sysfs provides us PAGE_SIZE buffer */ + while (len < PAGE_SIZE - 128 && loop < 0x30000) { + + if (priv->snapshot[0]) + for (i = 0; i < 4; i++) + buffer[i] = + *(u32 *) SNAPSHOT_ADDR(loop + i * 4); + else + for (i = 0; i < 4; i++) + read_nic_dword(dev, loop + i * 4, &buffer[i]); + + if (priv->dump_raw) + len += sprintf(buf + len, + "%c%c%c%c" + "%c%c%c%c" + "%c%c%c%c" + "%c%c%c%c", + ((u8 *) buffer)[0x0], + ((u8 *) buffer)[0x1], + ((u8 *) buffer)[0x2], + ((u8 *) buffer)[0x3], + ((u8 *) buffer)[0x4], + ((u8 *) buffer)[0x5], + ((u8 *) buffer)[0x6], + ((u8 *) buffer)[0x7], + ((u8 *) buffer)[0x8], + ((u8 *) buffer)[0x9], + ((u8 *) buffer)[0xa], + ((u8 *) buffer)[0xb], + ((u8 *) buffer)[0xc], + ((u8 *) buffer)[0xd], + ((u8 *) buffer)[0xe], + ((u8 *) buffer)[0xf]); + else + len += sprintf(buf + len, "%s\n", + snprint_line(line, sizeof(line), + (u8 *) buffer, 16, loop)); + loop += 16; + } + + return len; +} + +static ssize_t store_memory(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + const char *p = buf; + + (void)dev; /* kill unused-var warning for debug-only code */ + + if (count < 1) + return count; + + if (p[0] == '1' || + (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) { + IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n", + dev->name); + priv->dump_raw = 1; + + } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' && + tolower(p[1]) == 'f')) { + IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n", + dev->name); + priv->dump_raw = 0; + + } else if (tolower(p[0]) == 'r') { + IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name); + ipw2100_snapshot_free(priv); + + } else + IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, " + "reset = clear memory snapshot\n", dev->name); + + return count; +} + +static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory); + +static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + u32 val = 0; + int len = 0; + u32 val_len; + static int loop = 0; + + if (priv->status & STATUS_RF_KILL_MASK) + return 0; + + if (loop >= ARRAY_SIZE(ord_data)) + loop = 0; + + /* sysfs provides us PAGE_SIZE buffer */ + while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) { + val_len = sizeof(u32); + + if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val, + &val_len)) + len += sprintf(buf + len, "[0x%02X] = ERROR %s\n", + ord_data[loop].index, + ord_data[loop].desc); + else + len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n", + ord_data[loop].index, val, + ord_data[loop].desc); + loop++; + } + + return len; +} + +static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL); + +static ssize_t show_stats(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + char *out = buf; + + out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n", + priv->interrupts, priv->tx_interrupts, + priv->rx_interrupts, priv->inta_other); + out += sprintf(out, "firmware resets: %d\n", priv->resets); + out += sprintf(out, "firmware hangs: %d\n", priv->hangs); +#ifdef CONFIG_IPW2100_DEBUG + out += sprintf(out, "packet mismatch image: %s\n", + priv->snapshot[0] ? "YES" : "NO"); +#endif + + return out - buf; +} + +static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); + +static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) +{ + int err; + + if (mode == priv->ieee->iw_mode) + return 0; + + err = ipw2100_disable_adapter(priv); + if (err) { + printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", + priv->net_dev->name, err); + return err; + } + + switch (mode) { + case IW_MODE_INFRA: + priv->net_dev->type = ARPHRD_ETHER; + break; + case IW_MODE_ADHOC: + priv->net_dev->type = ARPHRD_ETHER; + break; +#ifdef CONFIG_IPW2100_MONITOR + case IW_MODE_MONITOR: + priv->last_mode = priv->ieee->iw_mode; + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; + break; +#endif /* CONFIG_IPW2100_MONITOR */ + } + + priv->ieee->iw_mode = mode; + +#ifdef CONFIG_PM + /* Indicate ipw2100_download_firmware download firmware + * from disk instead of memory. */ + ipw2100_firmware.version = 0; +#endif + + printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name); + priv->reset_backoff = 0; + schedule_reset(priv); + + return 0; +} + +static ssize_t show_internals(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + int len = 0; + +#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x) + + if (priv->status & STATUS_ASSOCIATED) + len += sprintf(buf + len, "connected: %lu\n", + get_seconds() - priv->connect_start); + else + len += sprintf(buf + len, "not connected\n"); + + DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p"); + DUMP_VAR(status, "08lx"); + DUMP_VAR(config, "08lx"); + DUMP_VAR(capability, "08lx"); + + len += + sprintf(buf + len, "last_rtc: %lu\n", + (unsigned long)priv->last_rtc); + + DUMP_VAR(fatal_error, "d"); + DUMP_VAR(stop_hang_check, "d"); + DUMP_VAR(stop_rf_kill, "d"); + DUMP_VAR(messages_sent, "d"); + + DUMP_VAR(tx_pend_stat.value, "d"); + DUMP_VAR(tx_pend_stat.hi, "d"); + + DUMP_VAR(tx_free_stat.value, "d"); + DUMP_VAR(tx_free_stat.lo, "d"); + + DUMP_VAR(msg_free_stat.value, "d"); + DUMP_VAR(msg_free_stat.lo, "d"); + + DUMP_VAR(msg_pend_stat.value, "d"); + DUMP_VAR(msg_pend_stat.hi, "d"); + + DUMP_VAR(fw_pend_stat.value, "d"); + DUMP_VAR(fw_pend_stat.hi, "d"); + + DUMP_VAR(txq_stat.value, "d"); + DUMP_VAR(txq_stat.lo, "d"); + + DUMP_VAR(ieee->scans, "d"); + DUMP_VAR(reset_backoff, "d"); + + return len; +} + +static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL); + +static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + char essid[IW_ESSID_MAX_SIZE + 1]; + u8 bssid[ETH_ALEN]; + u32 chan = 0; + char *out = buf; + int length; + int ret; + + if (priv->status & STATUS_RF_KILL_MASK) + return 0; + + memset(essid, 0, sizeof(essid)); + memset(bssid, 0, sizeof(bssid)); + + length = IW_ESSID_MAX_SIZE; + ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length); + if (ret) + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + + length = sizeof(bssid); + ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, + bssid, &length); + if (ret) + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + + length = sizeof(u32); + ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length); + if (ret) + IPW_DEBUG_INFO("failed querying ordinals at line %d\n", + __LINE__); + + out += sprintf(out, "ESSID: %s\n", essid); + out += sprintf(out, "BSSID: %pM\n", bssid); + out += sprintf(out, "Channel: %d\n", chan); + + return out - buf; +} + +static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); + +#ifdef CONFIG_IPW2100_DEBUG +static ssize_t show_debug_level(struct device_driver *d, char *buf) +{ + return sprintf(buf, "0x%08X\n", ipw2100_debug_level); +} + +static ssize_t store_debug_level(struct device_driver *d, + const char *buf, size_t count) +{ + char *p = (char *)buf; + u32 val; + + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buf) + IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf); + else + ipw2100_debug_level = val; + + return strnlen(buf, count); +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, + store_debug_level); +#endif /* CONFIG_IPW2100_DEBUG */ + +static ssize_t show_fatal_error(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + char *out = buf; + int i; + + if (priv->fatal_error) + out += sprintf(out, "0x%08X\n", priv->fatal_error); + else + out += sprintf(out, "0\n"); + + for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) { + if (!priv->fatal_errors[(priv->fatal_index - i) % + IPW2100_ERROR_QUEUE]) + continue; + + out += sprintf(out, "%d. 0x%08X\n", i, + priv->fatal_errors[(priv->fatal_index - i) % + IPW2100_ERROR_QUEUE]); + } + + return out - buf; +} + +static ssize_t store_fatal_error(struct device *d, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + schedule_reset(priv); + return count; +} + +static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error, + store_fatal_error); + +static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d\n", priv->ieee->scan_age); +} + +static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + char buffer[] = "00000000"; + unsigned long len = + (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; + unsigned long val; + char *p = buffer; + + (void)dev; /* kill unused-var warning for debug-only code */ + + IPW_DEBUG_INFO("enter\n"); + + strncpy(buffer, buf, len); + buffer[len] = 0; + + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buffer) { + IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); + } else { + priv->ieee->scan_age = val; + IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); + } + + IPW_DEBUG_INFO("exit\n"); + return len; +} + +static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); + +static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, + char *buf) +{ + /* 0 - RF kill not enabled + 1 - SW based RF kill active (sysfs) + 2 - HW based RF kill active + 3 - Both HW and SW baed RF kill active */ + struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data; + int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | + (rf_kill_active(priv) ? 0x2 : 0x0); + return sprintf(buf, "%i\n", val); +} + +static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) +{ + if ((disable_radio ? 1 : 0) == + (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) + return 0; + + IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", + disable_radio ? "OFF" : "ON"); + + mutex_lock(&priv->action_mutex); + + if (disable_radio) { + priv->status |= STATUS_RF_KILL_SW; + ipw2100_down(priv); + } else { + priv->status &= ~STATUS_RF_KILL_SW; + if (rf_kill_active(priv)) { + IPW_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + /* Make sure the RF_KILL check timer is running */ + priv->stop_rf_kill = 0; + cancel_delayed_work(&priv->rf_kill); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies_relative(HZ)); + } else + schedule_reset(priv); + } + + mutex_unlock(&priv->action_mutex); + return 1; +} + +static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw2100_priv *priv = dev_get_drvdata(d); + ipw_radio_kill_sw(priv, buf[0] == '1'); + return count; +} + +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); + +static struct attribute *ipw2100_sysfs_entries[] = { + &dev_attr_hardware.attr, + &dev_attr_registers.attr, + &dev_attr_ordinals.attr, + &dev_attr_pci.attr, + &dev_attr_stats.attr, + &dev_attr_internals.attr, + &dev_attr_bssinfo.attr, + &dev_attr_memory.attr, + &dev_attr_scan_age.attr, + &dev_attr_fatal_error.attr, + &dev_attr_rf_kill.attr, + &dev_attr_cfg.attr, + &dev_attr_status.attr, + &dev_attr_capability.attr, + NULL, +}; + +static struct attribute_group ipw2100_attribute_group = { + .attrs = ipw2100_sysfs_entries, +}; + +static int status_queue_allocate(struct ipw2100_priv *priv, int entries) +{ + struct ipw2100_status_queue *q = &priv->status_queue; + + IPW_DEBUG_INFO("enter\n"); + + q->size = entries * sizeof(struct ipw2100_status); + q->drv = + (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev, + q->size, &q->nic); + if (!q->drv) { + IPW_DEBUG_WARNING("Can not allocate status queue.\n"); + return -ENOMEM; + } + + memset(q->drv, 0, q->size); + + IPW_DEBUG_INFO("exit\n"); + + return 0; +} + +static void status_queue_free(struct ipw2100_priv *priv) +{ + IPW_DEBUG_INFO("enter\n"); + + if (priv->status_queue.drv) { + pci_free_consistent(priv->pci_dev, priv->status_queue.size, + priv->status_queue.drv, + priv->status_queue.nic); + priv->status_queue.drv = NULL; + } + + IPW_DEBUG_INFO("exit\n"); +} + +static int bd_queue_allocate(struct ipw2100_priv *priv, + struct ipw2100_bd_queue *q, int entries) +{ + IPW_DEBUG_INFO("enter\n"); + + memset(q, 0, sizeof(struct ipw2100_bd_queue)); + + q->entries = entries; + q->size = entries * sizeof(struct ipw2100_bd); + q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic); + if (!q->drv) { + IPW_DEBUG_INFO + ("can't allocate shared memory for buffer descriptors\n"); + return -ENOMEM; + } + memset(q->drv, 0, q->size); + + IPW_DEBUG_INFO("exit\n"); + + return 0; +} + +static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q) +{ + IPW_DEBUG_INFO("enter\n"); + + if (!q) + return; + + if (q->drv) { + pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic); + q->drv = NULL; + } + + IPW_DEBUG_INFO("exit\n"); +} + +static void bd_queue_initialize(struct ipw2100_priv *priv, + struct ipw2100_bd_queue *q, u32 base, u32 size, + u32 r, u32 w) +{ + IPW_DEBUG_INFO("enter\n"); + + IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, + (u32) q->nic); + + write_register(priv->net_dev, base, q->nic); + write_register(priv->net_dev, size, q->entries); + write_register(priv->net_dev, r, q->oldest); + write_register(priv->net_dev, w, q->next); + + IPW_DEBUG_INFO("exit\n"); +} + +static void ipw2100_kill_workqueue(struct ipw2100_priv *priv) +{ + if (priv->workqueue) { + priv->stop_rf_kill = 1; + priv->stop_hang_check = 1; + cancel_delayed_work(&priv->reset_work); + cancel_delayed_work(&priv->security_work); + cancel_delayed_work(&priv->wx_event_work); + cancel_delayed_work(&priv->hang_check); + cancel_delayed_work(&priv->rf_kill); + cancel_delayed_work(&priv->scan_event_later); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + } +} + +static int ipw2100_tx_allocate(struct ipw2100_priv *priv) +{ + int i, j, err = -EINVAL; + void *v; + dma_addr_t p; + + IPW_DEBUG_INFO("enter\n"); + + err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH); + if (err) { + IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n", + priv->net_dev->name); + return err; + } + + priv->tx_buffers = + (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH * + sizeof(struct + ipw2100_tx_packet), + GFP_ATOMIC); + if (!priv->tx_buffers) { + printk(KERN_ERR DRV_NAME + ": %s: alloc failed form tx buffers.\n", + priv->net_dev->name); + bd_queue_free(priv, &priv->tx_queue); + return -ENOMEM; + } + + for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { + v = pci_alloc_consistent(priv->pci_dev, + sizeof(struct ipw2100_data_header), + &p); + if (!v) { + printk(KERN_ERR DRV_NAME + ": %s: PCI alloc failed for tx " "buffers.\n", + priv->net_dev->name); + err = -ENOMEM; + break; + } + + priv->tx_buffers[i].type = DATA; + priv->tx_buffers[i].info.d_struct.data = + (struct ipw2100_data_header *)v; + priv->tx_buffers[i].info.d_struct.data_phys = p; + priv->tx_buffers[i].info.d_struct.txb = NULL; + } + + if (i == TX_PENDED_QUEUE_LENGTH) + return 0; + + for (j = 0; j < i; j++) { + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[j].info.d_struct.data, + priv->tx_buffers[j].info.d_struct. + data_phys); + } + + kfree(priv->tx_buffers); + priv->tx_buffers = NULL; + + return err; +} + +static void ipw2100_tx_initialize(struct ipw2100_priv *priv) +{ + int i; + + IPW_DEBUG_INFO("enter\n"); + + /* + * reinitialize packet info lists + */ + INIT_LIST_HEAD(&priv->fw_pend_list); + INIT_STAT(&priv->fw_pend_stat); + + /* + * reinitialize lists + */ + INIT_LIST_HEAD(&priv->tx_pend_list); + INIT_LIST_HEAD(&priv->tx_free_list); + INIT_STAT(&priv->tx_pend_stat); + INIT_STAT(&priv->tx_free_stat); + + for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { + /* We simply drop any SKBs that have been queued for + * transmit */ + if (priv->tx_buffers[i].info.d_struct.txb) { + ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + txb); + priv->tx_buffers[i].info.d_struct.txb = NULL; + } + + list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list); + } + + SET_STAT(&priv->tx_free_stat, i); + + priv->tx_queue.oldest = 0; + priv->tx_queue.available = priv->tx_queue.entries; + priv->tx_queue.next = 0; + INIT_STAT(&priv->txq_stat); + SET_STAT(&priv->txq_stat, priv->tx_queue.available); + + bd_queue_initialize(priv, &priv->tx_queue, + IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE, + IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE, + IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX, + IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX); + + IPW_DEBUG_INFO("exit\n"); + +} + +static void ipw2100_tx_free(struct ipw2100_priv *priv) +{ + int i; + + IPW_DEBUG_INFO("enter\n"); + + bd_queue_free(priv, &priv->tx_queue); + + if (!priv->tx_buffers) + return; + + for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { + if (priv->tx_buffers[i].info.d_struct.txb) { + ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + txb); + priv->tx_buffers[i].info.d_struct.txb = NULL; + } + if (priv->tx_buffers[i].info.d_struct.data) + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[i].info.d_struct. + data, + priv->tx_buffers[i].info.d_struct. + data_phys); + } + + kfree(priv->tx_buffers); + priv->tx_buffers = NULL; + + IPW_DEBUG_INFO("exit\n"); +} + +static int ipw2100_rx_allocate(struct ipw2100_priv *priv) +{ + int i, j, err = -EINVAL; + + IPW_DEBUG_INFO("enter\n"); + + err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH); + if (err) { + IPW_DEBUG_INFO("failed bd_queue_allocate\n"); + return err; + } + + err = status_queue_allocate(priv, RX_QUEUE_LENGTH); + if (err) { + IPW_DEBUG_INFO("failed status_queue_allocate\n"); + bd_queue_free(priv, &priv->rx_queue); + return err; + } + + /* + * allocate packets + */ + priv->rx_buffers = (struct ipw2100_rx_packet *) + kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet), + GFP_KERNEL); + if (!priv->rx_buffers) { + IPW_DEBUG_INFO("can't allocate rx packet buffer table\n"); + + bd_queue_free(priv, &priv->rx_queue); + + status_queue_free(priv); + + return -ENOMEM; + } + + for (i = 0; i < RX_QUEUE_LENGTH; i++) { + struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; + + err = ipw2100_alloc_skb(priv, packet); + if (unlikely(err)) { + err = -ENOMEM; + break; + } + + /* The BD holds the cache aligned address */ + priv->rx_queue.drv[i].host_addr = packet->dma_addr; + priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH; + priv->status_queue.drv[i].status_fields = 0; + } + + if (i == RX_QUEUE_LENGTH) + return 0; + + for (j = 0; j < i; j++) { + pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr, + sizeof(struct ipw2100_rx_packet), + PCI_DMA_FROMDEVICE); + dev_kfree_skb(priv->rx_buffers[j].skb); + } + + kfree(priv->rx_buffers); + priv->rx_buffers = NULL; + + bd_queue_free(priv, &priv->rx_queue); + + status_queue_free(priv); + + return err; +} + +static void ipw2100_rx_initialize(struct ipw2100_priv *priv) +{ + IPW_DEBUG_INFO("enter\n"); + + priv->rx_queue.oldest = 0; + priv->rx_queue.available = priv->rx_queue.entries - 1; + priv->rx_queue.next = priv->rx_queue.entries - 1; + + INIT_STAT(&priv->rxq_stat); + SET_STAT(&priv->rxq_stat, priv->rx_queue.available); + + bd_queue_initialize(priv, &priv->rx_queue, + IPW_MEM_HOST_SHARED_RX_BD_BASE, + IPW_MEM_HOST_SHARED_RX_BD_SIZE, + IPW_MEM_HOST_SHARED_RX_READ_INDEX, + IPW_MEM_HOST_SHARED_RX_WRITE_INDEX); + + /* set up the status queue */ + write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE, + priv->status_queue.nic); + + IPW_DEBUG_INFO("exit\n"); +} + +static void ipw2100_rx_free(struct ipw2100_priv *priv) +{ + int i; + + IPW_DEBUG_INFO("enter\n"); + + bd_queue_free(priv, &priv->rx_queue); + status_queue_free(priv); + + if (!priv->rx_buffers) + return; + + for (i = 0; i < RX_QUEUE_LENGTH; i++) { + if (priv->rx_buffers[i].rxp) { + pci_unmap_single(priv->pci_dev, + priv->rx_buffers[i].dma_addr, + sizeof(struct ipw2100_rx), + PCI_DMA_FROMDEVICE); + dev_kfree_skb(priv->rx_buffers[i].skb); + } + } + + kfree(priv->rx_buffers); + priv->rx_buffers = NULL; + + IPW_DEBUG_INFO("exit\n"); +} + +static int ipw2100_read_mac_address(struct ipw2100_priv *priv) +{ + u32 length = ETH_ALEN; + u8 addr[ETH_ALEN]; + + int err; + + err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length); + if (err) { + IPW_DEBUG_INFO("MAC address read failed\n"); + return -EIO; + } + + memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); + IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr); + + return 0; +} + +/******************************************************************** + * + * Firmware Commands + * + ********************************************************************/ + +static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode) +{ + struct host_command cmd = { + .host_command = ADAPTER_ADDRESS, + .host_command_sequence = 0, + .host_command_length = ETH_ALEN + }; + int err; + + IPW_DEBUG_HC("SET_MAC_ADDRESS\n"); + + IPW_DEBUG_INFO("enter\n"); + + if (priv->config & CFG_CUSTOM_MAC) { + memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN); + memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); + } else + memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr, + ETH_ALEN); + + err = ipw2100_hw_send_command(priv, &cmd); + + IPW_DEBUG_INFO("exit\n"); + return err; +} + +static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type, + int batch_mode) +{ + struct host_command cmd = { + .host_command = PORT_TYPE, + .host_command_sequence = 0, + .host_command_length = sizeof(u32) + }; + int err; + + switch (port_type) { + case IW_MODE_INFRA: + cmd.host_command_parameters[0] = IPW_BSS; + break; + case IW_MODE_ADHOC: + cmd.host_command_parameters[0] = IPW_IBSS; + break; + } + + IPW_DEBUG_HC("PORT_TYPE: %s\n", + port_type == IPW_IBSS ? "Ad-Hoc" : "Managed"); + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) { + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", + priv->net_dev->name, err); + return err; + } + } + + /* send cmd to firmware */ + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) + ipw2100_enable_adapter(priv); + + return err; +} + +static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel, + int batch_mode) +{ + struct host_command cmd = { + .host_command = CHANNEL, + .host_command_sequence = 0, + .host_command_length = sizeof(u32) + }; + int err; + + cmd.host_command_parameters[0] = channel; + + IPW_DEBUG_HC("CHANNEL: %d\n", channel); + + /* If BSS then we don't support channel selection */ + if (priv->ieee->iw_mode == IW_MODE_INFRA) + return 0; + + if ((channel != 0) && + ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL))) + return -EINVAL; + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) { + IPW_DEBUG_INFO("Failed to set channel to %d", channel); + return err; + } + + if (channel) + priv->config |= CFG_STATIC_CHANNEL; + else + priv->config &= ~CFG_STATIC_CHANNEL; + + priv->channel = channel; + + if (!batch_mode) { + err = ipw2100_enable_adapter(priv); + if (err) + return err; + } + + return 0; +} + +static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode) +{ + struct host_command cmd = { + .host_command = SYSTEM_CONFIG, + .host_command_sequence = 0, + .host_command_length = 12, + }; + u32 ibss_mask, len = sizeof(u32); + int err; + + /* Set system configuration */ + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START; + + cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK | + IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE; + + if (!(priv->config & CFG_LONG_PREAMBLE)) + cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO; + + err = ipw2100_get_ordinal(priv, + IPW_ORD_EEPROM_IBSS_11B_CHANNELS, + &ibss_mask, &len); + if (err) + ibss_mask = IPW_IBSS_11B_DEFAULT_MASK; + + cmd.host_command_parameters[1] = REG_CHANNEL_MASK; + cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask; + + /* 11b only */ + /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */ + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + +/* If IPv6 is configured in the kernel then we don't want to filter out all + * of the multicast packets as IPv6 needs some. */ +#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) + cmd.host_command = ADD_MULTICAST; + cmd.host_command_sequence = 0; + cmd.host_command_length = 0; + + ipw2100_hw_send_command(priv, &cmd); +#endif + if (!batch_mode) { + err = ipw2100_enable_adapter(priv); + if (err) + return err; + } + + return 0; +} + +static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate, + int batch_mode) +{ + struct host_command cmd = { + .host_command = BASIC_TX_RATES, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + cmd.host_command_parameters[0] = rate & TX_RATE_MASK; + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + /* Set BASIC TX Rate first */ + ipw2100_hw_send_command(priv, &cmd); + + /* Set TX Rate */ + cmd.host_command = TX_RATES; + ipw2100_hw_send_command(priv, &cmd); + + /* Set MSDU TX Rate */ + cmd.host_command = MSDU_TX_RATES; + ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) { + err = ipw2100_enable_adapter(priv); + if (err) + return err; + } + + priv->tx_rates = rate; + + return 0; +} + +static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level) +{ + struct host_command cmd = { + .host_command = POWER_MODE, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + cmd.host_command_parameters[0] = power_level; + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + + if (power_level == IPW_POWER_MODE_CAM) + priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); + else + priv->power_mode = IPW_POWER_ENABLED | power_level; + +#ifdef IPW2100_TX_POWER + if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) { + /* Set beacon interval */ + cmd.host_command = TX_POWER_INDEX; + cmd.host_command_parameters[0] = (u32) priv->adhoc_power; + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + } +#endif + + return 0; +} + +static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold) +{ + struct host_command cmd = { + .host_command = RTS_THRESHOLD, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + if (threshold & RTS_DISABLED) + cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD; + else + cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED; + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + + priv->rts_threshold = threshold; + + return 0; +} + +#if 0 +int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv, + u32 threshold, int batch_mode) +{ + struct host_command cmd = { + .host_command = FRAG_THRESHOLD, + .host_command_sequence = 0, + .host_command_length = 4, + .host_command_parameters[0] = 0, + }; + int err; + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + if (threshold == 0) + threshold = DEFAULT_FRAG_THRESHOLD; + else { + threshold = max(threshold, MIN_FRAG_THRESHOLD); + threshold = min(threshold, MAX_FRAG_THRESHOLD); + } + + cmd.host_command_parameters[0] = threshold; + + IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold); + + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) + ipw2100_enable_adapter(priv); + + if (!err) + priv->frag_threshold = threshold; + + return err; +} +#endif + +static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry) +{ + struct host_command cmd = { + .host_command = SHORT_RETRY_LIMIT, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + cmd.host_command_parameters[0] = retry; + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + + priv->short_retry_limit = retry; + + return 0; +} + +static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry) +{ + struct host_command cmd = { + .host_command = LONG_RETRY_LIMIT, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + cmd.host_command_parameters[0] = retry; + + err = ipw2100_hw_send_command(priv, &cmd); + if (err) + return err; + + priv->long_retry_limit = retry; + + return 0; +} + +static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, + int batch_mode) +{ + struct host_command cmd = { + .host_command = MANDATORY_BSSID, + .host_command_sequence = 0, + .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN + }; + int err; + +#ifdef CONFIG_IPW2100_DEBUG + if (bssid != NULL) + IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid); + else + IPW_DEBUG_HC("MANDATORY_BSSID: \n"); +#endif + /* if BSSID is empty then we disable mandatory bssid mode */ + if (bssid != NULL) + memcpy(cmd.host_command_parameters, bssid, ETH_ALEN); + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) + ipw2100_enable_adapter(priv); + + return err; +} + +static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv) +{ + struct host_command cmd = { + .host_command = DISASSOCIATION_BSSID, + .host_command_sequence = 0, + .host_command_length = ETH_ALEN + }; + int err; + int len; + + IPW_DEBUG_HC("DISASSOCIATION_BSSID\n"); + + len = ETH_ALEN; + /* The Firmware currently ignores the BSSID and just disassociates from + * the currently associated AP -- but in the off chance that a future + * firmware does use the BSSID provided here, we go ahead and try and + * set it to the currently associated AP's BSSID */ + memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN); + + err = ipw2100_hw_send_command(priv, &cmd); + + return err; +} + +static int ipw2100_set_wpa_ie(struct ipw2100_priv *, + struct ipw2100_wpa_assoc_frame *, int) + __attribute__ ((unused)); + +static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv, + struct ipw2100_wpa_assoc_frame *wpa_frame, + int batch_mode) +{ + struct host_command cmd = { + .host_command = SET_WPA_IE, + .host_command_sequence = 0, + .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame), + }; + int err; + + IPW_DEBUG_HC("SET_WPA_IE\n"); + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + memcpy(cmd.host_command_parameters, wpa_frame, + sizeof(struct ipw2100_wpa_assoc_frame)); + + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) { + if (ipw2100_enable_adapter(priv)) + err = -EIO; + } + + return err; +} + +struct security_info_params { + u32 allowed_ciphers; + u16 version; + u8 auth_mode; + u8 replay_counters_number; + u8 unicast_using_group; +} __attribute__ ((packed)); + +static int ipw2100_set_security_information(struct ipw2100_priv *priv, + int auth_mode, + int security_level, + int unicast_using_group, + int batch_mode) +{ + struct host_command cmd = { + .host_command = SET_SECURITY_INFORMATION, + .host_command_sequence = 0, + .host_command_length = sizeof(struct security_info_params) + }; + struct security_info_params *security = + (struct security_info_params *)&cmd.host_command_parameters; + int err; + memset(security, 0, sizeof(*security)); + + /* If shared key AP authentication is turned on, then we need to + * configure the firmware to try and use it. + * + * Actual data encryption/decryption is handled by the host. */ + security->auth_mode = auth_mode; + security->unicast_using_group = unicast_using_group; + + switch (security_level) { + default: + case SEC_LEVEL_0: + security->allowed_ciphers = IPW_NONE_CIPHER; + break; + case SEC_LEVEL_1: + security->allowed_ciphers = IPW_WEP40_CIPHER | + IPW_WEP104_CIPHER; + break; + case SEC_LEVEL_2: + security->allowed_ciphers = IPW_WEP40_CIPHER | + IPW_WEP104_CIPHER | IPW_TKIP_CIPHER; + break; + case SEC_LEVEL_2_CKIP: + security->allowed_ciphers = IPW_WEP40_CIPHER | + IPW_WEP104_CIPHER | IPW_CKIP_CIPHER; + break; + case SEC_LEVEL_3: + security->allowed_ciphers = IPW_WEP40_CIPHER | + IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER; + break; + } + + IPW_DEBUG_HC + ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n", + security->auth_mode, security->allowed_ciphers, security_level); + + security->replay_counters_number = 0; + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) + ipw2100_enable_adapter(priv); + + return err; +} + +static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power) +{ + struct host_command cmd = { + .host_command = TX_POWER_INDEX, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err = 0; + u32 tmp = tx_power; + + if (tx_power != IPW_TX_POWER_DEFAULT) + tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 / + (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); + + cmd.host_command_parameters[0] = tmp; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + err = ipw2100_hw_send_command(priv, &cmd); + if (!err) + priv->tx_power = tx_power; + + return 0; +} + +static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, + u32 interval, int batch_mode) +{ + struct host_command cmd = { + .host_command = BEACON_INTERVAL, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + cmd.host_command_parameters[0] = interval; + + IPW_DEBUG_INFO("enter\n"); + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) { + err = ipw2100_enable_adapter(priv); + if (err) + return err; + } + } + + IPW_DEBUG_INFO("exit\n"); + + return 0; +} + +void ipw2100_queues_initialize(struct ipw2100_priv *priv) +{ + ipw2100_tx_initialize(priv); + ipw2100_rx_initialize(priv); + ipw2100_msg_initialize(priv); +} + +void ipw2100_queues_free(struct ipw2100_priv *priv) +{ + ipw2100_tx_free(priv); + ipw2100_rx_free(priv); + ipw2100_msg_free(priv); +} + +int ipw2100_queues_allocate(struct ipw2100_priv *priv) +{ + if (ipw2100_tx_allocate(priv) || + ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv)) + goto fail; + + return 0; + + fail: + ipw2100_tx_free(priv); + ipw2100_rx_free(priv); + ipw2100_msg_free(priv); + return -ENOMEM; +} + +#define IPW_PRIVACY_CAPABLE 0x0008 + +static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags, + int batch_mode) +{ + struct host_command cmd = { + .host_command = WEP_FLAGS, + .host_command_sequence = 0, + .host_command_length = 4 + }; + int err; + + cmd.host_command_parameters[0] = flags; + + IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags); + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) { + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", + priv->net_dev->name, err); + return err; + } + } + + /* send cmd to firmware */ + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) + ipw2100_enable_adapter(priv); + + return err; +} + +struct ipw2100_wep_key { + u8 idx; + u8 len; + u8 key[13]; +}; + +/* Macros to ease up priting WEP keys */ +#define WEP_FMT_64 "%02X%02X%02X%02X-%02X" +#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X" +#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4] +#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10] + +/** + * Set a the wep key + * + * @priv: struct to work on + * @idx: index of the key we want to set + * @key: ptr to the key data to set + * @len: length of the buffer at @key + * @batch_mode: FIXME perform the operation in batch mode, not + * disabling the device. + * + * @returns 0 if OK, < 0 errno code on error. + * + * Fill out a command structure with the new wep key, length an + * index and send it down the wire. + */ +static int ipw2100_set_key(struct ipw2100_priv *priv, + int idx, char *key, int len, int batch_mode) +{ + int keylen = len ? (len <= 5 ? 5 : 13) : 0; + struct host_command cmd = { + .host_command = WEP_KEY_INFO, + .host_command_sequence = 0, + .host_command_length = sizeof(struct ipw2100_wep_key), + }; + struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters; + int err; + + IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n", + idx, keylen, len); + + /* NOTE: We don't check cached values in case the firmware was reset + * or some other problem is occurring. If the user is setting the key, + * then we push the change */ + + wep_key->idx = idx; + wep_key->len = keylen; + + if (keylen) { + memcpy(wep_key->key, key, len); + memset(wep_key->key + len, 0, keylen - len); + } + + /* Will be optimized out on debug not being configured in */ + if (keylen == 0) + IPW_DEBUG_WEP("%s: Clearing key %d\n", + priv->net_dev->name, wep_key->idx); + else if (keylen == 5) + IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n", + priv->net_dev->name, wep_key->idx, wep_key->len, + WEP_STR_64(wep_key->key)); + else + IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128 + "\n", + priv->net_dev->name, wep_key->idx, wep_key->len, + WEP_STR_128(wep_key->key)); + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */ + if (err) { + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", + priv->net_dev->name, err); + return err; + } + } + + /* send cmd to firmware */ + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) { + int err2 = ipw2100_enable_adapter(priv); + if (err == 0) + err = err2; + } + return err; +} + +static int ipw2100_set_key_index(struct ipw2100_priv *priv, + int idx, int batch_mode) +{ + struct host_command cmd = { + .host_command = WEP_KEY_INDEX, + .host_command_sequence = 0, + .host_command_length = 4, + .host_command_parameters = {idx}, + }; + int err; + + IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx); + + if (idx < 0 || idx > 3) + return -EINVAL; + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) { + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", + priv->net_dev->name, err); + return err; + } + } + + /* send cmd to firmware */ + err = ipw2100_hw_send_command(priv, &cmd); + + if (!batch_mode) + ipw2100_enable_adapter(priv); + + return err; +} + +static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) +{ + int i, err, auth_mode, sec_level, use_group; + + if (!(priv->status & STATUS_RUNNING)) + return 0; + + if (!batch_mode) { + err = ipw2100_disable_adapter(priv); + if (err) + return err; + } + + if (!priv->ieee->sec.enabled) { + err = + ipw2100_set_security_information(priv, IPW_AUTH_OPEN, + SEC_LEVEL_0, 0, 1); + } else { + auth_mode = IPW_AUTH_OPEN; + if (priv->ieee->sec.flags & SEC_AUTH_MODE) { + if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY) + auth_mode = IPW_AUTH_SHARED; + else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP) + auth_mode = IPW_AUTH_LEAP_CISCO_ID; + } + + sec_level = SEC_LEVEL_0; + if (priv->ieee->sec.flags & SEC_LEVEL) + sec_level = priv->ieee->sec.level; + + use_group = 0; + if (priv->ieee->sec.flags & SEC_UNICAST_GROUP) + use_group = priv->ieee->sec.unicast_uses_group; + + err = + ipw2100_set_security_information(priv, auth_mode, sec_level, + use_group, 1); + } + + if (err) + goto exit; + + if (priv->ieee->sec.enabled) { + for (i = 0; i < 4; i++) { + if (!(priv->ieee->sec.flags & (1 << i))) { + memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN); + priv->ieee->sec.key_sizes[i] = 0; + } else { + err = ipw2100_set_key(priv, i, + priv->ieee->sec.keys[i], + priv->ieee->sec. + key_sizes[i], 1); + if (err) + goto exit; + } + } + + ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1); + } + + /* Always enable privacy so the Host can filter WEP packets if + * encrypted data is sent up */ + err = + ipw2100_set_wep_flags(priv, + priv->ieee->sec. + enabled ? IPW_PRIVACY_CAPABLE : 0, 1); + if (err) + goto exit; + + priv->status &= ~STATUS_SECURITY_UPDATED; + + exit: + if (!batch_mode) + ipw2100_enable_adapter(priv); + + return err; +} + +static void ipw2100_security_work(struct work_struct *work) +{ + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, security_work.work); + + /* If we happen to have reconnected before we get a chance to + * process this, then update the security settings--which causes + * a disassociation to occur */ + if (!(priv->status & STATUS_ASSOCIATED) && + priv->status & STATUS_SECURITY_UPDATED) + ipw2100_configure_security(priv, 0); +} + +static void shim__set_security(struct net_device *dev, + struct ieee80211_security *sec) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int i, force_update = 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) + goto done; + + for (i = 0; i < 4; i++) { + if (sec->flags & (1 << i)) { + priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; + if (sec->key_sizes[i] == 0) + priv->ieee->sec.flags &= ~(1 << i); + else + memcpy(priv->ieee->sec.keys[i], sec->keys[i], + sec->key_sizes[i]); + if (sec->level == SEC_LEVEL_1) { + priv->ieee->sec.flags |= (1 << i); + priv->status |= STATUS_SECURITY_UPDATED; + } else + priv->ieee->sec.flags &= ~(1 << i); + } + } + + if ((sec->flags & SEC_ACTIVE_KEY) && + priv->ieee->sec.active_key != sec->active_key) { + if (sec->active_key <= 3) { + priv->ieee->sec.active_key = sec->active_key; + priv->ieee->sec.flags |= SEC_ACTIVE_KEY; + } else + priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; + + priv->status |= STATUS_SECURITY_UPDATED; + } + + if ((sec->flags & SEC_AUTH_MODE) && + (priv->ieee->sec.auth_mode != sec->auth_mode)) { + priv->ieee->sec.auth_mode = sec->auth_mode; + priv->ieee->sec.flags |= SEC_AUTH_MODE; + priv->status |= STATUS_SECURITY_UPDATED; + } + + if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) { + priv->ieee->sec.flags |= SEC_ENABLED; + priv->ieee->sec.enabled = sec->enabled; + priv->status |= STATUS_SECURITY_UPDATED; + force_update = 1; + } + + if (sec->flags & SEC_ENCRYPT) + priv->ieee->sec.encrypt = sec->encrypt; + + if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { + priv->ieee->sec.level = sec->level; + priv->ieee->sec.flags |= SEC_LEVEL; + priv->status |= STATUS_SECURITY_UPDATED; + } + + IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n", + priv->ieee->sec.flags & (1 << 8) ? '1' : '0', + priv->ieee->sec.flags & (1 << 7) ? '1' : '0', + priv->ieee->sec.flags & (1 << 6) ? '1' : '0', + priv->ieee->sec.flags & (1 << 5) ? '1' : '0', + priv->ieee->sec.flags & (1 << 4) ? '1' : '0', + priv->ieee->sec.flags & (1 << 3) ? '1' : '0', + priv->ieee->sec.flags & (1 << 2) ? '1' : '0', + priv->ieee->sec.flags & (1 << 1) ? '1' : '0', + priv->ieee->sec.flags & (1 << 0) ? '1' : '0'); + +/* As a temporary work around to enable WPA until we figure out why + * wpa_supplicant toggles the security capability of the driver, which + * forces a disassocation with force_update... + * + * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/ + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) + ipw2100_configure_security(priv, 0); + done: + mutex_unlock(&priv->action_mutex); +} + +static int ipw2100_adapter_setup(struct ipw2100_priv *priv) +{ + int err; + int batch_mode = 1; + u8 *bssid; + + IPW_DEBUG_INFO("enter\n"); + + err = ipw2100_disable_adapter(priv); + if (err) + return err; +#ifdef CONFIG_IPW2100_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + err = ipw2100_set_channel(priv, priv->channel, batch_mode); + if (err) + return err; + + IPW_DEBUG_INFO("exit\n"); + + return 0; + } +#endif /* CONFIG_IPW2100_MONITOR */ + + err = ipw2100_read_mac_address(priv); + if (err) + return -EIO; + + err = ipw2100_set_mac_address(priv, batch_mode); + if (err) + return err; + + err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode); + if (err) + return err; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + err = ipw2100_set_channel(priv, priv->channel, batch_mode); + if (err) + return err; + } + + err = ipw2100_system_config(priv, batch_mode); + if (err) + return err; + + err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode); + if (err) + return err; + + /* Default to power mode OFF */ + err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM); + if (err) + return err; + + err = ipw2100_set_rts_threshold(priv, priv->rts_threshold); + if (err) + return err; + + if (priv->config & CFG_STATIC_BSSID) + bssid = priv->bssid; + else + bssid = NULL; + err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode); + if (err) + return err; + + if (priv->config & CFG_STATIC_ESSID) + err = ipw2100_set_essid(priv, priv->essid, priv->essid_len, + batch_mode); + else + err = ipw2100_set_essid(priv, NULL, 0, batch_mode); + if (err) + return err; + + err = ipw2100_configure_security(priv, batch_mode); + if (err) + return err; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + err = + ipw2100_set_ibss_beacon_interval(priv, + priv->beacon_interval, + batch_mode); + if (err) + return err; + + err = ipw2100_set_tx_power(priv, priv->tx_power); + if (err) + return err; + } + + /* + err = ipw2100_set_fragmentation_threshold( + priv, priv->frag_threshold, batch_mode); + if (err) + return err; + */ + + IPW_DEBUG_INFO("exit\n"); + + return 0; +} + +/************************************************************************* + * + * EXTERNALLY CALLED METHODS + * + *************************************************************************/ + +/* This method is called by the network layer -- not to be confused with + * ipw2100_set_mac_address() declared above called by this driver (and this + * method as well) to talk to the firmware */ +static int ipw2100_set_address(struct net_device *dev, void *p) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct sockaddr *addr = p; + int err = 0; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + mutex_lock(&priv->action_mutex); + + priv->config |= CFG_CUSTOM_MAC; + memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); + + err = ipw2100_set_mac_address(priv, 0); + if (err) + goto done; + + priv->reset_backoff = 0; + mutex_unlock(&priv->action_mutex); + ipw2100_reset_adapter(&priv->reset_work.work); + return 0; + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_open(struct net_device *dev) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + unsigned long flags; + IPW_DEBUG_INFO("dev->open\n"); + + spin_lock_irqsave(&priv->low_lock, flags); + if (priv->status & STATUS_ASSOCIATED) { + netif_carrier_on(dev); + netif_start_queue(dev); + } + spin_unlock_irqrestore(&priv->low_lock, flags); + + return 0; +} + +static int ipw2100_close(struct net_device *dev) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + unsigned long flags; + struct list_head *element; + struct ipw2100_tx_packet *packet; + + IPW_DEBUG_INFO("enter\n"); + + spin_lock_irqsave(&priv->low_lock, flags); + + if (priv->status & STATUS_ASSOCIATED) + netif_carrier_off(dev); + netif_stop_queue(dev); + + /* Flush the TX queue ... */ + while (!list_empty(&priv->tx_pend_list)) { + element = priv->tx_pend_list.next; + packet = list_entry(element, struct ipw2100_tx_packet, list); + + list_del(element); + DEC_STAT(&priv->tx_pend_stat); + + ieee80211_txb_free(packet->info.d_struct.txb); + packet->info.d_struct.txb = NULL; + + list_add_tail(element, &priv->tx_free_list); + INC_STAT(&priv->tx_free_stat); + } + spin_unlock_irqrestore(&priv->low_lock, flags); + + IPW_DEBUG_INFO("exit\n"); + + return 0; +} + +/* + * TODO: Fix this function... its just wrong + */ +static void ipw2100_tx_timeout(struct net_device *dev) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + + priv->ieee->stats.tx_errors++; + +#ifdef CONFIG_IPW2100_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) + return; +#endif + + IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n", + dev->name); + schedule_reset(priv); +} + +static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) +{ + /* This is called when wpa_supplicant loads and closes the driver + * interface. */ + priv->ieee->wpa_enabled = value; + return 0; +} + +static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) +{ + + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_security sec = { + .flags = SEC_AUTH_MODE, + }; + int ret = 0; + + if (value & IW_AUTH_ALG_SHARED_KEY) { + sec.auth_mode = WLAN_AUTH_SHARED_KEY; + ieee->open_wep = 0; + } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { + sec.auth_mode = WLAN_AUTH_OPEN; + ieee->open_wep = 1; + } else if (value & IW_AUTH_ALG_LEAP) { + sec.auth_mode = WLAN_AUTH_LEAP; + ieee->open_wep = 1; + } else + return -EINVAL; + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + else + ret = -EOPNOTSUPP; + + return ret; +} + +static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, + char *wpa_ie, int wpa_ie_len) +{ + + struct ipw2100_wpa_assoc_frame frame; + + frame.fixed_ie_mask = 0; + + /* copy WPA IE */ + memcpy(frame.var_ie, wpa_ie, wpa_ie_len); + frame.var_ie_len = wpa_ie_len; + + /* make sure WPA is enabled */ + ipw2100_wpa_enable(priv, 1); + ipw2100_set_wpa_ie(priv, &frame, 0); +} + +static void ipw_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + char fw_ver[64], ucode_ver[64]; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + + ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver)); + ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver)); + + snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s", + fw_ver, priv->eeprom_version, ucode_ver); + + strcpy(info->bus_info, pci_name(priv->pci_dev)); +} + +static u32 ipw2100_ethtool_get_link(struct net_device *dev) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; +} + +static const struct ethtool_ops ipw2100_ethtool_ops = { + .get_link = ipw2100_ethtool_get_link, + .get_drvinfo = ipw_ethtool_get_drvinfo, +}; + +static void ipw2100_hang_check(struct work_struct *work) +{ + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, hang_check.work); + unsigned long flags; + u32 rtc = 0xa5a5a5a5; + u32 len = sizeof(rtc); + int restart = 0; + + spin_lock_irqsave(&priv->low_lock, flags); + + if (priv->fatal_error != 0) { + /* If fatal_error is set then we need to restart */ + IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n", + priv->net_dev->name); + + restart = 1; + } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) || + (rtc == priv->last_rtc)) { + /* Check if firmware is hung */ + IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n", + priv->net_dev->name); + + restart = 1; + } + + if (restart) { + /* Kill timer */ + priv->stop_hang_check = 1; + priv->hangs++; + + /* Restart the NIC */ + schedule_reset(priv); + } + + priv->last_rtc = rtc; + + if (!priv->stop_hang_check) + queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); + + spin_unlock_irqrestore(&priv->low_lock, flags); +} + +static void ipw2100_rf_kill(struct work_struct *work) +{ + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, rf_kill.work); + unsigned long flags; + + spin_lock_irqsave(&priv->low_lock, flags); + + if (rf_kill_active(priv)) { + IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); + if (!priv->stop_rf_kill) + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies_relative(HZ)); + goto exit_unlock; + } + + /* RF Kill is now disabled, so bring the device back up */ + + if (!(priv->status & STATUS_RF_KILL_MASK)) { + IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting " + "device\n"); + schedule_reset(priv); + } else + IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " + "enabled\n"); + + exit_unlock: + spin_unlock_irqrestore(&priv->low_lock, flags); +} + +static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); + +/* Look into using netdev destructor to shutdown ieee80211? */ + +static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, + void __iomem * base_addr, + unsigned long mem_start, + unsigned long mem_len) +{ + struct ipw2100_priv *priv; + struct net_device *dev; + + dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); + if (!dev) + return NULL; + priv = ieee80211_priv(dev); + priv->ieee = netdev_priv(dev); + priv->pci_dev = pci_dev; + priv->net_dev = dev; + + priv->ieee->hard_start_xmit = ipw2100_tx; + priv->ieee->set_security = shim__set_security; + + priv->ieee->perfect_rssi = -20; + priv->ieee->worst_rssi = -85; + + dev->open = ipw2100_open; + dev->stop = ipw2100_close; + dev->init = ipw2100_net_init; + dev->ethtool_ops = &ipw2100_ethtool_ops; + dev->tx_timeout = ipw2100_tx_timeout; + dev->wireless_handlers = &ipw2100_wx_handler_def; + priv->wireless_data.ieee80211 = priv->ieee; + dev->wireless_data = &priv->wireless_data; + dev->set_mac_address = ipw2100_set_address; + dev->watchdog_timeo = 3 * HZ; + dev->irq = 0; + + dev->base_addr = (unsigned long)base_addr; + dev->mem_start = mem_start; + dev->mem_end = dev->mem_start + mem_len - 1; + + /* NOTE: We don't use the wireless_handlers hook + * in dev as the system will start throwing WX requests + * to us before we're actually initialized and it just + * ends up causing problems. So, we just handle + * the WX extensions through the ipw2100_ioctl interface */ + + /* memset() puts everything to 0, so we only have explicitly set + * those values that need to be something else */ + + /* If power management is turned on, default to AUTO mode */ + priv->power_mode = IPW_POWER_AUTO; + +#ifdef CONFIG_IPW2100_MONITOR + priv->config |= CFG_CRC_CHECK; +#endif + priv->ieee->wpa_enabled = 0; + priv->ieee->drop_unencrypted = 0; + priv->ieee->privacy_invoked = 0; + priv->ieee->ieee802_1x = 1; + + /* Set module parameters */ + switch (mode) { + case 1: + priv->ieee->iw_mode = IW_MODE_ADHOC; + break; +#ifdef CONFIG_IPW2100_MONITOR + case 2: + priv->ieee->iw_mode = IW_MODE_MONITOR; + break; +#endif + default: + case 0: + priv->ieee->iw_mode = IW_MODE_INFRA; + break; + } + + if (disable == 1) + priv->status |= STATUS_RF_KILL_SW; + + if (channel != 0 && + ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) { + priv->config |= CFG_STATIC_CHANNEL; + priv->channel = channel; + } + + if (associate) + priv->config |= CFG_ASSOCIATE; + + priv->beacon_interval = DEFAULT_BEACON_INTERVAL; + priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; + priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; + priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED; + priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED; + priv->tx_power = IPW_TX_POWER_DEFAULT; + priv->tx_rates = DEFAULT_TX_RATES; + + strcpy(priv->nick, "ipw2100"); + + spin_lock_init(&priv->low_lock); + mutex_init(&priv->action_mutex); + mutex_init(&priv->adapter_mutex); + + init_waitqueue_head(&priv->wait_command_queue); + + netif_carrier_off(dev); + + INIT_LIST_HEAD(&priv->msg_free_list); + INIT_LIST_HEAD(&priv->msg_pend_list); + INIT_STAT(&priv->msg_free_stat); + INIT_STAT(&priv->msg_pend_stat); + + INIT_LIST_HEAD(&priv->tx_free_list); + INIT_LIST_HEAD(&priv->tx_pend_list); + INIT_STAT(&priv->tx_free_stat); + INIT_STAT(&priv->tx_pend_stat); + + INIT_LIST_HEAD(&priv->fw_pend_list); + INIT_STAT(&priv->fw_pend_stat); + + priv->workqueue = create_workqueue(DRV_NAME); + + INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter); + INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work); + INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work); + INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check); + INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill); + INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now); + INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later); + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + ipw2100_irq_tasklet, (unsigned long)priv); + + /* NOTE: We do not start the deferred work for status checks yet */ + priv->stop_rf_kill = 1; + priv->stop_hang_check = 1; + + return dev; +} + +static int ipw2100_pci_init_one(struct pci_dev *pci_dev, + const struct pci_device_id *ent) +{ + unsigned long mem_start, mem_len, mem_flags; + void __iomem *base_addr = NULL; + struct net_device *dev = NULL; + struct ipw2100_priv *priv = NULL; + int err = 0; + int registered = 0; + u32 val; + + IPW_DEBUG_INFO("enter\n"); + + mem_start = pci_resource_start(pci_dev, 0); + mem_len = pci_resource_len(pci_dev, 0); + mem_flags = pci_resource_flags(pci_dev, 0); + + if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) { + IPW_DEBUG_INFO("weird - resource type is not memory\n"); + err = -ENODEV; + goto fail; + } + + base_addr = ioremap_nocache(mem_start, mem_len); + if (!base_addr) { + printk(KERN_WARNING DRV_NAME + "Error calling ioremap_nocache.\n"); + err = -EIO; + goto fail; + } + + /* allocate and initialize our net_device */ + dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len); + if (!dev) { + printk(KERN_WARNING DRV_NAME + "Error calling ipw2100_alloc_device.\n"); + err = -ENOMEM; + goto fail; + } + + /* set up PCI mappings for device */ + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling pci_enable_device.\n"); + return err; + } + + priv = ieee80211_priv(dev); + + pci_set_master(pci_dev); + pci_set_drvdata(pci_dev, priv); + + err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling pci_set_dma_mask.\n"); + pci_disable_device(pci_dev); + return err; + } + + err = pci_request_regions(pci_dev, DRV_NAME); + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling pci_request_regions.\n"); + pci_disable_device(pci_dev); + return err; + } + + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(pci_dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); + + pci_set_power_state(pci_dev, PCI_D0); + + if (!ipw2100_hw_is_adapter_in_system(dev)) { + printk(KERN_WARNING DRV_NAME + "Device not found via register read.\n"); + err = -ENODEV; + goto fail; + } + + SET_NETDEV_DEV(dev, &pci_dev->dev); + + /* Force interrupts to be shut off on the device */ + priv->status |= STATUS_INT_ENABLED; + ipw2100_disable_interrupts(priv); + + /* Allocate and initialize the Tx/Rx queues and lists */ + if (ipw2100_queues_allocate(priv)) { + printk(KERN_WARNING DRV_NAME + "Error calling ipw2100_queues_allocate.\n"); + err = -ENOMEM; + goto fail; + } + ipw2100_queues_initialize(priv); + + err = request_irq(pci_dev->irq, + ipw2100_interrupt, IRQF_SHARED, dev->name, priv); + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling request_irq: %d.\n", pci_dev->irq); + goto fail; + } + dev->irq = pci_dev->irq; + + IPW_DEBUG_INFO("Attempting to register device...\n"); + + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2100 Network Connection\n"); + + /* Bring up the interface. Pre 0.46, after we registered the + * network device we would call ipw2100_up. This introduced a race + * condition with newer hotplug configurations (network was coming + * up and making calls before the device was initialized). + * + * If we called ipw2100_up before we registered the device, then the + * device name wasn't registered. So, we instead use the net_dev->init + * member to call a function that then just turns and calls ipw2100_up. + * net_dev->init is called after name allocation but before the + * notifier chain is called */ + err = register_netdev(dev); + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling register_netdev.\n"); + goto fail; + } + + mutex_lock(&priv->action_mutex); + registered = 1; + + IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev)); + + /* perform this after register_netdev so that dev->name is set */ + err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); + if (err) + goto fail_unlock; + + /* If the RF Kill switch is disabled, go ahead and complete the + * startup sequence */ + if (!(priv->status & STATUS_RF_KILL_MASK)) { + /* Enable the adapter - sends HOST_COMPLETE */ + if (ipw2100_enable_adapter(priv)) { + printk(KERN_WARNING DRV_NAME + ": %s: failed in call to enable adapter.\n", + priv->net_dev->name); + ipw2100_hw_stop_adapter(priv); + err = -EIO; + goto fail_unlock; + } + + /* Start a scan . . . */ + ipw2100_set_scan_options(priv); + ipw2100_start_scan(priv); + } + + IPW_DEBUG_INFO("exit\n"); + + priv->status |= STATUS_INITIALIZED; + + mutex_unlock(&priv->action_mutex); + + return 0; + + fail_unlock: + mutex_unlock(&priv->action_mutex); + + fail: + if (dev) { + if (registered) + unregister_netdev(dev); + + ipw2100_hw_stop_adapter(priv); + + ipw2100_disable_interrupts(priv); + + if (dev->irq) + free_irq(dev->irq, priv); + + ipw2100_kill_workqueue(priv); + + /* These are safe to call even if they weren't allocated */ + ipw2100_queues_free(priv); + sysfs_remove_group(&pci_dev->dev.kobj, + &ipw2100_attribute_group); + + free_ieee80211(dev); + pci_set_drvdata(pci_dev, NULL); + } + + if (base_addr) + iounmap(base_addr); + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + + return err; +} + +static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) +{ + struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); + struct net_device *dev; + + if (priv) { + mutex_lock(&priv->action_mutex); + + priv->status &= ~STATUS_INITIALIZED; + + dev = priv->net_dev; + sysfs_remove_group(&pci_dev->dev.kobj, + &ipw2100_attribute_group); + +#ifdef CONFIG_PM + if (ipw2100_firmware.version) + ipw2100_release_firmware(priv, &ipw2100_firmware); +#endif + /* Take down the hardware */ + ipw2100_down(priv); + + /* Release the mutex so that the network subsystem can + * complete any needed calls into the driver... */ + mutex_unlock(&priv->action_mutex); + + /* Unregister the device first - this results in close() + * being called if the device is open. If we free storage + * first, then close() will crash. */ + unregister_netdev(dev); + + /* ipw2100_down will ensure that there is no more pending work + * in the workqueue's, so we can safely remove them now. */ + ipw2100_kill_workqueue(priv); + + ipw2100_queues_free(priv); + + /* Free potential debugging firmware snapshot */ + ipw2100_snapshot_free(priv); + + if (dev->irq) + free_irq(dev->irq, priv); + + if (dev->base_addr) + iounmap((void __iomem *)dev->base_addr); + + free_ieee80211(dev); + } + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + + IPW_DEBUG_INFO("exit\n"); +} + +#ifdef CONFIG_PM +static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); + struct net_device *dev = priv->net_dev; + + IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name); + + mutex_lock(&priv->action_mutex); + if (priv->status & STATUS_INITIALIZED) { + /* Take down the device; powers it off, etc. */ + ipw2100_down(priv); + } + + /* Remove the PRESENT state of the device */ + netif_device_detach(dev); + + pci_save_state(pci_dev); + pci_disable_device(pci_dev); + pci_set_power_state(pci_dev, PCI_D3hot); + + mutex_unlock(&priv->action_mutex); + + return 0; +} + +static int ipw2100_resume(struct pci_dev *pci_dev) +{ + struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); + struct net_device *dev = priv->net_dev; + int err; + u32 val; + + if (IPW2100_PM_DISABLED) + return 0; + + mutex_lock(&priv->action_mutex); + + IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name); + + pci_set_power_state(pci_dev, PCI_D0); + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s: pci_enable_device failed on resume\n", + dev->name); + mutex_unlock(&priv->action_mutex); + return err; + } + pci_restore_state(pci_dev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_read_config_dword(pci_dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); + + /* Set the device back into the PRESENT state; this will also wake + * the queue of needed */ + netif_device_attach(dev); + + /* Bring the device back up */ + if (!(priv->status & STATUS_RF_KILL_SW)) + ipw2100_up(priv, 0); + + mutex_unlock(&priv->action_mutex); + + return 0; +} +#endif + +#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } + +static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { + IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */ + IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */ + IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */ + IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */ + + IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */ + + IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */ + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table); + +static struct pci_driver ipw2100_pci_driver = { + .name = DRV_NAME, + .id_table = ipw2100_pci_id_table, + .probe = ipw2100_pci_init_one, + .remove = __devexit_p(ipw2100_pci_remove_one), +#ifdef CONFIG_PM + .suspend = ipw2100_suspend, + .resume = ipw2100_resume, +#endif +}; + +/** + * Initialize the ipw2100 driver/module + * + * @returns 0 if ok, < 0 errno node con error. + * + * Note: we cannot init the /proc stuff until the PCI driver is there, + * or we risk an unlikely race condition on someone accessing + * uninitialized data in the PCI dev struct through /proc. + */ +static int __init ipw2100_init(void) +{ + int ret; + + printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); + + ret = pci_register_driver(&ipw2100_pci_driver); + if (ret) + goto out; + + pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", + PM_QOS_DEFAULT_VALUE); +#ifdef CONFIG_IPW2100_DEBUG + ipw2100_debug_level = debug; + ret = driver_create_file(&ipw2100_pci_driver.driver, + &driver_attr_debug_level); +#endif + +out: + return ret; +} + +/** + * Cleanup ipw2100 driver registration + */ +static void __exit ipw2100_exit(void) +{ + /* FIXME: IPG: check that we have no instances of the devices open */ +#ifdef CONFIG_IPW2100_DEBUG + driver_remove_file(&ipw2100_pci_driver.driver, + &driver_attr_debug_level); +#endif + pci_unregister_driver(&ipw2100_pci_driver); + pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100"); +} + +module_init(ipw2100_init); +module_exit(ipw2100_exit); + +#define WEXT_USECHANNELS 1 + +static const long ipw2100_frequencies[] = { + 2412, 2417, 2422, 2427, + 2432, 2437, 2442, 2447, + 2452, 2457, 2462, 2467, + 2472, 2484 +}; + +#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies) + +static const long ipw2100_rates_11b[] = { + 1000000, + 2000000, + 5500000, + 11000000 +}; + +#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b) + +static int ipw2100_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + if (!(priv->status & STATUS_ASSOCIATED)) + strcpy(wrqu->name, "unassociated"); + else + snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); + + IPW_DEBUG_WX("Name: %s\n", wrqu->name); + return 0; +} + +static int ipw2100_wx_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct iw_freq *fwrq = &wrqu->freq; + int err = 0; + + if (priv->ieee->iw_mode == IW_MODE_INFRA) + return -EOPNOTSUPP; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + /* if setting by freq convert to channel */ + if (fwrq->e == 1) { + if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + + while ((c < REG_MAX_CHANNEL) && + (f != ipw2100_frequencies[c])) + c++; + + /* hack to fall through */ + fwrq->e = 0; + fwrq->m = c + 1; + } + } + + if (fwrq->e > 0 || fwrq->m > 1000) { + err = -EOPNOTSUPP; + goto done; + } else { /* Set the channel */ + IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); + err = ipw2100_set_channel(priv, fwrq->m, 0); + } + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + wrqu->freq.e = 0; + + /* If we are associated, trying to associate, or have a statically + * configured CHANNEL then return that; otherwise return ANY */ + if (priv->config & CFG_STATIC_CHANNEL || + priv->status & STATUS_ASSOCIATED) + wrqu->freq.m = priv->channel; + else + wrqu->freq.m = 0; + + IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); + return 0; + +} + +static int ipw2100_wx_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0; + + IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode); + + if (wrqu->mode == priv->ieee->iw_mode) + return 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + switch (wrqu->mode) { +#ifdef CONFIG_IPW2100_MONITOR + case IW_MODE_MONITOR: + err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); + break; +#endif /* CONFIG_IPW2100_MONITOR */ + case IW_MODE_ADHOC: + err = ipw2100_switch_mode(priv, IW_MODE_ADHOC); + break; + case IW_MODE_INFRA: + case IW_MODE_AUTO: + default: + err = ipw2100_switch_mode(priv, IW_MODE_INFRA); + break; + } + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + wrqu->mode = priv->ieee->iw_mode; + IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode); + + return 0; +} + +#define POWER_MODES 5 + +/* Values are in microsecond */ +static const s32 timeout_duration[POWER_MODES] = { + 350000, + 250000, + 75000, + 37000, + 25000, +}; + +static const s32 period_duration[POWER_MODES] = { + 400000, + 700000, + 1000000, + 1000000, + 1000000 +}; + +static int ipw2100_wx_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct iw_range *range = (struct iw_range *)extra; + u16 val; + int i, level; + + wrqu->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + /* Let's try to keep this struct in the same order as in + * linux/include/wireless.h + */ + + /* TODO: See what values we can set, and remove the ones we can't + * set, or fill them with some default data. + */ + + /* ~5 Mb/s real (802.11b) */ + range->throughput = 5 * 1000 * 1000; + +// range->sensitivity; /* signal level threshold range */ + + range->max_qual.qual = 100; + /* TODO: Find real max RSSI and stick here */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = 7; /* Updated all three */ + + range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ + /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ + range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; /* Updated all three */ + + range->num_bitrates = RATE_COUNT; + + for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { + range->bitrate[i] = ipw2100_rates_11b[i]; + } + + range->min_rts = MIN_RTS_THRESHOLD; + range->max_rts = MAX_RTS_THRESHOLD; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->min_pmp = period_duration[0]; /* Minimal PM period */ + range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */ + range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */ + range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */ + + /* How to decode max/min PM period */ + range->pmp_flags = IW_POWER_PERIOD; + /* How to decode max/min PM period */ + range->pmt_flags = IW_POWER_TIMEOUT; + /* What PM options are supported */ + range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; /* Different token sizes */ + range->num_encoding_sizes = 2; /* Number of entry in the list */ + range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */ +// range->encoding_login_index; /* token index for login token */ + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + range->txpower_capa = IW_TXPOW_DBM; + range->num_txpower = IW_MAX_TXPOWER; + for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); + i < IW_MAX_TXPOWER; + i++, level -= + ((IPW_TX_POWER_MAX_DBM - + IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1)) + range->txpower[i] = level / 16; + } else { + range->txpower_capa = 0; + range->num_txpower = 0; + } + + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 18; + +// range->retry_capa; /* What retry options are supported */ +// range->retry_flags; /* How to decode max/min retry limit */ +// range->r_time_flags; /* How to decode max/min retry life */ +// range->min_retry; /* Minimal number of retries */ +// range->max_retry; /* Maximal number of retries */ +// range->min_r_time; /* Minimal retry lifetime */ +// range->max_r_time; /* Maximal retry lifetime */ + + range->num_channels = FREQ_COUNT; + + val = 0; + for (i = 0; i < FREQ_COUNT; i++) { + // TODO: Include only legal frequencies for some countries +// if (local->channel_mask & (1 << i)) { + range->freq[val].i = i + 1; + range->freq[val].m = ipw2100_frequencies[i] * 100000; + range->freq[val].e = 1; + val++; +// } + if (val == IW_MAX_FREQUENCIES) + break; + } + range->num_frequency = val; + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + + IPW_DEBUG_WX("GET Range\n"); + + return 0; +} + +static int ipw2100_wx_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0; + + static const unsigned char any[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + static const unsigned char off[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // sanity checks + if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || + !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { + /* we disable mandatory BSSID association */ + IPW_DEBUG_WX("exit - disable mandatory BSSID\n"); + priv->config &= ~CFG_STATIC_BSSID; + err = ipw2100_set_mandatory_bssid(priv, NULL, 0); + goto done; + } + + priv->config |= CFG_STATIC_BSSID; + memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN); + + err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); + + IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data); + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + /* If we are associated, trying to associate, or have a statically + * configured BSSID then return that; otherwise return ANY */ + if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) { + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); + } else + memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data); + return 0; +} + +static int ipw2100_wx_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + char *essid = ""; /* ANY */ + int length = 0; + int err = 0; + DECLARE_SSID_BUF(ssid); + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (wrqu->essid.flags && wrqu->essid.length) { + length = wrqu->essid.length; + essid = extra; + } + + if (length == 0) { + IPW_DEBUG_WX("Setting ESSID to ANY\n"); + priv->config &= ~CFG_STATIC_ESSID; + err = ipw2100_set_essid(priv, NULL, 0, 0); + goto done; + } + + length = min(length, IW_ESSID_MAX_SIZE); + + priv->config |= CFG_STATIC_ESSID; + + if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { + IPW_DEBUG_WX("ESSID set to current ESSID.\n"); + err = 0; + goto done; + } + + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, essid, length), length); + + priv->essid_len = length; + memcpy(priv->essid, essid, priv->essid_len); + + err = ipw2100_set_essid(priv, essid, length, 0); + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); + + /* If we are associated, trying to associate, or have a statically + * configured ESSID then return that; otherwise return ANY */ + if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { + IPW_DEBUG_WX("Getting essid: '%s'\n", + print_ssid(ssid, priv->essid, priv->essid_len)); + memcpy(extra, priv->essid, priv->essid_len); + wrqu->essid.length = priv->essid_len; + wrqu->essid.flags = 1; /* active */ + } else { + IPW_DEBUG_WX("Getting essid: ANY\n"); + wrqu->essid.length = 0; + wrqu->essid.flags = 0; /* active */ + } + + return 0; +} + +static int ipw2100_wx_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + if (wrqu->data.length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); + memset(priv->nick, 0, sizeof(priv->nick)); + memcpy(priv->nick, extra, wrqu->data.length); + + IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick); + + return 0; +} + +static int ipw2100_wx_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + wrqu->data.length = strlen(priv->nick); + memcpy(extra, priv->nick, wrqu->data.length); + wrqu->data.flags = 1; /* active */ + + IPW_DEBUG_WX("GET Nickname -> %s \n", extra); + + return 0; +} + +static int ipw2100_wx_set_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + u32 target_rate = wrqu->bitrate.value; + u32 rate; + int err = 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + rate = 0; + + if (target_rate == 1000000 || + (!wrqu->bitrate.fixed && target_rate > 1000000)) + rate |= TX_RATE_1_MBIT; + if (target_rate == 2000000 || + (!wrqu->bitrate.fixed && target_rate > 2000000)) + rate |= TX_RATE_2_MBIT; + if (target_rate == 5500000 || + (!wrqu->bitrate.fixed && target_rate > 5500000)) + rate |= TX_RATE_5_5_MBIT; + if (target_rate == 11000000 || + (!wrqu->bitrate.fixed && target_rate > 11000000)) + rate |= TX_RATE_11_MBIT; + if (rate == 0) + rate = DEFAULT_TX_RATES; + + err = ipw2100_set_tx_rates(priv, rate, 0); + + IPW_DEBUG_WX("SET Rate -> %04X \n", rate); + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int val; + int len = sizeof(val); + int err = 0; + + if (!(priv->status & STATUS_ENABLED) || + priv->status & STATUS_RF_KILL_MASK || + !(priv->status & STATUS_ASSOCIATED)) { + wrqu->bitrate.value = 0; + return 0; + } + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len); + if (err) { + IPW_DEBUG_WX("failed querying ordinals.\n"); + goto done; + } + + switch (val & TX_RATE_MASK) { + case TX_RATE_1_MBIT: + wrqu->bitrate.value = 1000000; + break; + case TX_RATE_2_MBIT: + wrqu->bitrate.value = 2000000; + break; + case TX_RATE_5_5_MBIT: + wrqu->bitrate.value = 5500000; + break; + case TX_RATE_11_MBIT: + wrqu->bitrate.value = 11000000; + break; + default: + wrqu->bitrate.value = 0; + } + + IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_set_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int value, err; + + /* Auto RTS not yet supported */ + if (wrqu->rts.fixed == 0) + return -EINVAL; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (wrqu->rts.disabled) + value = priv->rts_threshold | RTS_DISABLED; + else { + if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) { + err = -EINVAL; + goto done; + } + value = wrqu->rts.value; + } + + err = ipw2100_set_rts_threshold(priv, value); + + IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value); + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED; + wrqu->rts.fixed = 1; /* no auto select */ + + /* If RTS is set to the default value, then it is disabled */ + wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0; + + IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value); + + return 0; +} + +static int ipw2100_wx_set_txpow(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0, value; + + if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled)) + return -EINPROGRESS; + + if (priv->ieee->iw_mode != IW_MODE_ADHOC) + return 0; + + if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + + if (wrqu->txpower.fixed == 0) + value = IPW_TX_POWER_DEFAULT; + else { + if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM || + wrqu->txpower.value > IPW_TX_POWER_MAX_DBM) + return -EINVAL; + + value = wrqu->txpower.value; + } + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + err = ipw2100_set_tx_power(priv, value); + + IPW_DEBUG_WX("SET TX Power -> %d \n", value); + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_txpow(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; + + if (priv->tx_power == IPW_TX_POWER_DEFAULT) { + wrqu->txpower.fixed = 0; + wrqu->txpower.value = IPW_TX_POWER_MAX_DBM; + } else { + wrqu->txpower.fixed = 1; + wrqu->txpower.value = priv->tx_power; + } + + wrqu->txpower.flags = IW_TXPOW_DBM; + + IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value); + + return 0; +} + +static int ipw2100_wx_set_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + if (!wrqu->frag.fixed) + return -EINVAL; + + if (wrqu->frag.disabled) { + priv->frag_threshold |= FRAG_DISABLED; + priv->ieee->fts = DEFAULT_FTS; + } else { + if (wrqu->frag.value < MIN_FRAG_THRESHOLD || + wrqu->frag.value > MAX_FRAG_THRESHOLD) + return -EINVAL; + + priv->ieee->fts = wrqu->frag.value & ~0x1; + priv->frag_threshold = priv->ieee->fts; + } + + IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts); + + return 0; +} + +static int ipw2100_wx_get_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED; + wrqu->frag.fixed = 0; /* no auto select */ + wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0; + + IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); + + return 0; +} + +static int ipw2100_wx_set_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0; + + if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) + return -EINVAL; + + if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) + return 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (wrqu->retry.flags & IW_RETRY_SHORT) { + err = ipw2100_set_short_retry(priv, wrqu->retry.value); + IPW_DEBUG_WX("SET Short Retry Limit -> %d \n", + wrqu->retry.value); + goto done; + } + + if (wrqu->retry.flags & IW_RETRY_LONG) { + err = ipw2100_set_long_retry(priv, wrqu->retry.value); + IPW_DEBUG_WX("SET Long Retry Limit -> %d \n", + wrqu->retry.value); + goto done; + } + + err = ipw2100_set_short_retry(priv, wrqu->retry.value); + if (!err) + err = ipw2100_set_long_retry(priv, wrqu->retry.value); + + IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value); + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + wrqu->retry.disabled = 0; /* can't be disabled */ + + if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) + return -EINVAL; + + if (wrqu->retry.flags & IW_RETRY_LONG) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + wrqu->retry.value = priv->long_retry_limit; + } else { + wrqu->retry.flags = + (priv->short_retry_limit != + priv->long_retry_limit) ? + IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT; + + wrqu->retry.value = priv->short_retry_limit; + } + + IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value); + + return 0; +} + +static int ipw2100_wx_set_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + IPW_DEBUG_WX("Initiating scan...\n"); + + priv->user_requested_scan = 1; + if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) { + IPW_DEBUG_WX("Start scan failed.\n"); + + /* TODO: Mark a scan as pending so when hardware initialized + * a scan starts */ + } + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); +} + +/* + * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c + */ +static int ipw2100_wx_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + /* + * No check of STATUS_INITIALIZED required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); +} + +static int ipw2100_wx_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); +} + +static int ipw2100_wx_set_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (wrqu->power.disabled) { + priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); + err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM); + IPW_DEBUG_WX("SET Power Management Mode -> off\n"); + goto done; + } + + switch (wrqu->power.flags & IW_POWER_MODE) { + case IW_POWER_ON: /* If not specified */ + case IW_POWER_MODE: /* If set all mask */ + case IW_POWER_ALL_R: /* If explicitly state all */ + break; + default: /* Otherwise we don't support it */ + IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", + wrqu->power.flags); + err = -EOPNOTSUPP; + goto done; + } + + /* If the user hasn't specified a power management mode yet, default + * to BATTERY */ + priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; + err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); + + IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); + + done: + mutex_unlock(&priv->action_mutex); + return err; + +} + +static int ipw2100_wx_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + if (!(priv->power_mode & IPW_POWER_ENABLED)) + wrqu->power.disabled = 1; + else { + wrqu->power.disabled = 0; + wrqu->power.flags = 0; + } + + IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); + + return 0; +} + +/* + * WE-18 WPA support + */ + +/* SIOCSIWGENIE */ +static int ipw2100_wx_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + u8 *buf; + + if (!ieee->wpa_enabled) + return -EOPNOTSUPP; + + if (wrqu->data.length > MAX_WPA_IE_LEN || + (wrqu->data.length && extra == NULL)) + return -EINVAL; + + if (wrqu->data.length) { + buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = wrqu->data.length; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); + + return 0; +} + +/* SIOCGIWGENIE */ +static int ipw2100_wx_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + + if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { + wrqu->data.length = 0; + return 0; + } + + if (wrqu->data.length < ieee->wpa_ie_len) + return -E2BIG; + + wrqu->data.length = ieee->wpa_ie_len; + memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); + + return 0; +} + +/* SIOCSIWAUTH */ +static int ipw2100_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct iw_param *param = &wrqu->param; + struct lib80211_crypt_data *crypt; + unsigned long flags; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * ipw2200 does not use these parameters + */ + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) + break; + + flags = crypt->ops->get_flags(crypt->priv); + + if (param->value) + flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + else + flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + + crypt->ops->set_flags(flags, crypt->priv); + + break; + + case IW_AUTH_DROP_UNENCRYPTED:{ + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = param->value, + }; + priv->ieee->drop_unencrypted = param->value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!param->value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (priv->ieee->set_security) + priv->ieee->set_security(priv->ieee->dev, &sec); + break; + } + + case IW_AUTH_80211_AUTH_ALG: + ret = ipw2100_wpa_set_auth_algs(priv, param->value); + break; + + case IW_AUTH_WPA_ENABLED: + ret = ipw2100_wpa_enable(priv, param->value); + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = param->value; + break; + + //case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = param->value; + break; + + default: + return -EOPNOTSUPP; + } + return ret; +} + +/* SIOCGIWAUTH */ +static int ipw2100_wx_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct lib80211_crypt_data *crypt; + struct iw_param *param = &wrqu->param; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * wpa_supplicant will control these internally + */ + ret = -EOPNOTSUPP; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; + if (!crypt || !crypt->ops->get_flags) { + IPW_DEBUG_WARNING("Can't get TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + param->value = (crypt->ops->get_flags(crypt->priv) & + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; + + break; + + case IW_AUTH_DROP_UNENCRYPTED: + param->value = ieee->drop_unencrypted; + break; + + case IW_AUTH_80211_AUTH_ALG: + param->value = priv->ieee->sec.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = ieee->wpa_enabled; + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + param->value = ieee->ieee802_1x; + break; + + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + param->value = ieee->privacy_invoked; + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* SIOCSIWENCODEEXT */ +static int ipw2100_wx_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCGIWENCODEEXT */ +static int ipw2100_wx_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCSIWMLME */ +static int ipw2100_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + __le16 reason; + + reason = cpu_to_le16(mlme->reason_code); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + // silently ignore + break; + + case IW_MLME_DISASSOC: + ipw2100_disassociate_bssid(priv); + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* + * + * IWPRIV handlers + * + */ +#ifdef CONFIG_IPW2100_MONITOR +static int ipw2100_wx_set_promisc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int *parms = (int *)extra; + int enable = (parms[0] > 0); + int err = 0; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (enable) { + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + err = ipw2100_set_channel(priv, parms[1], 0); + goto done; + } + priv->channel = parms[1]; + err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); + } else { + if (priv->ieee->iw_mode == IW_MODE_MONITOR) + err = ipw2100_switch_mode(priv, priv->last_mode); + } + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + if (priv->status & STATUS_INITIALIZED) + schedule_reset(priv); + return 0; +} + +#endif + +static int ipw2100_wx_set_powermode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err = 0, mode = *(int *)extra; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if ((mode < 0) || (mode > POWER_MODES)) + mode = IPW_POWER_AUTO; + + if (IPW_POWER_LEVEL(priv->power_mode) != mode) + err = ipw2100_set_power_mode(priv, mode); + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +#define MAX_POWER_STRING 80 +static int ipw2100_wx_get_powermode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + int level = IPW_POWER_LEVEL(priv->power_mode); + s32 timeout, period; + + if (!(priv->power_mode & IPW_POWER_ENABLED)) { + snprintf(extra, MAX_POWER_STRING, + "Power save level: %d (Off)", level); + } else { + switch (level) { + case IPW_POWER_MODE_CAM: + snprintf(extra, MAX_POWER_STRING, + "Power save level: %d (None)", level); + break; + case IPW_POWER_AUTO: + snprintf(extra, MAX_POWER_STRING, + "Power save level: %d (Auto)", level); + break; + default: + timeout = timeout_duration[level - 1] / 1000; + period = period_duration[level - 1] / 1000; + snprintf(extra, MAX_POWER_STRING, + "Power save level: %d " + "(Timeout %dms, Period %dms)", + level, timeout, period); + } + } + + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +static int ipw2100_wx_set_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err, mode = *(int *)extra; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (mode == 1) + priv->config |= CFG_LONG_PREAMBLE; + else if (mode == 0) + priv->config &= ~CFG_LONG_PREAMBLE; + else { + err = -EINVAL; + goto done; + } + + err = ipw2100_system_config(priv, 0); + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + if (priv->config & CFG_LONG_PREAMBLE) + snprintf(wrqu->name, IFNAMSIZ, "long (1)"); + else + snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); + + return 0; +} + +#ifdef CONFIG_IPW2100_MONITOR +static int ipw2100_wx_set_crc_check(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err, mode = *(int *)extra; + + mutex_lock(&priv->action_mutex); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (mode == 1) + priv->config |= CFG_CRC_CHECK; + else if (mode == 0) + priv->config &= ~CFG_CRC_CHECK; + else { + err = -EINVAL; + goto done; + } + err = 0; + + done: + mutex_unlock(&priv->action_mutex); + return err; +} + +static int ipw2100_wx_get_crc_check(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + if (priv->config & CFG_CRC_CHECK) + snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)"); + else + snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)"); + + return 0; +} +#endif /* CONFIG_IPW2100_MONITOR */ + +static iw_handler ipw2100_wx_handlers[] = { + NULL, /* SIOCSIWCOMMIT */ + ipw2100_wx_get_name, /* SIOCGIWNAME */ + NULL, /* SIOCSIWNWID */ + NULL, /* SIOCGIWNWID */ + ipw2100_wx_set_freq, /* SIOCSIWFREQ */ + ipw2100_wx_get_freq, /* SIOCGIWFREQ */ + ipw2100_wx_set_mode, /* SIOCSIWMODE */ + ipw2100_wx_get_mode, /* SIOCGIWMODE */ + NULL, /* SIOCSIWSENS */ + NULL, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + ipw2100_wx_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ + NULL, /* SIOCGIWTHRSPY */ + NULL, /* SIOCWIWTHRSPY */ + ipw2100_wx_set_wap, /* SIOCSIWAP */ + ipw2100_wx_get_wap, /* SIOCGIWAP */ + ipw2100_wx_set_mlme, /* SIOCSIWMLME */ + NULL, /* SIOCGIWAPLIST -- deprecated */ + ipw2100_wx_set_scan, /* SIOCSIWSCAN */ + ipw2100_wx_get_scan, /* SIOCGIWSCAN */ + ipw2100_wx_set_essid, /* SIOCSIWESSID */ + ipw2100_wx_get_essid, /* SIOCGIWESSID */ + ipw2100_wx_set_nick, /* SIOCSIWNICKN */ + ipw2100_wx_get_nick, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + ipw2100_wx_set_rate, /* SIOCSIWRATE */ + ipw2100_wx_get_rate, /* SIOCGIWRATE */ + ipw2100_wx_set_rts, /* SIOCSIWRTS */ + ipw2100_wx_get_rts, /* SIOCGIWRTS */ + ipw2100_wx_set_frag, /* SIOCSIWFRAG */ + ipw2100_wx_get_frag, /* SIOCGIWFRAG */ + ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */ + ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */ + ipw2100_wx_set_retry, /* SIOCSIWRETRY */ + ipw2100_wx_get_retry, /* SIOCGIWRETRY */ + ipw2100_wx_set_encode, /* SIOCSIWENCODE */ + ipw2100_wx_get_encode, /* SIOCGIWENCODE */ + ipw2100_wx_set_power, /* SIOCSIWPOWER */ + ipw2100_wx_get_power, /* SIOCGIWPOWER */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + ipw2100_wx_set_genie, /* SIOCSIWGENIE */ + ipw2100_wx_get_genie, /* SIOCGIWGENIE */ + ipw2100_wx_set_auth, /* SIOCSIWAUTH */ + ipw2100_wx_get_auth, /* SIOCGIWAUTH */ + ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */ + ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */ + NULL, /* SIOCSIWPMKSA */ +}; + +#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV +#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1 +#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2 +#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3 +#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4 +#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5 +#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6 +#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7 + +static const struct iw_priv_args ipw2100_private_args[] = { + +#ifdef CONFIG_IPW2100_MONITOR + { + IPW2100_PRIV_SET_MONITOR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, + { + IPW2100_PRIV_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, +#endif /* CONFIG_IPW2100_MONITOR */ + + { + IPW2100_PRIV_SET_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"}, + { + IPW2100_PRIV_GET_POWER, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, + "get_power"}, + { + IPW2100_PRIV_SET_LONGPREAMBLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"}, + { + IPW2100_PRIV_GET_LONGPREAMBLE, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"}, +#ifdef CONFIG_IPW2100_MONITOR + { + IPW2100_PRIV_SET_CRC_CHECK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"}, + { + IPW2100_PRIV_GET_CRC_CHECK, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"}, +#endif /* CONFIG_IPW2100_MONITOR */ +}; + +static iw_handler ipw2100_private_handler[] = { +#ifdef CONFIG_IPW2100_MONITOR + ipw2100_wx_set_promisc, + ipw2100_wx_reset, +#else /* CONFIG_IPW2100_MONITOR */ + NULL, + NULL, +#endif /* CONFIG_IPW2100_MONITOR */ + ipw2100_wx_set_powermode, + ipw2100_wx_get_powermode, + ipw2100_wx_set_preamble, + ipw2100_wx_get_preamble, +#ifdef CONFIG_IPW2100_MONITOR + ipw2100_wx_set_crc_check, + ipw2100_wx_get_crc_check, +#else /* CONFIG_IPW2100_MONITOR */ + NULL, + NULL, +#endif /* CONFIG_IPW2100_MONITOR */ +}; + +/* + * Get wireless statistics. + * Called by /proc/net/wireless + * Also called by SIOCGIWSTATS + */ +static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) +{ + enum { + POOR = 30, + FAIR = 60, + GOOD = 80, + VERY_GOOD = 90, + EXCELLENT = 95, + PERFECT = 100 + }; + int rssi_qual; + int tx_qual; + int beacon_qual; + + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct iw_statistics *wstats; + u32 rssi, quality, tx_retries, missed_beacons, tx_failures; + u32 ord_len = sizeof(u32); + + if (!priv) + return (struct iw_statistics *)NULL; + + wstats = &priv->wstats; + + /* if hw is disabled, then ipw2100_get_ordinal() can't be called. + * ipw2100_wx_wireless_stats seems to be called before fw is + * initialized. STATUS_ASSOCIATED will only be set if the hw is up + * and associated; if not associcated, the values are all meaningless + * anyway, so set them all to NULL and INVALID */ + if (!(priv->status & STATUS_ASSOCIATED)) { + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = 7; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + return wstats; + } + + if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS, + &missed_beacons, &ord_len)) + goto fail_get_ordinal; + + /* If we don't have a connection the quality and level is 0 */ + if (!(priv->status & STATUS_ASSOCIATED)) { + wstats->qual.qual = 0; + wstats->qual.level = 0; + } else { + if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR, + &rssi, &ord_len)) + goto fail_get_ordinal; + wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM; + if (rssi < 10) + rssi_qual = rssi * POOR / 10; + else if (rssi < 15) + rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR; + else if (rssi < 20) + rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR; + else if (rssi < 30) + rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) / + 10 + GOOD; + else + rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) / + 10 + VERY_GOOD; + + if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES, + &tx_retries, &ord_len)) + goto fail_get_ordinal; + + if (tx_retries > 75) + tx_qual = (90 - tx_retries) * POOR / 15; + else if (tx_retries > 70) + tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; + else if (tx_retries > 65) + tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; + else if (tx_retries > 50) + tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / + 15 + GOOD; + else + tx_qual = (50 - tx_retries) * + (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; + + if (missed_beacons > 50) + beacon_qual = (60 - missed_beacons) * POOR / 10; + else if (missed_beacons > 40) + beacon_qual = (50 - missed_beacons) * (FAIR - POOR) / + 10 + POOR; + else if (missed_beacons > 32) + beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) / + 18 + FAIR; + else if (missed_beacons > 20) + beacon_qual = (32 - missed_beacons) * + (VERY_GOOD - GOOD) / 20 + GOOD; + else + beacon_qual = (20 - missed_beacons) * + (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; + + quality = min(beacon_qual, min(tx_qual, rssi_qual)); + +#ifdef CONFIG_IPW2100_DEBUG + if (beacon_qual == quality) + IPW_DEBUG_WX("Quality clamped by Missed Beacons\n"); + else if (tx_qual == quality) + IPW_DEBUG_WX("Quality clamped by Tx Retries\n"); + else if (quality != 100) + IPW_DEBUG_WX("Quality clamped by Signal Strength\n"); + else + IPW_DEBUG_WX("Quality not clamped.\n"); +#endif + + wstats->qual.qual = quality; + wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM; + } + + wstats->qual.noise = 0; + wstats->qual.updated = 7; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID; + + /* FIXME: this is percent and not a # */ + wstats->miss.beacon = missed_beacons; + + if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES, + &tx_failures, &ord_len)) + goto fail_get_ordinal; + wstats->discard.retries = tx_failures; + + return wstats; + + fail_get_ordinal: + IPW_DEBUG_WX("failed querying ordinals.\n"); + + return (struct iw_statistics *)NULL; +} + +static struct iw_handler_def ipw2100_wx_handler_def = { + .standard = ipw2100_wx_handlers, + .num_standard = ARRAY_SIZE(ipw2100_wx_handlers), + .num_private = ARRAY_SIZE(ipw2100_private_handler), + .num_private_args = ARRAY_SIZE(ipw2100_private_args), + .private = (iw_handler *) ipw2100_private_handler, + .private_args = (struct iw_priv_args *)ipw2100_private_args, + .get_wireless_stats = ipw2100_wx_wireless_stats, +}; + +static void ipw2100_wx_event_work(struct work_struct *work) +{ + struct ipw2100_priv *priv = + container_of(work, struct ipw2100_priv, wx_event_work.work); + union iwreq_data wrqu; + int len = ETH_ALEN; + + if (priv->status & STATUS_STOPPING) + return; + + mutex_lock(&priv->action_mutex); + + IPW_DEBUG_WX("enter\n"); + + mutex_unlock(&priv->action_mutex); + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + + /* Fetch BSSID from the hardware */ + if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) || + priv->status & STATUS_RF_KILL_MASK || + ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, + &priv->bssid, &len)) { + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + } else { + /* We now have the BSSID, so can finish setting to the full + * associated state */ + memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); + memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN); + priv->status &= ~STATUS_ASSOCIATING; + priv->status |= STATUS_ASSOCIATED; + netif_carrier_on(priv->net_dev); + netif_wake_queue(priv->net_dev); + } + + if (!(priv->status & STATUS_ASSOCIATED)) { + IPW_DEBUG_WX("Configuring ESSID\n"); + mutex_lock(&priv->action_mutex); + /* This is a disassociation event, so kick the firmware to + * look for another AP */ + if (priv->config & CFG_STATIC_ESSID) + ipw2100_set_essid(priv, priv->essid, priv->essid_len, + 0); + else + ipw2100_set_essid(priv, NULL, 0, 0); + mutex_unlock(&priv->action_mutex); + } + + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); +} + +#define IPW2100_FW_MAJOR_VERSION 1 +#define IPW2100_FW_MINOR_VERSION 3 + +#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8) +#define IPW2100_FW_MAJOR(x) (x & 0xff) + +#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \ + IPW2100_FW_MAJOR_VERSION) + +#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \ +"." __stringify(IPW2100_FW_MINOR_VERSION) + +#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw" + +/* + +BINARY FIRMWARE HEADER FORMAT + +offset length desc +0 2 version +2 2 mode == 0:BSS,1:IBSS,2:MONITOR +4 4 fw_len +8 4 uc_len +C fw_len firmware data +12 + fw_len uc_len microcode data + +*/ + +struct ipw2100_fw_header { + short version; + short mode; + unsigned int fw_size; + unsigned int uc_size; +} __attribute__ ((packed)); + +static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) +{ + struct ipw2100_fw_header *h = + (struct ipw2100_fw_header *)fw->fw_entry->data; + + if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) { + printk(KERN_WARNING DRV_NAME ": Firmware image not compatible " + "(detected version id of %u). " + "See Documentation/networking/README.ipw2100\n", + h->version); + return 1; + } + + fw->version = h->version; + fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header); + fw->fw.size = h->fw_size; + fw->uc.data = fw->fw.data + h->fw_size; + fw->uc.size = h->uc_size; + + return 0; +} + +static int ipw2100_get_firmware(struct ipw2100_priv *priv, + struct ipw2100_fw *fw) +{ + char *fw_name; + int rc; + + IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n", + priv->net_dev->name); + + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + fw_name = IPW2100_FW_NAME("-i"); + break; +#ifdef CONFIG_IPW2100_MONITOR + case IW_MODE_MONITOR: + fw_name = IPW2100_FW_NAME("-p"); + break; +#endif + case IW_MODE_INFRA: + default: + fw_name = IPW2100_FW_NAME(""); + break; + } + + rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev); + + if (rc < 0) { + printk(KERN_ERR DRV_NAME ": " + "%s: Firmware '%s' not available or load failed.\n", + priv->net_dev->name, fw_name); + return rc; + } + IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data, + fw->fw_entry->size); + + ipw2100_mod_firmware_load(fw); + + return 0; +} + +static void ipw2100_release_firmware(struct ipw2100_priv *priv, + struct ipw2100_fw *fw) +{ + fw->version = 0; + if (fw->fw_entry) + release_firmware(fw->fw_entry); + fw->fw_entry = NULL; +} + +static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, + size_t max) +{ + char ver[MAX_FW_VERSION_LEN]; + u32 len = MAX_FW_VERSION_LEN; + u32 tmp; + int i; + /* firmware version is an ascii string (max len of 14) */ + if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len)) + return -EIO; + tmp = max; + if (len >= max) + len = max - 1; + for (i = 0; i < len; i++) + buf[i] = ver[i]; + buf[i] = '\0'; + return tmp; +} + +static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, + size_t max) +{ + u32 ver; + u32 len = sizeof(ver); + /* microcode version is a 32 bit integer */ + if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len)) + return -EIO; + return snprintf(buf, max, "%08X", ver); +} + +/* + * On exit, the firmware will have been freed from the fw list + */ +static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw) +{ + /* firmware is constructed of N contiguous entries, each entry is + * structured as: + * + * offset sie desc + * 0 4 address to write to + * 4 2 length of data run + * 6 length data + */ + unsigned int addr; + unsigned short len; + + const unsigned char *firmware_data = fw->fw.data; + unsigned int firmware_data_left = fw->fw.size; + + while (firmware_data_left > 0) { + addr = *(u32 *) (firmware_data); + firmware_data += 4; + firmware_data_left -= 4; + + len = *(u16 *) (firmware_data); + firmware_data += 2; + firmware_data_left -= 2; + + if (len > 32) { + printk(KERN_ERR DRV_NAME ": " + "Invalid firmware run-length of %d bytes\n", + len); + return -EINVAL; + } + + write_nic_memory(priv->net_dev, addr, len, firmware_data); + firmware_data += len; + firmware_data_left -= len; + } + + return 0; +} + +struct symbol_alive_response { + u8 cmd_id; + u8 seq_num; + u8 ucode_rev; + u8 eeprom_valid; + u16 valid_flags; + u8 IEEE_addr[6]; + u16 flags; + u16 pcb_rev; + u16 clock_settle_time; // 1us LSB + u16 powerup_settle_time; // 1us LSB + u16 hop_settle_time; // 1us LSB + u8 date[3]; // month, day, year + u8 time[2]; // hours, minutes + u8 ucode_valid; +}; + +static int ipw2100_ucode_download(struct ipw2100_priv *priv, + struct ipw2100_fw *fw) +{ + struct net_device *dev = priv->net_dev; + const unsigned char *microcode_data = fw->uc.data; + unsigned int microcode_data_left = fw->uc.size; + void __iomem *reg = (void __iomem *)dev->base_addr; + + struct symbol_alive_response response; + int i, j; + u8 data; + + /* Symbol control */ + write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); + readl(reg); + write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); + readl(reg); + + /* HW config */ + write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ + readl(reg); + write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ + readl(reg); + + /* EN_CS_ACCESS bit to reset control store pointer */ + write_nic_byte(dev, 0x210000, 0x40); + readl(reg); + write_nic_byte(dev, 0x210000, 0x0); + readl(reg); + write_nic_byte(dev, 0x210000, 0x40); + readl(reg); + + /* copy microcode from buffer into Symbol */ + + while (microcode_data_left > 0) { + write_nic_byte(dev, 0x210010, *microcode_data++); + write_nic_byte(dev, 0x210010, *microcode_data++); + microcode_data_left -= 2; + } + + /* EN_CS_ACCESS bit to reset the control store pointer */ + write_nic_byte(dev, 0x210000, 0x0); + readl(reg); + + /* Enable System (Reg 0) + * first enable causes garbage in RX FIFO */ + write_nic_byte(dev, 0x210000, 0x0); + readl(reg); + write_nic_byte(dev, 0x210000, 0x80); + readl(reg); + + /* Reset External Baseband Reg */ + write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); + readl(reg); + write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); + readl(reg); + + /* HW Config (Reg 5) */ + write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 + readl(reg); + write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 + readl(reg); + + /* Enable System (Reg 0) + * second enable should be OK */ + write_nic_byte(dev, 0x210000, 0x00); // clear enable system + readl(reg); + write_nic_byte(dev, 0x210000, 0x80); // set enable system + + /* check Symbol is enabled - upped this from 5 as it wasn't always + * catching the update */ + for (i = 0; i < 10; i++) { + udelay(10); + + /* check Dino is enabled bit */ + read_nic_byte(dev, 0x210000, &data); + if (data & 0x1) + break; + } + + if (i == 10) { + printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n", + dev->name); + return -EIO; + } + + /* Get Symbol alive response */ + for (i = 0; i < 30; i++) { + /* Read alive response structure */ + for (j = 0; + j < (sizeof(struct symbol_alive_response) >> 1); j++) + read_nic_word(dev, 0x210004, ((u16 *) & response) + j); + + if ((response.cmd_id == 1) && (response.ucode_valid == 0x1)) + break; + udelay(10); + } + + if (i == 30) { + printk(KERN_ERR DRV_NAME + ": %s: No response from Symbol - hw not alive\n", + dev->name); + printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response)); + return -EIO; + } + + return 0; +} diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h new file mode 100644 index 0000000..bbf1ddc --- /dev/null +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -0,0 +1,1162 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#ifndef _IPW2100_H +#define _IPW2100_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // new driver API + +#include + +#ifdef CONFIG_IPW2100_MONITOR +#include +#endif + +#include +#include + +struct ipw2100_priv; +struct ipw2100_tx_packet; +struct ipw2100_rx_packet; + +#define IPW_DL_UNINIT 0x80000000 +#define IPW_DL_NONE 0x00000000 +#define IPW_DL_ALL 0x7FFFFFFF + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IPW_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your + * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw2100/debug_level + * + * you simply need to add your entry to the ipw2100_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw2100 then you do not have + * CONFIG_IPW2100_DEBUG defined in your kernel configuration + * + */ + +#define IPW_DL_ERROR (1<<0) +#define IPW_DL_WARNING (1<<1) +#define IPW_DL_INFO (1<<2) +#define IPW_DL_WX (1<<3) +#define IPW_DL_HC (1<<5) +#define IPW_DL_STATE (1<<6) + +#define IPW_DL_NOTIF (1<<10) +#define IPW_DL_SCAN (1<<11) +#define IPW_DL_ASSOC (1<<12) +#define IPW_DL_DROP (1<<13) + +#define IPW_DL_IOCTL (1<<14) +#define IPW_DL_RF_KILL (1<<17) + +#define IPW_DL_MANAGE (1<<15) +#define IPW_DL_FW (1<<16) + +#define IPW_DL_FRAG (1<<21) +#define IPW_DL_WEP (1<<22) +#define IPW_DL_TX (1<<23) +#define IPW_DL_RX (1<<24) +#define IPW_DL_ISR (1<<25) +#define IPW_DL_IO (1<<26) +#define IPW_DL_TRACE (1<<28) + +#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) +#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) +#define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f) +#define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f) +#define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f) +#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f) +#define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f) +#define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f) +#define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f) +#define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f) +#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f) +#define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f) +#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f) +#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f) +#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f) +#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f) +#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f) +#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f) +#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f) +#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) +#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) + +enum { + IPW_HW_STATE_DISABLED = 1, + IPW_HW_STATE_ENABLED = 0 +}; + +struct ssid_context { + char ssid[IW_ESSID_MAX_SIZE + 1]; + int ssid_len; + unsigned char bssid[ETH_ALEN]; + int port_type; + int channel; + +}; + +extern const char *port_type_str[]; +extern const char *band_str[]; + +#define NUMBER_OF_BD_PER_COMMAND_PACKET 1 +#define NUMBER_OF_BD_PER_DATA_PACKET 2 + +#define IPW_MAX_BDS 6 +#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2 +#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1 + +#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \ + (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET) + +struct bd_status { + union { + struct { + u8 nlf:1, txType:2, intEnabled:1, reserved:4; + } fields; + u8 field; + } info; +} __attribute__ ((packed)); + +struct ipw2100_bd { + u32 host_addr; + u32 buf_length; + struct bd_status status; + /* number of fragments for frame (should be set only for + * 1st TBD) */ + u8 num_fragments; + u8 reserved[6]; +} __attribute__ ((packed)); + +#define IPW_BD_QUEUE_LENGTH(n) (1<value = (x)->hi = 0; \ + (x)->lo = 0x7fffffff; \ +} while (0) +#define SET_STAT(x,y) do { \ + (x)->value = y; \ + if ((x)->value > (x)->hi) (x)->hi = (x)->value; \ + if ((x)->value < (x)->lo) (x)->lo = (x)->value; \ +} while (0) +#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \ +while (0) +#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \ +while (0) + +#define IPW2100_ERROR_QUEUE 5 + +/* Power management code: enable or disable? */ +enum { +#ifdef CONFIG_PM + IPW2100_PM_DISABLED = 0, + PM_STATE_SIZE = 16, +#else + IPW2100_PM_DISABLED = 1, + PM_STATE_SIZE = 0, +#endif +}; + +#define STATUS_POWERED (1<<0) +#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */ +#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */ +#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */ +#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */ +#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */ +#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */ +#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */ +#define STATUS_INT_ENABLED (1<<11) +#define STATUS_RF_KILL_HW (1<<12) +#define STATUS_RF_KILL_SW (1<<13) +#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW) +#define STATUS_EXIT_PENDING (1<<14) + +#define STATUS_SCAN_PENDING (1<<23) +#define STATUS_SCANNING (1<<24) +#define STATUS_SCAN_ABORTING (1<<25) +#define STATUS_SCAN_COMPLETE (1<<26) +#define STATUS_WX_EVENT_PENDING (1<<27) +#define STATUS_RESET_PENDING (1<<29) +#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */ + +/* Internal NIC states */ +#define IPW_STATE_INITIALIZED (1<<0) +#define IPW_STATE_COUNTRY_FOUND (1<<1) +#define IPW_STATE_ASSOCIATED (1<<2) +#define IPW_STATE_ASSN_LOST (1<<3) +#define IPW_STATE_ASSN_CHANGED (1<<4) +#define IPW_STATE_SCAN_COMPLETE (1<<5) +#define IPW_STATE_ENTERED_PSP (1<<6) +#define IPW_STATE_LEFT_PSP (1<<7) +#define IPW_STATE_RF_KILL (1<<8) +#define IPW_STATE_DISABLED (1<<9) +#define IPW_STATE_POWER_DOWN (1<<10) +#define IPW_STATE_SCANNING (1<<11) + +#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ +#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ +#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ +#define CFG_CUSTOM_MAC (1<<3) +#define CFG_LONG_PREAMBLE (1<<4) +#define CFG_ASSOCIATE (1<<6) +#define CFG_FIXED_RATE (1<<7) +#define CFG_ADHOC_CREATE (1<<8) +#define CFG_PASSIVE_SCAN (1<<10) +#ifdef CONFIG_IPW2100_MONITOR +#define CFG_CRC_CHECK (1<<11) +#endif + +#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ +#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ + +struct ipw2100_priv { + + int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ + int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ + + struct ieee80211_device *ieee; + unsigned long status; + unsigned long config; + unsigned long capability; + + /* Statistics */ + int resets; + int reset_backoff; + + /* Context */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u8 bssid[ETH_ALEN]; + u8 channel; + int last_mode; + + unsigned long connect_start; + unsigned long last_reset; + + u32 channel_mask; + u32 fatal_error; + u32 fatal_errors[IPW2100_ERROR_QUEUE]; + u32 fatal_index; + int eeprom_version; + int firmware_version; + unsigned long hw_features; + int hangs; + u32 last_rtc; + int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */ + u8 *snapshot[0x30]; + + u8 mandatory_bssid_mac[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + + int power_mode; + + int messages_sent; + + int short_retry_limit; + int long_retry_limit; + + u32 rts_threshold; + u32 frag_threshold; + + int in_isr; + + u32 tx_rates; + int tx_power; + u32 beacon_interval; + + char nick[IW_ESSID_MAX_SIZE + 1]; + + struct ipw2100_status_queue status_queue; + + struct statistic txq_stat; + struct statistic rxq_stat; + struct ipw2100_bd_queue rx_queue; + struct ipw2100_bd_queue tx_queue; + struct ipw2100_rx_packet *rx_buffers; + + struct statistic fw_pend_stat; + struct list_head fw_pend_list; + + struct statistic msg_free_stat; + struct statistic msg_pend_stat; + struct list_head msg_free_list; + struct list_head msg_pend_list; + struct ipw2100_tx_packet *msg_buffers; + + struct statistic tx_free_stat; + struct statistic tx_pend_stat; + struct list_head tx_free_list; + struct list_head tx_pend_list; + struct ipw2100_tx_packet *tx_buffers; + + struct ipw2100_ordinals ordinals; + + struct pci_dev *pci_dev; + + struct proc_dir_entry *dir_dev; + + struct net_device *net_dev; + struct iw_statistics wstats; + + struct iw_public_data wireless_data; + + struct tasklet_struct irq_tasklet; + + struct workqueue_struct *workqueue; + struct delayed_work reset_work; + struct delayed_work security_work; + struct delayed_work wx_event_work; + struct delayed_work hang_check; + struct delayed_work rf_kill; + struct work_struct scan_event_now; + struct delayed_work scan_event_later; + + int user_requested_scan; + + u32 interrupts; + int tx_interrupts; + int rx_interrupts; + int inta_other; + + spinlock_t low_lock; + struct mutex action_mutex; + struct mutex adapter_mutex; + + wait_queue_head_t wait_command_queue; +}; + +/********************************************************* + * Host Command -> From Driver to FW + *********************************************************/ + +/** + * Host command identifiers + */ +#define HOST_COMPLETE 2 +#define SYSTEM_CONFIG 6 +#define SSID 8 +#define MANDATORY_BSSID 9 +#define AUTHENTICATION_TYPE 10 +#define ADAPTER_ADDRESS 11 +#define PORT_TYPE 12 +#define INTERNATIONAL_MODE 13 +#define CHANNEL 14 +#define RTS_THRESHOLD 15 +#define FRAG_THRESHOLD 16 +#define POWER_MODE 17 +#define TX_RATES 18 +#define BASIC_TX_RATES 19 +#define WEP_KEY_INFO 20 +#define WEP_KEY_INDEX 25 +#define WEP_FLAGS 26 +#define ADD_MULTICAST 27 +#define CLEAR_ALL_MULTICAST 28 +#define BEACON_INTERVAL 29 +#define ATIM_WINDOW 30 +#define CLEAR_STATISTICS 31 +#define SEND 33 +#define TX_POWER_INDEX 36 +#define BROADCAST_SCAN 43 +#define CARD_DISABLE 44 +#define PREFERRED_BSSID 45 +#define SET_SCAN_OPTIONS 46 +#define SCAN_DWELL_TIME 47 +#define SWEEP_TABLE 48 +#define AP_OR_STATION_TABLE 49 +#define GROUP_ORDINALS 50 +#define SHORT_RETRY_LIMIT 51 +#define LONG_RETRY_LIMIT 52 + +#define HOST_PRE_POWER_DOWN 58 +#define CARD_DISABLE_PHY_OFF 61 +#define MSDU_TX_RATES 62 + +/* Rogue AP Detection */ +#define SET_STATION_STAT_BITS 64 +#define CLEAR_STATIONS_STAT_BITS 65 +#define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP +#define SET_SECURITY_INFORMATION 67 +#define DISASSOCIATION_BSSID 68 +#define SET_WPA_IE 69 + +/* system configuration bit mask: */ +#define IPW_CFG_MONITOR 0x00004 +#define IPW_CFG_PREAMBLE_AUTO 0x00010 +#define IPW_CFG_IBSS_AUTO_START 0x00020 +#define IPW_CFG_LOOPBACK 0x00100 +#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800 +#define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000 +#define IPW_CFG_802_1x_ENABLE 0x04000 +#define IPW_CFG_BSS_MASK 0x08000 +#define IPW_CFG_IBSS_MASK 0x10000 + +#define IPW_SCAN_NOASSOCIATE (1<<0) +#define IPW_SCAN_MIXED_CELL (1<<1) +/* RESERVED (1<<2) */ +#define IPW_SCAN_PASSIVE (1<<3) + +#define IPW_NIC_FATAL_ERROR 0x2A7F0 +#define IPW_ERROR_ADDR(x) (x & 0x3FFFF) +#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24) +#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24) +#define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24) +#define IPW2100_ERR_FW_LOAD (0x12 << 24) + +#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200 +#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80 + +#define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40) +#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44) +#define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48) +#define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0) + +#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00) +#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04) +#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80) + +#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \ + (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20) + +#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \ + (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND) + +#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180) +#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184) + +#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB) +#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1 +#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2 +#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3 +#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4 +#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5 +#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16 +#define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24 +#define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25 +#define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30 +#define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB) + +#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001) +#define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002) +#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004) +#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008) +#define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080) +#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100) +#define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200) + +#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB) +#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1 +#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2 +#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10 +#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9 +#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10 +#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29 +#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30 +#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB) + +#define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C +#define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0 +#define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008 +#define IPW_BIT_GPIO_RF_KILL 0x00010000 + +#define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1 + +#define IPW_REG_DOMAIN_0_OFFSET 0x0000 +#define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + +#define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008 +#define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C +#define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010 +#define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014 +#define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018 +#define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C +#define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020 +#define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024 +#define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030 +#define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188 +#define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C +#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 + +#define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC + +#define IPW_INTERRUPT_MASK 0xC1010013 + +#define IPW2100_CONTROL_REG 0x220000 +#define IPW2100_CONTROL_PHY_OFF 0x8 + +#define IPW2100_COMMAND 0x00300004 +#define IPW2100_COMMAND_PHY_ON 0x0 +#define IPW2100_COMMAND_PHY_OFF 0x1 + +/* in DEBUG_AREA, values of memory always 0xd55555d5 */ +#define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090 +#define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF +#define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5 + +#define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0 + +#define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds +#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds +#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds + +// BD ring queue read/write difference +#define IPW_BD_QUEUE_W_R_MIN_SPARE 2 + +#define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80 + +#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli +#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli + +#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr) +#define IPW_MAX_80211_PAYLOAD_SIZE 2304U +#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312 +#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536 +#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60 +#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \ + (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \ + sizeof(struct ethhdr)) + +#define IPW_802_11_FCS_LENGTH 4 +#define IPW_RX_NIC_BUFFER_LENGTH \ + (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \ + IPW_802_11_FCS_LENGTH) + +#define IPW_802_11_PAYLOAD_OFFSET \ + (sizeof(struct ieee80211_hdr_3addr) + \ + sizeof(struct ieee80211_snap_hdr)) + +struct ipw2100_rx { + union { + unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; + struct ieee80211_hdr_4addr header; + u32 status; + struct ipw2100_notification notification; + struct ipw2100_cmd_header command; + } rx_data; +} __attribute__ ((packed)); + +/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */ +#define TX_RATE_1_MBIT 0x0001 +#define TX_RATE_2_MBIT 0x0002 +#define TX_RATE_5_5_MBIT 0x0004 +#define TX_RATE_11_MBIT 0x0008 +#define TX_RATE_MASK 0x000F +#define DEFAULT_TX_RATES 0x000F + +#define IPW_POWER_MODE_CAM 0x00 //(always on) +#define IPW_POWER_INDEX_1 0x01 +#define IPW_POWER_INDEX_2 0x02 +#define IPW_POWER_INDEX_3 0x03 +#define IPW_POWER_INDEX_4 0x04 +#define IPW_POWER_INDEX_5 0x05 +#define IPW_POWER_AUTO 0x06 +#define IPW_POWER_MASK 0x0F +#define IPW_POWER_ENABLED 0x10 +#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK) + +#define IPW_TX_POWER_AUTO 0 +#define IPW_TX_POWER_ENHANCED 1 + +#define IPW_TX_POWER_DEFAULT 32 +#define IPW_TX_POWER_MIN 0 +#define IPW_TX_POWER_MAX 16 +#define IPW_TX_POWER_MIN_DBM (-12) +#define IPW_TX_POWER_MAX_DBM 16 + +#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan +#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan + +#define REG_MIN_CHANNEL 0 +#define REG_MAX_CHANNEL 14 + +#define REG_CHANNEL_MASK 0x00003FFF +#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff + +#define DIVERSITY_EITHER 0 // Use both antennas +#define DIVERSITY_ANTENNA_A 1 // Use antenna A +#define DIVERSITY_ANTENNA_B 2 // Use antenna B + +#define HOST_COMMAND_WAIT 0 +#define HOST_COMMAND_NO_WAIT 1 + +#define LOCK_NONE 0 +#define LOCK_DRIVER 1 +#define LOCK_FW 2 + +#define TYPE_SWEEP_ORD 0x000D +#define TYPE_IBSS_STTN_ORD 0x000E +#define TYPE_BSS_AP_ORD 0x000F +#define TYPE_RAW_BEACON_ENTRY 0x0010 +#define TYPE_CALIBRATION_DATA 0x0011 +#define TYPE_ROGUE_AP_DATA 0x0012 +#define TYPE_ASSOCIATION_REQUEST 0x0013 +#define TYPE_REASSOCIATION_REQUEST 0x0014 + +#define HW_FEATURE_RFKILL 0x0001 +#define RF_KILLSWITCH_OFF 1 +#define RF_KILLSWITCH_ON 0 + +#define IPW_COMMAND_POOL_SIZE 40 + +#define IPW_START_ORD_TAB_1 1 +#define IPW_START_ORD_TAB_2 1000 + +#define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32) + +#define IS_ORDINAL_TABLE_ONE(mgr,id) \ + ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size)) +#define IS_ORDINAL_TABLE_TWO(mgr,id) \ + ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2))) + +#define BSS_ID_LENGTH 6 + +// Fixed size data: Ordinal Table 1 +typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW +// Transmit statistics + IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU) + IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU) + IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU) + + IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB + IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB + IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB + IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB + IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB + + IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB + IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB + IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB + IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB + + IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's + IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS + IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS + IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK + IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's + IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's + IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's + IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's + IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted + IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted + IPW_ORD_STAT_TX_BEACON, // # of tx beacon + IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM + IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX + IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx + IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX + + IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes + IPW_ORD_STAT_TX_RETRIES, // # of Tx retries + IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS + IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS + IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS + IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS + + IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures + IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time + IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed + IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup + IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted + IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed + IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames + IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent + IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks + + // Receive statistics + IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host + IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets + IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB + IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB + IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB + IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB + IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB + + IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets + IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB + IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB + IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB + IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB + + IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's + IPW_ORD_STAT_RX_POLL, //NS // # of poll rx + IPW_ORD_STAT_RX_RTS, // # of Rx RTS + IPW_ORD_STAT_RX_CTS, // # of Rx CTS + IPW_ORD_STAT_RX_ACK, // # of Rx ACK + IPW_ORD_STAT_RX_CFEND, // # of Rx CF End + IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack + IPW_ORD_STAT_RX_ASSN, // # of Association Rx's + IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's + IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's + IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's + IPW_ORD_STAT_RX_PROBE, // # of probe Rx's + IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's + IPW_ORD_STAT_RX_BEACON, // # of Rx beacon + IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM + IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx + IPW_ORD_STAT_RX_AUTH, // # of authentication Rx + IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx + + IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received + IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error + IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB + IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB + IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB + IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB + + IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB + IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB + IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB + IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB + IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets + + IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db + IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db + IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db + IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol + IPW_ORD_SYS_BOOT_TIME, // # Boot time + IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer + IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late + IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop + IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment + IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment + IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame + IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame + IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused) + IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption + +// PSP Statistics + IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended + IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout + IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts + IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt + IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received + IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received + IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID + +// Association and roaming + IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association + IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons + IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries + IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated + // AP table entry. set to 0 if not associated + IPW_ORD_AVAILABLE_AP_CNT, // # of AP's decsribed in the AP table + IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs + IPW_ORD_STAT_AP_ASSNS, // # of associations + IPW_ORD_STAT_ASSN_FAIL, // # of association failures + IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail + IPW_ORD_STAT_FULL_SCANS, // # of full scans + + IPW_ORD_CARD_DISABLED, // # Card Disabled + IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity + IPW_FILLER_40, + IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association + IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N + // hops or no prob_ responses in last 3 minutes + IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality + IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive + // load at the AP + IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below + // eligible group + IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling + IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap + IPW_FILLER_41, + IPW_FILLER_42, + IPW_FILLER_43, + IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed + IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed + IPW_ORD_STATION_TABLE_CNT, // # of entries in association table + +// Other statistics + IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI + IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word + IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word + IPW_ORD_SELF_TEST_STATUS, //NS // + IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP + IPW_ORD_POWER_MGMT_INDEX, //NS // + IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon + IPW_ORD_COUNTRY_CHANNELS, // channels suported by country +// IPW_ORD_COUNTRY_CHANNELS: +// For 11b the lower 2-byte are used for channels from 1-14 +// and the higher 2-byte are not used. + IPW_ORD_RESET_CNT, // # of adapter resets (warm) + IPW_ORD_BEACON_INTERVAL, // Beacon interval + + IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version + IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled + IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed) + IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated + IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs + IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID + + IPW_ORD_RTC_TIME = 190, // current RTC time + IPW_ORD_PORT_TYPE, // operating mode + IPW_ORD_CURRENT_TX_RATE, // current tx rate + IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates + IPW_ORD_ATIM_WINDOW, // current ATIM Window + IPW_ORD_BASIC_RATES, // bitmap of basic tx rates + IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates + IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates + IPW_ORD_CAPABILITIES, // Management frame capability field + IPW_ORD_AUTH_TYPE, // Type of authentication + IPW_ORD_RADIO_TYPE, // Adapter card platform type + IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used + IPW_ORD_INT_MODE, // International mode + IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold + IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM + IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM + IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 = + IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set + + IPW_ORD_MAC_VERSION = 209, // MAC Version + IPW_ORD_MAC_REVISION, // MAC Revision + IPW_ORD_RADIO_VERSION, // Radio Version + IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP + IPW_ORD_UCODE_VERSION, // Ucode Version + IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State +} ORDINALTABLE1; + +// ordinal table 2 +// Variable length data: +#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001 + +typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW + IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs + IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address + IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP + IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP + IPW_FILL_1, //NS // + IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code + IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String + IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans) + IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans) + IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log + IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log + IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures + IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011") + IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002") + IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP + IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes: + IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII + IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date + IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018, +} ORDINALTABLE2; // NS - means Not Supported by FW + +#define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018 + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY // enable iwspy support +#endif + +#define IPW_HOST_FW_SHARED_AREA0 0x0002f200 +#define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes + +#define IPW_HOST_FW_SHARED_AREA1 0x0002f610 +#define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes + +#define IPW_HOST_FW_SHARED_AREA2 0x0002fa00 +#define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes + +#define IPW_HOST_FW_SHARED_AREA3 0x0002fc00 +#define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes + +#define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80 +#define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes + +struct ipw2100_fw_chunk { + unsigned char *buf; + long len; + long pos; + struct list_head list; +}; + +struct ipw2100_fw_chunk_set { + const void *data; + unsigned long size; +}; + +struct ipw2100_fw { + int version; + struct ipw2100_fw_chunk_set fw; + struct ipw2100_fw_chunk_set uc; + const struct firmware *fw_entry; +}; + +#define MAX_FW_VERSION_LEN 14 + +#endif /* _IPW2100_H */ diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c new file mode 100644 index 0000000..d2a2b75 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -0,0 +1,11984 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. + + 802.11 status code portion of this file from ethereal-0.10.6: + Copyright 2000, Axis Communications AB + Ethereal - Network traffic analyzer + By Gerald Combs + Copyright 1998 Gerald Combs + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ + +#include "ipw2200.h" + + +#ifndef KBUILD_EXTMOD +#define VK "k" +#else +#define VK +#endif + +#ifdef CONFIG_IPW2200_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IPW2200_MONITOR +#define VM "m" +#else +#define VM +#endif + +#ifdef CONFIG_IPW2200_PROMISCUOUS +#define VP "p" +#else +#define VP +#endif + +#ifdef CONFIG_IPW2200_RADIOTAP +#define VR "r" +#else +#define VR +#endif + +#ifdef CONFIG_IPW2200_QOS +#define VQ "q" +#else +#define VQ +#endif + +#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ +#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" +#define DRV_VERSION IPW2200_VERSION + +#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1) + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +static int cmdlog = 0; +static int debug = 0; +static int channel = 0; +static int mode = 0; + +static u32 ipw_debug_level; +static int associate; +static int auto_create = 1; +static int led = 0; +static int disable = 0; +static int bt_coexist = 0; +static int hwcrypto = 0; +static int roaming = 1; +static const char ipw_modes[] = { + 'a', 'b', 'g', '?' +}; +static int antenna = CFG_SYS_ANTENNA_BOTH; + +#ifdef CONFIG_IPW2200_PROMISCUOUS +static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ +#endif + + +#ifdef CONFIG_IPW2200_QOS +static int qos_enable = 0; +static int qos_burst_enable = 0; +static int qos_no_ack_mask = 0; +static int burst_duration_CCK = 0; +static int burst_duration_OFDM = 0; + +static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { + {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM, + QOS_TX3_CW_MIN_OFDM}, + {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM, + QOS_TX3_CW_MAX_OFDM}, + {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, + {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, + {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM, + QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM} +}; + +static struct ieee80211_qos_parameters def_qos_parameters_CCK = { + {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK, + QOS_TX3_CW_MIN_CCK}, + {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK, + QOS_TX3_CW_MAX_CCK}, + {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, + {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, + {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK, + QOS_TX3_TXOP_LIMIT_CCK} +}; + +static struct ieee80211_qos_parameters def_parameters_OFDM = { + {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM, + DEF_TX3_CW_MIN_OFDM}, + {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM, + DEF_TX3_CW_MAX_OFDM}, + {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, + {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, + {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM, + DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM} +}; + +static struct ieee80211_qos_parameters def_parameters_CCK = { + {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK, + DEF_TX3_CW_MIN_CCK}, + {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK, + DEF_TX3_CW_MAX_CCK}, + {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, + {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, + {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK, + DEF_TX3_TXOP_LIMIT_CCK} +}; + +static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; + +static int from_priority_to_tx_queue[] = { + IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1, + IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4 +}; + +static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv); + +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters + *qos_param); +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element + *qos_param); +#endif /* CONFIG_IPW2200_QOS */ + +static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev); +static void ipw_remove_current_network(struct ipw_priv *priv); +static void ipw_rx(struct ipw_priv *priv); +static int ipw_queue_tx_reclaim(struct ipw_priv *priv, + struct clx2_tx_queue *txq, int qindex); +static int ipw_queue_reset(struct ipw_priv *priv); + +static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, + int len, int sync); + +static void ipw_tx_queue_free(struct ipw_priv *); + +static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); +static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); +static void ipw_rx_queue_replenish(void *); +static int ipw_up(struct ipw_priv *); +static void ipw_bg_up(struct work_struct *work); +static void ipw_down(struct ipw_priv *); +static void ipw_bg_down(struct work_struct *work); +static int ipw_config(struct ipw_priv *); +static int init_supported_rates(struct ipw_priv *priv, + struct ipw_supported_rates *prates); +static void ipw_set_hwcrypto_keys(struct ipw_priv *); +static void ipw_send_wep_keys(struct ipw_priv *, int); + +static int snprint_line(char *buf, size_t count, + const u8 * data, u32 len, u32 ofs) +{ + int out, i, j, l; + char c; + + out = snprintf(buf, count, "%08X", ofs); + + for (l = 0, i = 0; i < 2; i++) { + out += snprintf(buf + out, count - out, " "); + for (j = 0; j < 8 && l < len; j++, l++) + out += snprintf(buf + out, count - out, "%02X ", + data[(i * 8 + j)]); + for (; j < 8; j++) + out += snprintf(buf + out, count - out, " "); + } + + out += snprintf(buf + out, count - out, " "); + for (l = 0, i = 0; i < 2; i++) { + out += snprintf(buf + out, count - out, " "); + for (j = 0; j < 8 && l < len; j++, l++) { + c = data[(i * 8 + j)]; + if (!isascii(c) || !isprint(c)) + c = '.'; + + out += snprintf(buf + out, count - out, "%c", c); + } + + for (; j < 8; j++) + out += snprintf(buf + out, count - out, " "); + } + + return out; +} + +static void printk_buf(int level, const u8 * data, u32 len) +{ + char line[81]; + u32 ofs = 0; + if (!(ipw_debug_level & level)) + return; + + while (len) { + snprint_line(line, sizeof(line), &data[ofs], + min(len, 16U), ofs); + printk(KERN_DEBUG "%s\n", line); + ofs += 16; + len -= min(len, 16U); + } +} + +static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len) +{ + size_t out = size; + u32 ofs = 0; + int total = 0; + + while (size && len) { + out = snprint_line(output, size, &data[ofs], + min_t(size_t, len, 16U), ofs); + + ofs += 16; + output += out; + size -= out; + len -= min_t(size_t, len, 16U); + total += out; + } + return total; +} + +/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ +static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); +#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) + +/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ +static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg); +#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b) + +/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ +static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value); +static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) +{ + IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__, + __LINE__, (u32) (b), (u32) (c)); + _ipw_write_reg8(a, b, c); +} + +/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ +static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value); +static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) +{ + IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__, + __LINE__, (u32) (b), (u32) (c)); + _ipw_write_reg16(a, b, c); +} + +/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ +static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value); +static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) +{ + IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__, + __LINE__, (u32) (b), (u32) (c)); + _ipw_write_reg32(a, b, c); +} + +/* 8-bit direct write (low 4K) */ +#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) + +/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ +#define ipw_write8(ipw, ofs, val) do { \ + IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ + _ipw_write8(ipw, ofs, val); \ + } while (0) + +/* 16-bit direct write (low 4K) */ +#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) + +/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ +#define ipw_write16(ipw, ofs, val) \ + IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ + _ipw_write16(ipw, ofs, val) + +/* 32-bit direct write (low 4K) */ +#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) + +/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ +#define ipw_write32(ipw, ofs, val) \ + IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ + _ipw_write32(ipw, ofs, val) + +/* 8-bit direct read (low 4K) */ +#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) + +/* 8-bit direct read (low 4K), with debug wrapper */ +static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) +{ + IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs)); + return _ipw_read8(ipw, ofs); +} + +/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ +#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) + +/* 16-bit direct read (low 4K) */ +#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) + +/* 16-bit direct read (low 4K), with debug wrapper */ +static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) +{ + IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs)); + return _ipw_read16(ipw, ofs); +} + +/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ +#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) + +/* 32-bit direct read (low 4K) */ +#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) + +/* 32-bit direct read (low 4K), with debug wrapper */ +static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) +{ + IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs)); + return _ipw_read32(ipw, ofs); +} + +/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ +#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) + +/* multi-byte read (above 4K), with debug wrapper */ +static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); +static inline void __ipw_read_indirect(const char *f, int l, + struct ipw_priv *a, u32 b, u8 * c, int d) +{ + IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b), + d); + _ipw_read_indirect(a, b, c, d); +} + +/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ +#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d) + +/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ +static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, + int num); +#define ipw_write_indirect(a, b, c, d) \ + IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ + _ipw_write_indirect(a, b, c, d) + +/* 32-bit indirect write (above 4K) */ +static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) +{ + IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); + _ipw_write32(priv, IPW_INDIRECT_DATA, value); +} + +/* 8-bit indirect write (above 4K) */ +static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) +{ + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = reg - aligned_addr; + + IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value); +} + +/* 16-bit indirect write (above 4K) */ +static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) +{ + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = (reg - aligned_addr) & (~0x1ul); + + IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value); +} + +/* 8-bit indirect read (above 4K) */ +static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) +{ + u32 word; + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); + IPW_DEBUG_IO(" reg = 0x%8X : \n", reg); + word = _ipw_read32(priv, IPW_INDIRECT_DATA); + return (word >> ((reg & 0x3) * 8)) & 0xff; +} + +/* 32-bit indirect read (above 4K) */ +static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) +{ + u32 value; + + IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg); + + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); + value = _ipw_read32(priv, IPW_INDIRECT_DATA); + IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value); + return value; +} + +/* General purpose, no alignment requirement, iterative (multi-byte) read, */ +/* for area above 1st 4K of SRAM/reg space */ +static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, + int num) +{ + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = addr - aligned_addr; + u32 i; + + IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); + + if (num <= 0) { + return; + } + + /* Read the first dword (or portion) byte by byte */ + if (unlikely(dif_len)) { + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + /* Start reading at aligned_addr + dif_len */ + for (i = dif_len; ((i < 4) && (num > 0)); i++, num--) + *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i); + aligned_addr += 4; + } + + /* Read all of the middle dwords as dwords, with auto-increment */ + _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); + for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) + *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA); + + /* Read the last dword (or portion) byte by byte */ + if (unlikely(num)) { + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + for (i = 0; num > 0; i++, num--) + *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i); + } +} + +/* General purpose, no alignment requirement, iterative (multi-byte) write, */ +/* for area above 1st 4K of SRAM/reg space */ +static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, + int num) +{ + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = addr - aligned_addr; + u32 i; + + IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); + + if (num <= 0) { + return; + } + + /* Write the first dword (or portion) byte by byte */ + if (unlikely(dif_len)) { + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + /* Start writing at aligned_addr + dif_len */ + for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) + _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); + aligned_addr += 4; + } + + /* Write all of the middle dwords as dwords, with auto-increment */ + _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); + for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) + _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf); + + /* Write the last dword (or portion) byte by byte */ + if (unlikely(num)) { + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + for (i = 0; num > 0; i++, num--, buf++) + _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); + } +} + +/* General purpose, no alignment requirement, iterative (multi-byte) write, */ +/* for 1st 4K of SRAM/regs space */ +static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, + int num) +{ + memcpy_toio((priv->hw_base + addr), buf, num); +} + +/* Set bit(s) in low 4K of SRAM/regs */ +static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask) +{ + ipw_write32(priv, reg, ipw_read32(priv, reg) | mask); +} + +/* Clear bit(s) in low 4K of SRAM/regs */ +static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) +{ + ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); +} + +static inline void __ipw_enable_interrupts(struct ipw_priv *priv) +{ + if (priv->status & STATUS_INT_ENABLED) + return; + priv->status |= STATUS_INT_ENABLED; + ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); +} + +static inline void __ipw_disable_interrupts(struct ipw_priv *priv) +{ + if (!(priv->status & STATUS_INT_ENABLED)) + return; + priv->status &= ~STATUS_INT_ENABLED; + ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); +} + +static inline void ipw_enable_interrupts(struct ipw_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + __ipw_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void ipw_disable_interrupts(struct ipw_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + __ipw_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static char *ipw_error_desc(u32 val) +{ + switch (val) { + case IPW_FW_ERROR_OK: + return "ERROR_OK"; + case IPW_FW_ERROR_FAIL: + return "ERROR_FAIL"; + case IPW_FW_ERROR_MEMORY_UNDERFLOW: + return "MEMORY_UNDERFLOW"; + case IPW_FW_ERROR_MEMORY_OVERFLOW: + return "MEMORY_OVERFLOW"; + case IPW_FW_ERROR_BAD_PARAM: + return "BAD_PARAM"; + case IPW_FW_ERROR_BAD_CHECKSUM: + return "BAD_CHECKSUM"; + case IPW_FW_ERROR_NMI_INTERRUPT: + return "NMI_INTERRUPT"; + case IPW_FW_ERROR_BAD_DATABASE: + return "BAD_DATABASE"; + case IPW_FW_ERROR_ALLOC_FAIL: + return "ALLOC_FAIL"; + case IPW_FW_ERROR_DMA_UNDERRUN: + return "DMA_UNDERRUN"; + case IPW_FW_ERROR_DMA_STATUS: + return "DMA_STATUS"; + case IPW_FW_ERROR_DINO_ERROR: + return "DINO_ERROR"; + case IPW_FW_ERROR_EEPROM_ERROR: + return "EEPROM_ERROR"; + case IPW_FW_ERROR_SYSASSERT: + return "SYSASSERT"; + case IPW_FW_ERROR_FATAL_ERROR: + return "FATAL_ERROR"; + default: + return "UNKNOWN_ERROR"; + } +} + +static void ipw_dump_error_log(struct ipw_priv *priv, + struct ipw_fw_error *error) +{ + u32 i; + + if (!error) { + IPW_ERROR("Error allocating and capturing error log. " + "Nothing to dump.\n"); + return; + } + + IPW_ERROR("Start IPW Error Log Dump:\n"); + IPW_ERROR("Status: 0x%08X, Config: %08X\n", + error->status, error->config); + + for (i = 0; i < error->elem_len; i++) + IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + ipw_error_desc(error->elem[i].desc), + error->elem[i].time, + error->elem[i].blink1, + error->elem[i].blink2, + error->elem[i].link1, + error->elem[i].link2, error->elem[i].data); + for (i = 0; i < error->log_len; i++) + IPW_ERROR("%i\t0x%08x\t%i\n", + error->log[i].time, + error->log[i].data, error->log[i].event); +} + +static inline int ipw_is_init(struct ipw_priv *priv) +{ + return (priv->status & STATUS_INIT) ? 1 : 0; +} + +static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len) +{ + u32 addr, field_info, field_len, field_count, total_len; + + IPW_DEBUG_ORD("ordinal = %i\n", ord); + + if (!priv || !val || !len) { + IPW_DEBUG_ORD("Invalid argument\n"); + return -EINVAL; + } + + /* verify device ordinal tables have been initialized */ + if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) { + IPW_DEBUG_ORD("Access ordinals before initialization\n"); + return -EINVAL; + } + + switch (IPW_ORD_TABLE_ID_MASK & ord) { + case IPW_ORD_TABLE_0_MASK: + /* + * TABLE 0: Direct access to a table of 32 bit values + * + * This is a very simple table with the data directly + * read from the table + */ + + /* remove the table id from the ordinal */ + ord &= IPW_ORD_TABLE_VALUE_MASK; + + /* boundary check */ + if (ord > priv->table0_len) { + IPW_DEBUG_ORD("ordinal value (%i) longer then " + "max (%i)\n", ord, priv->table0_len); + return -EINVAL; + } + + /* verify we have enough room to store the value */ + if (*len < sizeof(u32)) { + IPW_DEBUG_ORD("ordinal buffer length too small, " + "need %zd\n", sizeof(u32)); + return -EINVAL; + } + + IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n", + ord, priv->table0_addr + (ord << 2)); + + *len = sizeof(u32); + ord <<= 2; + *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord); + break; + + case IPW_ORD_TABLE_1_MASK: + /* + * TABLE 1: Indirect access to a table of 32 bit values + * + * This is a fairly large table of u32 values each + * representing starting addr for the data (which is + * also a u32) + */ + + /* remove the table id from the ordinal */ + ord &= IPW_ORD_TABLE_VALUE_MASK; + + /* boundary check */ + if (ord > priv->table1_len) { + IPW_DEBUG_ORD("ordinal value too long\n"); + return -EINVAL; + } + + /* verify we have enough room to store the value */ + if (*len < sizeof(u32)) { + IPW_DEBUG_ORD("ordinal buffer length too small, " + "need %zd\n", sizeof(u32)); + return -EINVAL; + } + + *((u32 *) val) = + ipw_read_reg32(priv, (priv->table1_addr + (ord << 2))); + *len = sizeof(u32); + break; + + case IPW_ORD_TABLE_2_MASK: + /* + * TABLE 2: Indirect access to a table of variable sized values + * + * This table consist of six values, each containing + * - dword containing the starting offset of the data + * - dword containing the lengh in the first 16bits + * and the count in the second 16bits + */ + + /* remove the table id from the ordinal */ + ord &= IPW_ORD_TABLE_VALUE_MASK; + + /* boundary check */ + if (ord > priv->table2_len) { + IPW_DEBUG_ORD("ordinal value too long\n"); + return -EINVAL; + } + + /* get the address of statistic */ + addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3)); + + /* get the second DW of statistics ; + * two 16-bit words - first is length, second is count */ + field_info = + ipw_read_reg32(priv, + priv->table2_addr + (ord << 3) + + sizeof(u32)); + + /* get each entry length */ + field_len = *((u16 *) & field_info); + + /* get number of entries */ + field_count = *(((u16 *) & field_info) + 1); + + /* abort if not enought memory */ + total_len = field_len * field_count; + if (total_len > *len) { + *len = total_len; + return -EINVAL; + } + + *len = total_len; + if (!total_len) + return 0; + + IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, " + "field_info = 0x%08x\n", + addr, total_len, field_info); + ipw_read_indirect(priv, addr, val, total_len); + break; + + default: + IPW_DEBUG_ORD("Invalid ordinal!\n"); + return -EINVAL; + + } + + return 0; +} + +static void ipw_init_ordinals(struct ipw_priv *priv) +{ + priv->table0_addr = IPW_ORDINALS_TABLE_LOWER; + priv->table0_len = ipw_read32(priv, priv->table0_addr); + + IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n", + priv->table0_addr, priv->table0_len); + + priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1); + priv->table1_len = ipw_read_reg32(priv, priv->table1_addr); + + IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n", + priv->table1_addr, priv->table1_len); + + priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2); + priv->table2_len = ipw_read_reg32(priv, priv->table2_addr); + priv->table2_len &= 0x0000ffff; /* use first two bytes */ + + IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n", + priv->table2_addr, priv->table2_len); + +} + +static u32 ipw_register_toggle(u32 reg) +{ + reg &= ~IPW_START_STANDBY; + if (reg & IPW_GATE_ODMA) + reg &= ~IPW_GATE_ODMA; + if (reg & IPW_GATE_IDMA) + reg &= ~IPW_GATE_IDMA; + if (reg & IPW_GATE_ADMA) + reg &= ~IPW_GATE_ADMA; + return reg; +} + +/* + * LED behavior: + * - On radio ON, turn on any LEDs that require to be on during start + * - On initialization, start unassociated blink + * - On association, disable unassociated blink + * - On disassociation, start unassociated blink + * - On radio OFF, turn off any LEDs started during radio on + * + */ +#define LD_TIME_LINK_ON msecs_to_jiffies(300) +#define LD_TIME_LINK_OFF msecs_to_jiffies(2700) +#define LD_TIME_ACT_ON msecs_to_jiffies(250) + +static void ipw_led_link_on(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* If configured to not use LEDs, or nic_type is 1, + * then we don't toggle a LINK led */ + if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (!(priv->status & STATUS_RF_KILL_MASK) && + !(priv->status & STATUS_LED_LINK_ON)) { + IPW_DEBUG_LED("Link LED On\n"); + led = ipw_read_reg32(priv, IPW_EVENT_REG); + led |= priv->led_association_on; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); + + priv->status |= STATUS_LED_LINK_ON; + + /* If we aren't associated, schedule turning the LED off */ + if (!(priv->status & STATUS_ASSOCIATED)) + queue_delayed_work(priv->workqueue, + &priv->led_link_off, + LD_TIME_LINK_ON); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipw_bg_led_link_on(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_on.work); + mutex_lock(&priv->mutex); + ipw_led_link_on(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_led_link_off(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* If configured not to use LEDs, or nic type is 1, + * then we don't goggle the LINK led. */ + if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->status & STATUS_LED_LINK_ON) { + led = ipw_read_reg32(priv, IPW_EVENT_REG); + led &= priv->led_association_off; + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); + + IPW_DEBUG_LED("Link LED Off\n"); + + priv->status &= ~STATUS_LED_LINK_ON; + + /* If we aren't associated and the radio is on, schedule + * turning the LED on (blink while unassociated) */ + if (!(priv->status & STATUS_RF_KILL_MASK) && + !(priv->status & STATUS_ASSOCIATED)) + queue_delayed_work(priv->workqueue, &priv->led_link_on, + LD_TIME_LINK_OFF); + + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipw_bg_led_link_off(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_off.work); + mutex_lock(&priv->mutex); + ipw_led_link_off(priv); + mutex_unlock(&priv->mutex); +} + +static void __ipw_led_activity_on(struct ipw_priv *priv) +{ + u32 led; + + if (priv->config & CFG_NO_LED) + return; + + if (priv->status & STATUS_RF_KILL_MASK) + return; + + if (!(priv->status & STATUS_LED_ACT_ON)) { + led = ipw_read_reg32(priv, IPW_EVENT_REG); + led |= priv->led_activity_on; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); + + IPW_DEBUG_LED("Activity LED On\n"); + + priv->status |= STATUS_LED_ACT_ON; + + cancel_delayed_work(&priv->led_act_off); + queue_delayed_work(priv->workqueue, &priv->led_act_off, + LD_TIME_ACT_ON); + } else { + /* Reschedule LED off for full time period */ + cancel_delayed_work(&priv->led_act_off); + queue_delayed_work(priv->workqueue, &priv->led_act_off, + LD_TIME_ACT_ON); + } +} + +#if 0 +void ipw_led_activity_on(struct ipw_priv *priv) +{ + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); + __ipw_led_activity_on(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} +#endif /* 0 */ + +static void ipw_led_activity_off(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + if (priv->config & CFG_NO_LED) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->status & STATUS_LED_ACT_ON) { + led = ipw_read_reg32(priv, IPW_EVENT_REG); + led &= priv->led_activity_off; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); + + IPW_DEBUG_LED("Activity LED Off\n"); + + priv->status &= ~STATUS_LED_ACT_ON; + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipw_bg_led_activity_off(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_act_off.work); + mutex_lock(&priv->mutex); + ipw_led_activity_off(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_led_band_on(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* Only nic type 1 supports mode LEDs */ + if (priv->config & CFG_NO_LED || + priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network) + return; + + spin_lock_irqsave(&priv->lock, flags); + + led = ipw_read_reg32(priv, IPW_EVENT_REG); + if (priv->assoc_network->mode == IEEE_A) { + led |= priv->led_ofdm_on; + led &= priv->led_association_off; + IPW_DEBUG_LED("Mode LED On: 802.11a\n"); + } else if (priv->assoc_network->mode == IEEE_G) { + led |= priv->led_ofdm_on; + led |= priv->led_association_on; + IPW_DEBUG_LED("Mode LED On: 802.11g\n"); + } else { + led &= priv->led_ofdm_off; + led |= priv->led_association_on; + IPW_DEBUG_LED("Mode LED On: 802.11b\n"); + } + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipw_led_band_off(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* Only nic type 1 supports mode LEDs */ + if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + led = ipw_read_reg32(priv, IPW_EVENT_REG); + led &= priv->led_ofdm_off; + led &= priv->led_association_off; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipw_led_radio_on(struct ipw_priv *priv) +{ + ipw_led_link_on(priv); +} + +static void ipw_led_radio_off(struct ipw_priv *priv) +{ + ipw_led_activity_off(priv); + ipw_led_link_off(priv); +} + +static void ipw_led_link_up(struct ipw_priv *priv) +{ + /* Set the Link Led on for all nic types */ + ipw_led_link_on(priv); +} + +static void ipw_led_link_down(struct ipw_priv *priv) +{ + ipw_led_activity_off(priv); + ipw_led_link_off(priv); + + if (priv->status & STATUS_RF_KILL_MASK) + ipw_led_radio_off(priv); +} + +static void ipw_led_init(struct ipw_priv *priv) +{ + priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; + + /* Set the default PINs for the link and activity leds */ + priv->led_activity_on = IPW_ACTIVITY_LED; + priv->led_activity_off = ~(IPW_ACTIVITY_LED); + + priv->led_association_on = IPW_ASSOCIATED_LED; + priv->led_association_off = ~(IPW_ASSOCIATED_LED); + + /* Set the default PINs for the OFDM leds */ + priv->led_ofdm_on = IPW_OFDM_LED; + priv->led_ofdm_off = ~(IPW_OFDM_LED); + + switch (priv->nic_type) { + case EEPROM_NIC_TYPE_1: + /* In this NIC type, the LEDs are reversed.... */ + priv->led_activity_on = IPW_ASSOCIATED_LED; + priv->led_activity_off = ~(IPW_ASSOCIATED_LED); + priv->led_association_on = IPW_ACTIVITY_LED; + priv->led_association_off = ~(IPW_ACTIVITY_LED); + + if (!(priv->config & CFG_NO_LED)) + ipw_led_band_on(priv); + + /* And we don't blink link LEDs for this nic, so + * just return here */ + return; + + case EEPROM_NIC_TYPE_3: + case EEPROM_NIC_TYPE_2: + case EEPROM_NIC_TYPE_4: + case EEPROM_NIC_TYPE_0: + break; + + default: + IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n", + priv->nic_type); + priv->nic_type = EEPROM_NIC_TYPE_0; + break; + } + + if (!(priv->config & CFG_NO_LED)) { + if (priv->status & STATUS_ASSOCIATED) + ipw_led_link_on(priv); + else + ipw_led_link_off(priv); + } +} + +static void ipw_led_shutdown(struct ipw_priv *priv) +{ + ipw_led_activity_off(priv); + ipw_led_link_off(priv); + ipw_led_band_off(priv); + cancel_delayed_work(&priv->led_link_on); + cancel_delayed_work(&priv->led_link_off); + cancel_delayed_work(&priv->led_act_off); +} + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) + * used for controling the debug level. + * + * See the level definitions in ipw for details. + */ +static ssize_t show_debug_level(struct device_driver *d, char *buf) +{ + return sprintf(buf, "0x%08X\n", ipw_debug_level); +} + +static ssize_t store_debug_level(struct device_driver *d, const char *buf, + size_t count) +{ + char *p = (char *)buf; + u32 val; + + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + ipw_debug_level = val; + + return strnlen(buf, count); +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + +static inline u32 ipw_get_event_log_len(struct ipw_priv *priv) +{ + /* length = 1st dword in log */ + return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG)); +} + +static void ipw_capture_event_log(struct ipw_priv *priv, + u32 log_len, struct ipw_event *log) +{ + u32 base; + + if (log_len) { + base = ipw_read32(priv, IPW_EVENT_LOG); + ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32), + (u8 *) log, sizeof(*log) * log_len); + } +} + +static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv) +{ + struct ipw_fw_error *error; + u32 log_len = ipw_get_event_log_len(priv); + u32 base = ipw_read32(priv, IPW_ERROR_LOG); + u32 elem_len = ipw_read_reg32(priv, base); + + error = kmalloc(sizeof(*error) + + sizeof(*error->elem) * elem_len + + sizeof(*error->log) * log_len, GFP_ATOMIC); + if (!error) { + IPW_ERROR("Memory allocation for firmware error log " + "failed.\n"); + return NULL; + } + error->jiffies = jiffies; + error->status = priv->status; + error->config = priv->config; + error->elem_len = elem_len; + error->log_len = log_len; + error->elem = (struct ipw_error_elem *)error->payload; + error->log = (struct ipw_event *)(error->elem + elem_len); + + ipw_capture_event_log(priv, log_len, error->log); + + if (elem_len) + ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem, + sizeof(*error->elem) * elem_len); + + return error; +} + +static ssize_t show_event_log(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + u32 log_len = ipw_get_event_log_len(priv); + u32 log_size; + struct ipw_event *log; + u32 len = 0, i; + + /* not using min() because of its strict type checking */ + log_size = PAGE_SIZE / sizeof(*log) > log_len ? + sizeof(*log) * log_len : PAGE_SIZE; + log = kzalloc(log_size, GFP_KERNEL); + if (!log) { + IPW_ERROR("Unable to allocate memory for log\n"); + return 0; + } + log_len = log_size / sizeof(*log); + ipw_capture_event_log(priv, log_len, log); + + len += snprintf(buf + len, PAGE_SIZE - len, "%08X", log_len); + for (i = 0; i < log_len; i++) + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X%08X%08X", + log[i].time, log[i].event, log[i].data); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + kfree(log); + return len; +} + +static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL); + +static ssize_t show_error(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + u32 len = 0, i; + if (!priv->error) + return 0; + len += snprintf(buf + len, PAGE_SIZE - len, + "%08lX%08X%08X%08X", + priv->error->jiffies, + priv->error->status, + priv->error->config, priv->error->elem_len); + for (i = 0; i < priv->error->elem_len; i++) + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X%08X%08X%08X%08X%08X%08X", + priv->error->elem[i].time, + priv->error->elem[i].desc, + priv->error->elem[i].blink1, + priv->error->elem[i].blink2, + priv->error->elem[i].link1, + priv->error->elem[i].link2, + priv->error->elem[i].data); + + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X", priv->error->log_len); + for (i = 0; i < priv->error->log_len; i++) + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X%08X%08X", + priv->error->log[i].time, + priv->error->log[i].event, + priv->error->log[i].data); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} + +static ssize_t clear_error(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + + kfree(priv->error); + priv->error = NULL; + return count; +} + +static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error); + +static ssize_t show_cmd_log(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + u32 len = 0, i; + if (!priv->cmdlog) + return 0; + for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len; + (i != priv->cmdlog_pos) && (PAGE_SIZE - len); + i = (i + 1) % priv->cmdlog_len) { + len += + snprintf(buf + len, PAGE_SIZE - len, + "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies, + priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd, + priv->cmdlog[i].cmd.len); + len += + snprintk_buf(buf + len, PAGE_SIZE - len, + (u8 *) priv->cmdlog[i].cmd.param, + priv->cmdlog[i].cmd.len); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} + +static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); + +#ifdef CONFIG_IPW2200_PROMISCUOUS +static void ipw_prom_free(struct ipw_priv *priv); +static int ipw_prom_alloc(struct ipw_priv *priv); +static ssize_t store_rtap_iface(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + int rc = 0; + + if (count < 1) + return -EINVAL; + + switch (buf[0]) { + case '0': + if (!rtap_iface) + return count; + + if (netif_running(priv->prom_net_dev)) { + IPW_WARNING("Interface is up. Cannot unregister.\n"); + return count; + } + + ipw_prom_free(priv); + rtap_iface = 0; + break; + + case '1': + if (rtap_iface) + return count; + + rc = ipw_prom_alloc(priv); + if (!rc) + rtap_iface = 1; + break; + + default: + return -EINVAL; + } + + if (rc) { + IPW_ERROR("Failed to register promiscuous network " + "device (error %d).\n", rc); + } + + return count; +} + +static ssize_t show_rtap_iface(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + if (rtap_iface) + return sprintf(buf, "%s", priv->prom_net_dev->name); + else { + buf[0] = '-'; + buf[1] = '1'; + buf[2] = '\0'; + return 3; + } +} + +static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface, + store_rtap_iface); + +static ssize_t store_rtap_filter(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + + if (!priv->prom_priv) { + IPW_ERROR("Attempting to set filter without " + "rtap_iface enabled.\n"); + return -EPERM; + } + + priv->prom_priv->filter = simple_strtol(buf, NULL, 0); + + IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n", + BIT_ARG16(priv->prom_priv->filter)); + + return count; +} + +static ssize_t show_rtap_filter(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%04X", + priv->prom_priv ? priv->prom_priv->filter : 0); +} + +static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter, + store_rtap_filter); +#endif + +static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d\n", priv->ieee->scan_age); +} + +static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + char buffer[] = "00000000"; + unsigned long len = + (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; + unsigned long val; + char *p = buffer; + + IPW_DEBUG_INFO("enter\n"); + + strncpy(buffer, buf, len); + buffer[len] = 0; + + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buffer) { + IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); + } else { + priv->ieee->scan_age = val; + IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); + } + + IPW_DEBUG_INFO("exit\n"); + return len; +} + +static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); + +static ssize_t show_led(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1); +} + +static ssize_t store_led(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + + IPW_DEBUG_INFO("enter\n"); + + if (count == 0) + return 0; + + if (*buf == 0) { + IPW_DEBUG_LED("Disabling LED control.\n"); + priv->config |= CFG_NO_LED; + ipw_led_shutdown(priv); + } else { + IPW_DEBUG_LED("Enabling LED control.\n"); + priv->config &= ~CFG_NO_LED; + ipw_led_init(priv); + } + + IPW_DEBUG_INFO("exit\n"); + return count; +} + +static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); + +static ssize_t show_status(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *p = d->driver_data; + return sprintf(buf, "0x%08x\n", (int)p->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +static ssize_t show_cfg(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *p = d->driver_data; + return sprintf(buf, "0x%08x\n", (int)p->config); +} + +static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); + +static ssize_t show_nic_type(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = d->driver_data; + return sprintf(buf, "TYPE: %d\n", priv->nic_type); +} + +static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); + +static ssize_t show_ucode_version(struct device *d, + struct device_attribute *attr, char *buf) +{ + u32 len = sizeof(u32), tmp = 0; + struct ipw_priv *p = d->driver_data; + + if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len)) + return 0; + + return sprintf(buf, "0x%08x\n", tmp); +} + +static DEVICE_ATTR(ucode_version, S_IWUSR | S_IRUGO, show_ucode_version, NULL); + +static ssize_t show_rtc(struct device *d, struct device_attribute *attr, + char *buf) +{ + u32 len = sizeof(u32), tmp = 0; + struct ipw_priv *p = d->driver_data; + + if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len)) + return 0; + + return sprintf(buf, "0x%08x\n", tmp); +} + +static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL); + +/* + * Add a device attribute to view/control the delay between eeprom + * operations. + */ +static ssize_t show_eeprom_delay(struct device *d, + struct device_attribute *attr, char *buf) +{ + int n = ((struct ipw_priv *)d->driver_data)->eeprom_delay; + return sprintf(buf, "%i\n", n); +} +static ssize_t store_eeprom_delay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *p = d->driver_data; + sscanf(buf, "%i", &p->eeprom_delay); + return strnlen(buf, count); +} + +static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO, + show_eeprom_delay, store_eeprom_delay); + +static ssize_t show_command_event_reg(struct device *d, + struct device_attribute *attr, char *buf) +{ + u32 reg = 0; + struct ipw_priv *p = d->driver_data; + + reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT); + return sprintf(buf, "0x%08x\n", reg); +} +static ssize_t store_command_event_reg(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 reg; + struct ipw_priv *p = d->driver_data; + + sscanf(buf, "%x", ®); + ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg); + return strnlen(buf, count); +} + +static DEVICE_ATTR(command_event_reg, S_IWUSR | S_IRUGO, + show_command_event_reg, store_command_event_reg); + +static ssize_t show_mem_gpio_reg(struct device *d, + struct device_attribute *attr, char *buf) +{ + u32 reg = 0; + struct ipw_priv *p = d->driver_data; + + reg = ipw_read_reg32(p, 0x301100); + return sprintf(buf, "0x%08x\n", reg); +} +static ssize_t store_mem_gpio_reg(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 reg; + struct ipw_priv *p = d->driver_data; + + sscanf(buf, "%x", ®); + ipw_write_reg32(p, 0x301100, reg); + return strnlen(buf, count); +} + +static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO, + show_mem_gpio_reg, store_mem_gpio_reg); + +static ssize_t show_indirect_dword(struct device *d, + struct device_attribute *attr, char *buf) +{ + u32 reg = 0; + struct ipw_priv *priv = d->driver_data; + + if (priv->status & STATUS_INDIRECT_DWORD) + reg = ipw_read_reg32(priv, priv->indirect_dword); + else + reg = 0; + + return sprintf(buf, "0x%08x\n", reg); +} +static ssize_t store_indirect_dword(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = d->driver_data; + + sscanf(buf, "%x", &priv->indirect_dword); + priv->status |= STATUS_INDIRECT_DWORD; + return strnlen(buf, count); +} + +static DEVICE_ATTR(indirect_dword, S_IWUSR | S_IRUGO, + show_indirect_dword, store_indirect_dword); + +static ssize_t show_indirect_byte(struct device *d, + struct device_attribute *attr, char *buf) +{ + u8 reg = 0; + struct ipw_priv *priv = d->driver_data; + + if (priv->status & STATUS_INDIRECT_BYTE) + reg = ipw_read_reg8(priv, priv->indirect_byte); + else + reg = 0; + + return sprintf(buf, "0x%02x\n", reg); +} +static ssize_t store_indirect_byte(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = d->driver_data; + + sscanf(buf, "%x", &priv->indirect_byte); + priv->status |= STATUS_INDIRECT_BYTE; + return strnlen(buf, count); +} + +static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO, + show_indirect_byte, store_indirect_byte); + +static ssize_t show_direct_dword(struct device *d, + struct device_attribute *attr, char *buf) +{ + u32 reg = 0; + struct ipw_priv *priv = d->driver_data; + + if (priv->status & STATUS_DIRECT_DWORD) + reg = ipw_read32(priv, priv->direct_dword); + else + reg = 0; + + return sprintf(buf, "0x%08x\n", reg); +} +static ssize_t store_direct_dword(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = d->driver_data; + + sscanf(buf, "%x", &priv->direct_dword); + priv->status |= STATUS_DIRECT_DWORD; + return strnlen(buf, count); +} + +static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO, + show_direct_dword, store_direct_dword); + +static int rf_kill_active(struct ipw_priv *priv) +{ + if (0 == (ipw_read32(priv, 0x30) & 0x10000)) + priv->status |= STATUS_RF_KILL_HW; + else + priv->status &= ~STATUS_RF_KILL_HW; + + return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0; +} + +static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, + char *buf) +{ + /* 0 - RF kill not enabled + 1 - SW based RF kill active (sysfs) + 2 - HW based RF kill active + 3 - Both HW and SW baed RF kill active */ + struct ipw_priv *priv = d->driver_data; + int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | + (rf_kill_active(priv) ? 0x2 : 0x0); + return sprintf(buf, "%i\n", val); +} + +static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) +{ + if ((disable_radio ? 1 : 0) == + ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0)) + return 0; + + IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", + disable_radio ? "OFF" : "ON"); + + if (disable_radio) { + priv->status |= STATUS_RF_KILL_SW; + + if (priv->workqueue) { + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); + cancel_delayed_work(&priv->scan_event); + } + queue_work(priv->workqueue, &priv->down); + } else { + priv->status &= ~STATUS_RF_KILL_SW; + if (rf_kill_active(priv)) { + IPW_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + /* Make sure the RF_KILL check timer is running */ + cancel_delayed_work(&priv->rf_kill); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + round_jiffies_relative(2 * HZ)); + } else + queue_work(priv->workqueue, &priv->up); + } + + return 1; +} + +static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = d->driver_data; + + ipw_radio_kill_sw(priv, buf[0] == '1'); + + return count; +} + +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); + +static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + int pos = 0, len = 0; + if (priv->config & CFG_SPEED_SCAN) { + while (priv->speed_scan[pos] != 0) + len += sprintf(&buf[len], "%d ", + priv->speed_scan[pos++]); + return len + sprintf(&buf[len], "\n"); + } + + return sprintf(buf, "0\n"); +} + +static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + int channel, pos = 0; + const char *p = buf; + + /* list of space separated channels to scan, optionally ending with 0 */ + while ((channel = simple_strtol(p, NULL, 0))) { + if (pos == MAX_SPEED_SCAN - 1) { + priv->speed_scan[pos] = 0; + break; + } + + if (ieee80211_is_valid_channel(priv->ieee, channel)) + priv->speed_scan[pos++] = channel; + else + IPW_WARNING("Skipping invalid channel request: %d\n", + channel); + p = strchr(p, ' '); + if (!p) + break; + while (*p == ' ' || *p == '\t') + p++; + } + + if (pos == 0) + priv->config &= ~CFG_SPEED_SCAN; + else { + priv->speed_scan_pos = 0; + priv->config |= CFG_SPEED_SCAN; + } + + return count; +} + +static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, + store_speed_scan); + +static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0'); +} + +static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + if (buf[0] == '1') + priv->config |= CFG_NET_STATS; + else + priv->config &= ~CFG_NET_STATS; + + return count; +} + +static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, + show_net_stats, store_net_stats); + +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + int len = 0, i; + + len = sprintf(&buf[len], + "Displaying %d channels in 2.4Ghz band " + "(802.11bg):\n", geo->bg_channels); + + for (i = 0; i < geo->bg_channels; i++) { + len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", + geo->bg[i].channel, + geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? + " (radar spectrum)" : "", + ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || + (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) + ? "" : ", IBSS", + geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + "passive only" : "active/passive", + geo->bg[i].flags & IEEE80211_CH_B_ONLY ? + "B" : "B/G"); + } + + len += sprintf(&buf[len], + "Displaying %d channels in 5.2Ghz band " + "(802.11a):\n", geo->a_channels); + for (i = 0; i < geo->a_channels; i++) { + len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", + geo->a[i].channel, + geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? + " (radar spectrum)" : "", + ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || + (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) + ? "" : ", IBSS", + geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + "passive only" : "active/passive"); + } + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + +static void notify_wx_assoc_event(struct ipw_priv *priv) +{ + union iwreq_data wrqu; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (priv->status & STATUS_ASSOCIATED) + memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); + else + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); +} + +static void ipw_irq_tasklet(struct ipw_priv *priv) +{ + u32 inta, inta_mask, handled = 0; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&priv->irq_lock, flags); + + inta = ipw_read32(priv, IPW_INTA_RW); + inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); + inta &= (IPW_INTA_MASK_ALL & inta_mask); + + /* Add any cached INTA values that need to be handled */ + inta |= priv->isr_inta; + + spin_unlock_irqrestore(&priv->irq_lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + + /* handle all the justifications for the interrupt */ + if (inta & IPW_INTA_BIT_RX_TRANSFER) { + ipw_rx(priv); + handled |= IPW_INTA_BIT_RX_TRANSFER; + } + + if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) { + IPW_DEBUG_HC("Command completed.\n"); + rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1); + priv->status &= ~STATUS_HCMD_ACTIVE; + wake_up_interruptible(&priv->wait_command_queue); + handled |= IPW_INTA_BIT_TX_CMD_QUEUE; + } + + if (inta & IPW_INTA_BIT_TX_QUEUE_1) { + IPW_DEBUG_TX("TX_QUEUE_1\n"); + rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0); + handled |= IPW_INTA_BIT_TX_QUEUE_1; + } + + if (inta & IPW_INTA_BIT_TX_QUEUE_2) { + IPW_DEBUG_TX("TX_QUEUE_2\n"); + rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1); + handled |= IPW_INTA_BIT_TX_QUEUE_2; + } + + if (inta & IPW_INTA_BIT_TX_QUEUE_3) { + IPW_DEBUG_TX("TX_QUEUE_3\n"); + rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2); + handled |= IPW_INTA_BIT_TX_QUEUE_3; + } + + if (inta & IPW_INTA_BIT_TX_QUEUE_4) { + IPW_DEBUG_TX("TX_QUEUE_4\n"); + rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3); + handled |= IPW_INTA_BIT_TX_QUEUE_4; + } + + if (inta & IPW_INTA_BIT_STATUS_CHANGE) { + IPW_WARNING("STATUS_CHANGE\n"); + handled |= IPW_INTA_BIT_STATUS_CHANGE; + } + + if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) { + IPW_WARNING("TX_PERIOD_EXPIRED\n"); + handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED; + } + + if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) { + IPW_WARNING("HOST_CMD_DONE\n"); + handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE; + } + + if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) { + IPW_WARNING("FW_INITIALIZATION_DONE\n"); + handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE; + } + + if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) { + IPW_WARNING("PHY_OFF_DONE\n"); + handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE; + } + + if (inta & IPW_INTA_BIT_RF_KILL_DONE) { + IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); + priv->status |= STATUS_RF_KILL_HW; + wake_up_interruptible(&priv->wait_command_queue); + priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); + cancel_delayed_work(&priv->scan_event); + schedule_work(&priv->link_down); + queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); + handled |= IPW_INTA_BIT_RF_KILL_DONE; + } + + if (inta & IPW_INTA_BIT_FATAL_ERROR) { + IPW_WARNING("Firmware error detected. Restarting.\n"); + if (priv->error) { + IPW_DEBUG_FW("Sysfs 'error' log already exists.\n"); + if (ipw_debug_level & IPW_DL_FW_ERRORS) { + struct ipw_fw_error *error = + ipw_alloc_error_log(priv); + ipw_dump_error_log(priv, error); + kfree(error); + } + } else { + priv->error = ipw_alloc_error_log(priv); + if (priv->error) + IPW_DEBUG_FW("Sysfs 'error' log captured.\n"); + else + IPW_DEBUG_FW("Error allocating sysfs 'error' " + "log.\n"); + if (ipw_debug_level & IPW_DL_FW_ERRORS) + ipw_dump_error_log(priv, priv->error); + } + + /* XXX: If hardware encryption is for WPA/WPA2, + * we have to notify the supplicant. */ + if (priv->ieee->sec.encrypt) { + priv->status &= ~STATUS_ASSOCIATED; + notify_wx_assoc_event(priv); + } + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + priv->status &= ~STATUS_INIT; + + /* Cancel currently queued command. */ + priv->status &= ~STATUS_HCMD_ACTIVE; + wake_up_interruptible(&priv->wait_command_queue); + + queue_work(priv->workqueue, &priv->adapter_restart); + handled |= IPW_INTA_BIT_FATAL_ERROR; + } + + if (inta & IPW_INTA_BIT_PARITY_ERROR) { + IPW_ERROR("Parity error\n"); + handled |= IPW_INTA_BIT_PARITY_ERROR; + } + + if (handled != inta) { + IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* enable all interrupts */ + ipw_enable_interrupts(priv); +} + +#define IPW_CMD(x) case IPW_CMD_ ## x : return #x +static char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IPW_CMD(HOST_COMPLETE); + IPW_CMD(POWER_DOWN); + IPW_CMD(SYSTEM_CONFIG); + IPW_CMD(MULTICAST_ADDRESS); + IPW_CMD(SSID); + IPW_CMD(ADAPTER_ADDRESS); + IPW_CMD(PORT_TYPE); + IPW_CMD(RTS_THRESHOLD); + IPW_CMD(FRAG_THRESHOLD); + IPW_CMD(POWER_MODE); + IPW_CMD(WEP_KEY); + IPW_CMD(TGI_TX_KEY); + IPW_CMD(SCAN_REQUEST); + IPW_CMD(SCAN_REQUEST_EXT); + IPW_CMD(ASSOCIATE); + IPW_CMD(SUPPORTED_RATES); + IPW_CMD(SCAN_ABORT); + IPW_CMD(TX_FLUSH); + IPW_CMD(QOS_PARAMETERS); + IPW_CMD(DINO_CONFIG); + IPW_CMD(RSN_CAPABILITIES); + IPW_CMD(RX_KEY); + IPW_CMD(CARD_DISABLE); + IPW_CMD(SEED_NUMBER); + IPW_CMD(TX_POWER); + IPW_CMD(COUNTRY_INFO); + IPW_CMD(AIRONET_INFO); + IPW_CMD(AP_TX_POWER); + IPW_CMD(CCKM_INFO); + IPW_CMD(CCX_VER_INFO); + IPW_CMD(SET_CALIBRATION); + IPW_CMD(SENSITIVITY_CALIB); + IPW_CMD(RETRY_LIMIT); + IPW_CMD(IPW_PRE_POWER_DOWN); + IPW_CMD(VAP_BEACON_TEMPLATE); + IPW_CMD(VAP_DTIM_PERIOD); + IPW_CMD(EXT_SUPPORTED_RATES); + IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT); + IPW_CMD(VAP_QUIET_INTERVALS); + IPW_CMD(VAP_CHANNEL_SWITCH); + IPW_CMD(VAP_MANDATORY_CHANNELS); + IPW_CMD(VAP_CELL_PWR_LIMIT); + IPW_CMD(VAP_CF_PARAM_SET); + IPW_CMD(VAP_SET_BEACONING_STATE); + IPW_CMD(MEASUREMENT); + IPW_CMD(POWER_CAPABILITY); + IPW_CMD(SUPPORTED_CHANNELS); + IPW_CMD(TPC_REPORT); + IPW_CMD(WME_INFO); + IPW_CMD(PRODUCTION_COMMAND); + default: + return "UNKNOWN"; + } +} + +#define HOST_COMPLETE_TIMEOUT HZ + +static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) +{ + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->status & STATUS_HCMD_ACTIVE) { + IPW_ERROR("Failed to send %s: Already sending a command.\n", + get_cmd_string(cmd->cmd)); + spin_unlock_irqrestore(&priv->lock, flags); + return -EAGAIN; + } + + priv->status |= STATUS_HCMD_ACTIVE; + + if (priv->cmdlog) { + priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies; + priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd; + priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len; + memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param, + cmd->len); + priv->cmdlog[priv->cmdlog_pos].retcode = -1; + } + + IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", + get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, + priv->status); + +#ifndef DEBUG_CMD_WEP_KEY + if (cmd->cmd == IPW_CMD_WEP_KEY) + IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n"); + else +#endif + printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); + + rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0); + if (rc) { + priv->status &= ~STATUS_HCMD_ACTIVE; + IPW_ERROR("Failed to send %s: Reason %d\n", + get_cmd_string(cmd->cmd), rc); + spin_unlock_irqrestore(&priv->lock, flags); + goto exit; + } + spin_unlock_irqrestore(&priv->lock, flags); + + rc = wait_event_interruptible_timeout(priv->wait_command_queue, + !(priv-> + status & STATUS_HCMD_ACTIVE), + HOST_COMPLETE_TIMEOUT); + if (rc == 0) { + spin_lock_irqsave(&priv->lock, flags); + if (priv->status & STATUS_HCMD_ACTIVE) { + IPW_ERROR("Failed to send %s: Command timed out.\n", + get_cmd_string(cmd->cmd)); + priv->status &= ~STATUS_HCMD_ACTIVE; + spin_unlock_irqrestore(&priv->lock, flags); + rc = -EIO; + goto exit; + } + spin_unlock_irqrestore(&priv->lock, flags); + } else + rc = 0; + + if (priv->status & STATUS_RF_KILL_HW) { + IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", + get_cmd_string(cmd->cmd)); + rc = -EIO; + goto exit; + } + + exit: + if (priv->cmdlog) { + priv->cmdlog[priv->cmdlog_pos++].retcode = rc; + priv->cmdlog_pos %= priv->cmdlog_len; + } + return rc; +} + +static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command) +{ + struct host_cmd cmd = { + .cmd = command, + }; + + return __ipw_send_cmd(priv, &cmd); +} + +static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len, + void *data) +{ + struct host_cmd cmd = { + .cmd = command, + .len = len, + .param = data, + }; + + return __ipw_send_cmd(priv, &cmd); +} + +static int ipw_send_host_complete(struct ipw_priv *priv) +{ + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE); +} + +static int ipw_send_system_config(struct ipw_priv *priv) +{ + return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, + sizeof(priv->sys_config), + &priv->sys_config); +} + +static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) +{ + if (!priv || !ssid) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE), + ssid); +} + +static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) +{ + if (!priv || !mac) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + IPW_DEBUG_INFO("%s: Setting MAC to %pM\n", + priv->net_dev->name, mac); + + return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); +} + +/* + * NOTE: This must be executed from our workqueue as it results in udelay + * being called which may corrupt the keyboard if executed on default + * workqueue + */ +static void ipw_adapter_restart(void *adapter) +{ + struct ipw_priv *priv = adapter; + + if (priv->status & STATUS_RF_KILL_MASK) + return; + + ipw_down(priv); + + if (priv->assoc_network && + (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS)) + ipw_remove_current_network(priv); + + if (ipw_up(priv)) { + IPW_ERROR("Failed to up device\n"); + return; + } +} + +static void ipw_bg_adapter_restart(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adapter_restart); + mutex_lock(&priv->mutex); + ipw_adapter_restart(priv); + mutex_unlock(&priv->mutex); +} + +#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) + +static void ipw_scan_check(void *data) +{ + struct ipw_priv *priv = data; + if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { + IPW_DEBUG_SCAN("Scan completion watchdog resetting " + "adapter after (%dms).\n", + jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG)); + queue_work(priv->workqueue, &priv->adapter_restart); + } +} + +static void ipw_bg_scan_check(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_check.work); + mutex_lock(&priv->mutex); + ipw_scan_check(priv); + mutex_unlock(&priv->mutex); +} + +static int ipw_send_scan_request_ext(struct ipw_priv *priv, + struct ipw_scan_request_ext *request) +{ + return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT, + sizeof(*request), request); +} + +static int ipw_send_scan_abort(struct ipw_priv *priv) +{ + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT); +} + +static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) +{ + struct ipw_sensitivity_calib calib = { + .beacon_rssi_raw = cpu_to_le16(sens), + }; + + return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib), + &calib); +} + +static int ipw_send_associate(struct ipw_priv *priv, + struct ipw_associate *associate) +{ + if (!priv || !associate) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate), + associate); +} + +static int ipw_send_supported_rates(struct ipw_priv *priv, + struct ipw_supported_rates *rates) +{ + if (!priv || !rates) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates), + rates); +} + +static int ipw_set_random_seed(struct ipw_priv *priv) +{ + u32 val; + + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + get_random_bytes(&val, sizeof(val)); + + return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val); +} + +static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) +{ + __le32 v = cpu_to_le32(phy_off); + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v); +} + +static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) +{ + if (!priv || !power) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power); +} + +static int ipw_set_tx_power(struct ipw_priv *priv) +{ + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + struct ipw_tx_power tx_power; + s8 max_power; + int i; + + memset(&tx_power, 0, sizeof(tx_power)); + + /* configure device for 'G' band */ + tx_power.ieee_mode = IPW_G_MODE; + tx_power.num_channels = geo->bg_channels; + for (i = 0; i < geo->bg_channels; i++) { + max_power = geo->bg[i].max_power; + tx_power.channels_tx_power[i].channel_number = + geo->bg[i].channel; + tx_power.channels_tx_power[i].tx_power = max_power ? + min(max_power, priv->tx_power) : priv->tx_power; + } + if (ipw_send_tx_power(priv, &tx_power)) + return -EIO; + + /* configure device to also handle 'B' band */ + tx_power.ieee_mode = IPW_B_MODE; + if (ipw_send_tx_power(priv, &tx_power)) + return -EIO; + + /* configure device to also handle 'A' band */ + if (priv->ieee->abg_true) { + tx_power.ieee_mode = IPW_A_MODE; + tx_power.num_channels = geo->a_channels; + for (i = 0; i < tx_power.num_channels; i++) { + max_power = geo->a[i].max_power; + tx_power.channels_tx_power[i].channel_number = + geo->a[i].channel; + tx_power.channels_tx_power[i].tx_power = max_power ? + min(max_power, priv->tx_power) : priv->tx_power; + } + if (ipw_send_tx_power(priv, &tx_power)) + return -EIO; + } + return 0; +} + +static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) +{ + struct ipw_rts_threshold rts_threshold = { + .rts_threshold = cpu_to_le16(rts), + }; + + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD, + sizeof(rts_threshold), &rts_threshold); +} + +static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) +{ + struct ipw_frag_threshold frag_threshold = { + .frag_threshold = cpu_to_le16(frag), + }; + + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD, + sizeof(frag_threshold), &frag_threshold); +} + +static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) +{ + __le32 param; + + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + /* If on battery, set to 3, if AC set to CAM, else user + * level */ + switch (mode) { + case IPW_POWER_BATTERY: + param = cpu_to_le32(IPW_POWER_INDEX_3); + break; + case IPW_POWER_AC: + param = cpu_to_le32(IPW_POWER_MODE_CAM); + break; + default: + param = cpu_to_le32(mode); + break; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), + ¶m); +} + +static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) +{ + struct ipw_retry_limit retry_limit = { + .short_retry_limit = slimit, + .long_retry_limit = llimit + }; + + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit), + &retry_limit); +} + +/* + * The IPW device contains a Microwire compatible EEPROM that stores + * various data like the MAC address. Usually the firmware has exclusive + * access to the eeprom, but during device initialization (before the + * device driver has sent the HostComplete command to the firmware) the + * device driver has read access to the EEPROM by way of indirect addressing + * through a couple of memory mapped registers. + * + * The following is a simplified implementation for pulling data out of the + * the eeprom, along with some helper functions to find information in + * the per device private data's copy of the eeprom. + * + * NOTE: To better understand how these functions work (i.e what is a chip + * select and why do have to keep driving the eeprom clock?), read + * just about any data sheet for a Microwire compatible EEPROM. + */ + +/* write a 32 bit value into the indirect accessor register */ +static inline void eeprom_write_reg(struct ipw_priv *p, u32 data) +{ + ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data); + + /* the eeprom requires some time to complete the operation */ + udelay(p->eeprom_delay); + + return; +} + +/* perform a chip select operation */ +static void eeprom_cs(struct ipw_priv *priv) +{ + eeprom_write_reg(priv, 0); + eeprom_write_reg(priv, EEPROM_BIT_CS); + eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK); + eeprom_write_reg(priv, EEPROM_BIT_CS); +} + +/* perform a chip select operation */ +static void eeprom_disable_cs(struct ipw_priv *priv) +{ + eeprom_write_reg(priv, EEPROM_BIT_CS); + eeprom_write_reg(priv, 0); + eeprom_write_reg(priv, EEPROM_BIT_SK); +} + +/* push a single bit down to the eeprom */ +static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit) +{ + int d = (bit ? EEPROM_BIT_DI : 0); + eeprom_write_reg(p, EEPROM_BIT_CS | d); + eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK); +} + +/* push an opcode followed by an address down to the eeprom */ +static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr) +{ + int i; + + eeprom_cs(priv); + eeprom_write_bit(priv, 1); + eeprom_write_bit(priv, op & 2); + eeprom_write_bit(priv, op & 1); + for (i = 7; i >= 0; i--) { + eeprom_write_bit(priv, addr & (1 << i)); + } +} + +/* pull 16 bits off the eeprom, one bit at a time */ +static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr) +{ + int i; + u16 r = 0; + + /* Send READ Opcode */ + eeprom_op(priv, EEPROM_CMD_READ, addr); + + /* Send dummy bit */ + eeprom_write_reg(priv, EEPROM_BIT_CS); + + /* Read the byte off the eeprom one bit at a time */ + for (i = 0; i < 16; i++) { + u32 data = 0; + eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK); + eeprom_write_reg(priv, EEPROM_BIT_CS); + data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS); + r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0); + } + + /* Send another dummy bit */ + eeprom_write_reg(priv, 0); + eeprom_disable_cs(priv); + + return r; +} + +/* helper function for pulling the mac address out of the private */ +/* data's copy of the eeprom data */ +static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) +{ + memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6); +} + +/* + * Either the device driver (i.e. the host) or the firmware can + * load eeprom data into the designated region in SRAM. If neither + * happens then the FW will shutdown with a fatal error. + * + * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE + * bit needs region of shared SRAM needs to be non-zero. + */ +static void ipw_eeprom_init_sram(struct ipw_priv *priv) +{ + int i; + __le16 *eeprom = (__le16 *) priv->eeprom; + + IPW_DEBUG_TRACE(">>\n"); + + /* read entire contents of eeprom into private buffer */ + for (i = 0; i < 128; i++) + eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i)); + + /* + If the data looks correct, then copy it to our private + copy. Otherwise let the firmware know to perform the operation + on its own. + */ + if (priv->eeprom[EEPROM_VERSION] != 0) { + IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n"); + + /* write the eeprom data to sram */ + for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) + ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]); + + /* Do not load eeprom data on fatal error or suspend */ + ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); + } else { + IPW_DEBUG_INFO("Enabling FW initializationg of SRAM\n"); + + /* Load eeprom data on fatal error or suspend */ + ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1); + } + + IPW_DEBUG_TRACE("<<\n"); +} + +static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count) +{ + count >>= 2; + if (!count) + return; + _ipw_write32(priv, IPW_AUTOINC_ADDR, start); + while (count--) + _ipw_write32(priv, IPW_AUTOINC_DATA, 0); +} + +static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv) +{ + ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL, + CB_NUMBER_OF_ELEMENTS_SMALL * + sizeof(struct command_block)); +} + +static int ipw_fw_dma_enable(struct ipw_priv *priv) +{ /* start dma engine but no transfers yet */ + + IPW_DEBUG_FW(">> : \n"); + + /* Start the dma */ + ipw_fw_dma_reset_command_blocks(priv); + + /* Write CB base address */ + ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL); + + IPW_DEBUG_FW("<< : \n"); + return 0; +} + +static void ipw_fw_dma_abort(struct ipw_priv *priv) +{ + u32 control = 0; + + IPW_DEBUG_FW(">> :\n"); + + /* set the Stop and Abort bit */ + control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; + ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); + priv->sram_desc.last_cb_index = 0; + + IPW_DEBUG_FW("<< \n"); +} + +static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index, + struct command_block *cb) +{ + u32 address = + IPW_SHARED_SRAM_DMA_CONTROL + + (sizeof(struct command_block) * index); + IPW_DEBUG_FW(">> :\n"); + + ipw_write_indirect(priv, address, (u8 *) cb, + (int)sizeof(struct command_block)); + + IPW_DEBUG_FW("<< :\n"); + return 0; + +} + +static int ipw_fw_dma_kick(struct ipw_priv *priv) +{ + u32 control = 0; + u32 index = 0; + + IPW_DEBUG_FW(">> :\n"); + + for (index = 0; index < priv->sram_desc.last_cb_index; index++) + ipw_fw_dma_write_command_block(priv, index, + &priv->sram_desc.cb_list[index]); + + /* Enable the DMA in the CSR register */ + ipw_clear_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED | + IPW_RESET_REG_STOP_MASTER); + + /* Set the Start bit. */ + control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START; + ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); + + IPW_DEBUG_FW("<< :\n"); + return 0; +} + +static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv) +{ + u32 address; + u32 register_value = 0; + u32 cb_fields_address = 0; + + IPW_DEBUG_FW(">> :\n"); + address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB); + IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address); + + /* Read the DMA Controlor register */ + register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL); + IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value); + + /* Print the CB values */ + cb_fields_address = address; + register_value = ipw_read_reg32(priv, cb_fields_address); + IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n", register_value); + + cb_fields_address += sizeof(u32); + register_value = ipw_read_reg32(priv, cb_fields_address); + IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n", register_value); + + cb_fields_address += sizeof(u32); + register_value = ipw_read_reg32(priv, cb_fields_address); + IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n", + register_value); + + cb_fields_address += sizeof(u32); + register_value = ipw_read_reg32(priv, cb_fields_address); + IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n", register_value); + + IPW_DEBUG_FW(">> :\n"); +} + +static int ipw_fw_dma_command_block_index(struct ipw_priv *priv) +{ + u32 current_cb_address = 0; + u32 current_cb_index = 0; + + IPW_DEBUG_FW("<< :\n"); + current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB); + + current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) / + sizeof(struct command_block); + + IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n", + current_cb_index, current_cb_address); + + IPW_DEBUG_FW(">> :\n"); + return current_cb_index; + +} + +static int ipw_fw_dma_add_command_block(struct ipw_priv *priv, + u32 src_address, + u32 dest_address, + u32 length, + int interrupt_enabled, int is_last) +{ + + u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC | + CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG | + CB_DEST_SIZE_LONG; + struct command_block *cb; + u32 last_cb_element = 0; + + IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n", + src_address, dest_address, length); + + if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL) + return -1; + + last_cb_element = priv->sram_desc.last_cb_index; + cb = &priv->sram_desc.cb_list[last_cb_element]; + priv->sram_desc.last_cb_index++; + + /* Calculate the new CB control word */ + if (interrupt_enabled) + control |= CB_INT_ENABLED; + + if (is_last) + control |= CB_LAST_VALID; + + control |= length; + + /* Calculate the CB Element's checksum value */ + cb->status = control ^ src_address ^ dest_address; + + /* Copy the Source and Destination addresses */ + cb->dest_addr = dest_address; + cb->source_addr = src_address; + + /* Copy the Control Word last */ + cb->control = control; + + return 0; +} + +static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, + u32 src_phys, u32 dest_address, u32 length) +{ + u32 bytes_left = length; + u32 src_offset = 0; + u32 dest_offset = 0; + int status = 0; + IPW_DEBUG_FW(">> \n"); + IPW_DEBUG_FW_INFO("src_phys=0x%x dest_address=0x%x length=0x%x\n", + src_phys, dest_address, length); + while (bytes_left > CB_MAX_LENGTH) { + status = ipw_fw_dma_add_command_block(priv, + src_phys + src_offset, + dest_address + + dest_offset, + CB_MAX_LENGTH, 0, 0); + if (status) { + IPW_DEBUG_FW_INFO(": Failed\n"); + return -1; + } else + IPW_DEBUG_FW_INFO(": Added new cb\n"); + + src_offset += CB_MAX_LENGTH; + dest_offset += CB_MAX_LENGTH; + bytes_left -= CB_MAX_LENGTH; + } + + /* add the buffer tail */ + if (bytes_left > 0) { + status = + ipw_fw_dma_add_command_block(priv, src_phys + src_offset, + dest_address + dest_offset, + bytes_left, 0, 0); + if (status) { + IPW_DEBUG_FW_INFO(": Failed on the buffer tail\n"); + return -1; + } else + IPW_DEBUG_FW_INFO + (": Adding new cb - the buffer tail\n"); + } + + IPW_DEBUG_FW("<< \n"); + return 0; +} + +static int ipw_fw_dma_wait(struct ipw_priv *priv) +{ + u32 current_index = 0, previous_index; + u32 watchdog = 0; + + IPW_DEBUG_FW(">> : \n"); + + current_index = ipw_fw_dma_command_block_index(priv); + IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n", + (int)priv->sram_desc.last_cb_index); + + while (current_index < priv->sram_desc.last_cb_index) { + udelay(50); + previous_index = current_index; + current_index = ipw_fw_dma_command_block_index(priv); + + if (previous_index < current_index) { + watchdog = 0; + continue; + } + if (++watchdog > 400) { + IPW_DEBUG_FW_INFO("Timeout\n"); + ipw_fw_dma_dump_command_block(priv); + ipw_fw_dma_abort(priv); + return -1; + } + } + + ipw_fw_dma_abort(priv); + + /*Disable the DMA in the CSR register */ + ipw_set_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER); + + IPW_DEBUG_FW("<< dmaWaitSync \n"); + return 0; +} + +static void ipw_remove_current_network(struct ipw_priv *priv) +{ + struct list_head *element, *safe; + struct ieee80211_network *network = NULL; + unsigned long flags; + + spin_lock_irqsave(&priv->ieee->lock, flags); + list_for_each_safe(element, safe, &priv->ieee->network_list) { + network = list_entry(element, struct ieee80211_network, list); + if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + list_del(element); + list_add_tail(&network->list, + &priv->ieee->network_free_list); + } + } + spin_unlock_irqrestore(&priv->ieee->lock, flags); +} + +/** + * Check that card is still alive. + * Reads debug register from domain0. + * If card is present, pre-defined value should + * be found there. + * + * @param priv + * @return 1 if card is present, 0 otherwise + */ +static inline int ipw_alive(struct ipw_priv *priv) +{ + return ipw_read32(priv, 0x90) == 0xd55555d5; +} + +/* timeout in msec, attempted in 10-msec quanta */ +static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask, + int timeout) +{ + int i = 0; + + do { + if ((ipw_read32(priv, addr) & mask) == mask) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIME; +} + +/* These functions load the firmware and micro code for the operation of + * the ipw hardware. It assumes the buffer has all the bits for the + * image and the caller is handling the memory allocation and clean up. + */ + +static int ipw_stop_master(struct ipw_priv *priv) +{ + int rc; + + IPW_DEBUG_TRACE(">> \n"); + /* stop master. typical delay - 0 */ + ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); + + /* timeout is in msec, polled in 10-msec quanta */ + rc = ipw_poll_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED, 100); + if (rc < 0) { + IPW_ERROR("wait for stop master failed after 100ms\n"); + return -1; + } + + IPW_DEBUG_INFO("stop master %dms\n", rc); + + return rc; +} + +static void ipw_arc_release(struct ipw_priv *priv) +{ + IPW_DEBUG_TRACE(">> \n"); + mdelay(5); + + ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); + + /* no one knows timing, for safety add some delay */ + mdelay(5); +} + +struct fw_chunk { + __le32 address; + __le32 length; +}; + +static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) +{ + int rc = 0, i, addr; + u8 cr = 0; + __le16 *image; + + image = (__le16 *) data; + + IPW_DEBUG_TRACE(">> \n"); + + rc = ipw_stop_master(priv); + + if (rc < 0) + return rc; + + for (addr = IPW_SHARED_LOWER_BOUND; + addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { + ipw_write32(priv, addr, 0); + } + + /* no ucode (yet) */ + memset(&priv->dino_alive, 0, sizeof(priv->dino_alive)); + /* destroy DMA queues */ + /* reset sequence */ + + ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON); + ipw_arc_release(priv); + ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF); + mdelay(1); + + /* reset PHY */ + ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN); + mdelay(1); + + ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0); + mdelay(1); + + /* enable ucode store */ + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS); + mdelay(1); + + /* write ucode */ + /** + * @bug + * Do NOT set indirect address register once and then + * store data to indirect data register in the loop. + * It seems very reasonable, but in this case DINO do not + * accept ucode. It is essential to set address each time. + */ + /* load new ipw uCode */ + for (i = 0; i < len / 2; i++) + ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE, + le16_to_cpu(image[i])); + + /* enable DINO */ + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM); + + /* this is where the igx / win driver deveates from the VAP driver. */ + + /* wait for alive response */ + for (i = 0; i < 100; i++) { + /* poll for incoming data */ + cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS); + if (cr & DINO_RXFIFO_DATA) + break; + mdelay(1); + } + + if (cr & DINO_RXFIFO_DATA) { + /* alive_command_responce size is NOT multiple of 4 */ + __le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4]; + + for (i = 0; i < ARRAY_SIZE(response_buffer); i++) + response_buffer[i] = + cpu_to_le32(ipw_read_reg32(priv, + IPW_BASEBAND_RX_FIFO_READ)); + memcpy(&priv->dino_alive, response_buffer, + sizeof(priv->dino_alive)); + if (priv->dino_alive.alive_command == 1 + && priv->dino_alive.ucode_valid == 1) { + rc = 0; + IPW_DEBUG_INFO + ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) " + "of %02d/%02d/%02d %02d:%02d\n", + priv->dino_alive.software_revision, + priv->dino_alive.software_revision, + priv->dino_alive.device_identifier, + priv->dino_alive.device_identifier, + priv->dino_alive.time_stamp[0], + priv->dino_alive.time_stamp[1], + priv->dino_alive.time_stamp[2], + priv->dino_alive.time_stamp[3], + priv->dino_alive.time_stamp[4]); + } else { + IPW_DEBUG_INFO("Microcode is not alive\n"); + rc = -EINVAL; + } + } else { + IPW_DEBUG_INFO("No alive response from DINO\n"); + rc = -ETIME; + } + + /* disable DINO, otherwise for some reason + firmware have problem getting alive resp. */ + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); + + return rc; +} + +static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) +{ + int rc = -1; + int offset = 0; + struct fw_chunk *chunk; + dma_addr_t shared_phys; + u8 *shared_virt; + + IPW_DEBUG_TRACE("<< : \n"); + shared_virt = pci_alloc_consistent(priv->pci_dev, len, &shared_phys); + + if (!shared_virt) + return -ENOMEM; + + memmove(shared_virt, data, len); + + /* Start the Dma */ + rc = ipw_fw_dma_enable(priv); + + if (priv->sram_desc.last_cb_index > 0) { + /* the DMA is already ready this would be a bug. */ + BUG(); + goto out; + } + + do { + chunk = (struct fw_chunk *)(data + offset); + offset += sizeof(struct fw_chunk); + /* build DMA packet and queue up for sending */ + /* dma to chunk->address, the chunk->length bytes from data + + * offeset*/ + /* Dma loading */ + rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, + le32_to_cpu(chunk->address), + le32_to_cpu(chunk->length)); + if (rc) { + IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); + goto out; + } + + offset += le32_to_cpu(chunk->length); + } while (offset < len); + + /* Run the DMA and wait for the answer */ + rc = ipw_fw_dma_kick(priv); + if (rc) { + IPW_ERROR("dmaKick Failed\n"); + goto out; + } + + rc = ipw_fw_dma_wait(priv); + if (rc) { + IPW_ERROR("dmaWaitSync Failed\n"); + goto out; + } + out: + pci_free_consistent(priv->pci_dev, len, shared_virt, shared_phys); + return rc; +} + +/* stop nic */ +static int ipw_stop_nic(struct ipw_priv *priv) +{ + int rc = 0; + + /* stop */ + ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); + + rc = ipw_poll_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED, 500); + if (rc < 0) { + IPW_ERROR("wait for reg master disabled failed after 500ms\n"); + return rc; + } + + ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); + + return rc; +} + +static void ipw_start_nic(struct ipw_priv *priv) +{ + IPW_DEBUG_TRACE(">>\n"); + + /* prvHwStartNic release ARC */ + ipw_clear_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED | + IPW_RESET_REG_STOP_MASTER | + CBD_RESET_REG_PRINCETON_RESET); + + /* enable power management */ + ipw_set_bit(priv, IPW_GP_CNTRL_RW, + IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); + + IPW_DEBUG_TRACE("<<\n"); +} + +static int ipw_init_nic(struct ipw_priv *priv) +{ + int rc; + + IPW_DEBUG_TRACE(">>\n"); + /* reset */ + /*prvHwInitNic */ + /* set "initialization complete" bit to move adapter to D0 state */ + ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE); + + /* low-level PLL activation */ + ipw_write32(priv, IPW_READ_INT_REGISTER, + IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER); + + /* wait for clock stabilization */ + rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW, + IPW_GP_CNTRL_BIT_CLOCK_READY, 250); + if (rc < 0) + IPW_DEBUG_INFO("FAILED wait for clock stablization\n"); + + /* assert SW reset */ + ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET); + + udelay(10); + + /* set "initialization complete" bit to move adapter to D0 state */ + ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE); + + IPW_DEBUG_TRACE(">>\n"); + return 0; +} + +/* Call this function from process context, it will sleep in request_firmware. + * Probe is an ok place to call this from. + */ +static int ipw_reset_nic(struct ipw_priv *priv) +{ + int rc = 0; + unsigned long flags; + + IPW_DEBUG_TRACE(">>\n"); + + rc = ipw_init_nic(priv); + + spin_lock_irqsave(&priv->lock, flags); + /* Clear the 'host command active' bit... */ + priv->status &= ~STATUS_HCMD_ACTIVE; + wake_up_interruptible(&priv->wait_command_queue); + priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); + wake_up_interruptible(&priv->wait_state); + spin_unlock_irqrestore(&priv->lock, flags); + + IPW_DEBUG_TRACE("<<\n"); + return rc; +} + + +struct ipw_fw { + __le32 ver; + __le32 boot_size; + __le32 ucode_size; + __le32 fw_size; + u8 data[0]; +}; + +static int ipw_get_fw(struct ipw_priv *priv, + const struct firmware **raw, const char *name) +{ + struct ipw_fw *fw; + int rc; + + /* ask firmware_class module to get the boot firmware off disk */ + rc = request_firmware(raw, name, &priv->pci_dev->dev); + if (rc < 0) { + IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc); + return rc; + } + + if ((*raw)->size < sizeof(*fw)) { + IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size); + return -EINVAL; + } + + fw = (void *)(*raw)->data; + + if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) + + le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) { + IPW_ERROR("%s is too small or corrupt (%zd)\n", + name, (*raw)->size); + return -EINVAL; + } + + IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n", + name, + le32_to_cpu(fw->ver) >> 16, + le32_to_cpu(fw->ver) & 0xff, + (*raw)->size - sizeof(*fw)); + return 0; +} + +#define IPW_RX_BUF_SIZE (3000) + +static void ipw_rx_queue_reset(struct ipw_priv *priv, + struct ipw_rx_queue *rxq) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&rxq->lock, flags); + + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} + +#ifdef CONFIG_PM +static int fw_loaded = 0; +static const struct firmware *raw = NULL; + +static void free_firmware(void) +{ + if (fw_loaded) { + release_firmware(raw); + raw = NULL; + fw_loaded = 0; + } +} +#else +#define free_firmware() do {} while (0) +#endif + +static int ipw_load(struct ipw_priv *priv) +{ +#ifndef CONFIG_PM + const struct firmware *raw = NULL; +#endif + struct ipw_fw *fw; + u8 *boot_img, *ucode_img, *fw_img; + u8 *name = NULL; + int rc = 0, retries = 3; + + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + name = "ipw2200-ibss.fw"; + break; +#ifdef CONFIG_IPW2200_MONITOR + case IW_MODE_MONITOR: + name = "ipw2200-sniffer.fw"; + break; +#endif + case IW_MODE_INFRA: + name = "ipw2200-bss.fw"; + break; + } + + if (!name) { + rc = -EINVAL; + goto error; + } + +#ifdef CONFIG_PM + if (!fw_loaded) { +#endif + rc = ipw_get_fw(priv, &raw, name); + if (rc < 0) + goto error; +#ifdef CONFIG_PM + } +#endif + + fw = (void *)raw->data; + boot_img = &fw->data[0]; + ucode_img = &fw->data[le32_to_cpu(fw->boot_size)]; + fw_img = &fw->data[le32_to_cpu(fw->boot_size) + + le32_to_cpu(fw->ucode_size)]; + + if (rc < 0) + goto error; + + if (!priv->rxq) + priv->rxq = ipw_rx_queue_alloc(priv); + else + ipw_rx_queue_reset(priv, priv->rxq); + if (!priv->rxq) { + IPW_ERROR("Unable to initialize Rx queue\n"); + goto error; + } + + retry: + /* Ensure interrupts are disabled */ + ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); + priv->status &= ~STATUS_INT_ENABLED; + + /* ack pending interrupts */ + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); + + ipw_stop_nic(priv); + + rc = ipw_reset_nic(priv); + if (rc < 0) { + IPW_ERROR("Unable to reset NIC\n"); + goto error; + } + + ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, + IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); + + /* DMA the initial boot firmware into the device */ + rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size)); + if (rc < 0) { + IPW_ERROR("Unable to load boot firmware: %d\n", rc); + goto error; + } + + /* kick start the device */ + ipw_start_nic(priv); + + /* wait for the device to finish its initial startup sequence */ + rc = ipw_poll_bit(priv, IPW_INTA_RW, + IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); + if (rc < 0) { + IPW_ERROR("device failed to boot initial fw image\n"); + goto error; + } + IPW_DEBUG_INFO("initial device response after %dms\n", rc); + + /* ack fw init done interrupt */ + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); + + /* DMA the ucode into the device */ + rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size)); + if (rc < 0) { + IPW_ERROR("Unable to load ucode: %d\n", rc); + goto error; + } + + /* stop nic */ + ipw_stop_nic(priv); + + /* DMA bss firmware into the device */ + rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size)); + if (rc < 0) { + IPW_ERROR("Unable to load firmware: %d\n", rc); + goto error; + } +#ifdef CONFIG_PM + fw_loaded = 1; +#endif + + ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); + + rc = ipw_queue_reset(priv); + if (rc < 0) { + IPW_ERROR("Unable to initialize queues\n"); + goto error; + } + + /* Ensure interrupts are disabled */ + ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); + /* ack pending interrupts */ + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); + + /* kick start the device */ + ipw_start_nic(priv); + + if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) { + if (retries > 0) { + IPW_WARNING("Parity error. Retrying init.\n"); + retries--; + goto retry; + } + + IPW_ERROR("TODO: Handle parity error -- schedule restart?\n"); + rc = -EIO; + goto error; + } + + /* wait for the device */ + rc = ipw_poll_bit(priv, IPW_INTA_RW, + IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); + if (rc < 0) { + IPW_ERROR("device failed to start within 500ms\n"); + goto error; + } + IPW_DEBUG_INFO("device response after %dms\n", rc); + + /* ack fw init done interrupt */ + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); + + /* read eeprom data and initialize the eeprom region of sram */ + priv->eeprom_delay = 1; + ipw_eeprom_init_sram(priv); + + /* enable interrupts */ + ipw_enable_interrupts(priv); + + /* Ensure our queue has valid packets */ + ipw_rx_queue_replenish(priv); + + ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read); + + /* ack pending interrupts */ + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); + +#ifndef CONFIG_PM + release_firmware(raw); +#endif + return 0; + + error: + if (priv->rxq) { + ipw_rx_queue_free(priv, priv->rxq); + priv->rxq = NULL; + } + ipw_tx_queue_free(priv); + if (raw) + release_firmware(raw); +#ifdef CONFIG_PM + fw_loaded = 0; + raw = NULL; +#endif + + return rc; +} + +/** + * DMA services + * + * Theory of operation + * + * A queue is a circular buffers with 'Read' and 'Write' pointers. + * 2 empty entries always kept in the buffer to protect from overflow. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * The IPW operates with six queues, one receive queue in the device's + * sram, one transmit queue for sending commands to the device firmware, + * and four transmit queues for data. + * + * The four transmit queues allow for performing quality of service (qos) + * transmissions as per the 802.11 protocol. Currently Linux does not + * provide a mechanism to the user for utilizing prioritized queues, so + * we only utilize the first data transmit queue (queue1). + */ + +/** + * Driver allocates buffers of this size for Rx + */ + +/** + * ipw_rx_queue_space - Return number of free slots available in queue. + */ +static int ipw_rx_queue_space(const struct ipw_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +static inline int ipw_tx_queue_space(const struct clx2_queue *q) +{ + int s = q->last_used - q->first_empty; + if (s <= 0) + s += q->n_bd; + s -= 2; /* keep some reserve to not confuse empty and full situations */ + if (s < 0) + s = 0; + return s; +} + +static inline int ipw_queue_inc_wrap(int index, int n_bd) +{ + return (++index == n_bd) ? 0 : index; +} + +/** + * Initialize common DMA queue structure + * + * @param q queue to init + * @param count Number of BD's to allocate. Should be power of 2 + * @param read_register Address for 'read' register + * (not offset within BAR, full address) + * @param write_register Address for 'write' register + * (not offset within BAR, full address) + * @param base_register Address for 'base' register + * (not offset within BAR, full address) + * @param size Address for 'size' register + * (not offset within BAR, full address) + */ +static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q, + int count, u32 read, u32 write, u32 base, u32 size) +{ + q->n_bd = count; + + q->low_mark = q->n_bd / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_bd / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->first_empty = q->last_used = 0; + q->reg_r = read; + q->reg_w = write; + + ipw_write32(priv, base, q->dma_addr); + ipw_write32(priv, size, count); + ipw_write32(priv, read, 0); + ipw_write32(priv, write, 0); + + _ipw_read32(priv, 0x90); +} + +static int ipw_queue_tx_init(struct ipw_priv *priv, + struct clx2_tx_queue *q, + int count, u32 read, u32 write, u32 base, u32 size) +{ + struct pci_dev *dev = priv->pci_dev; + + q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL); + if (!q->txb) { + IPW_ERROR("vmalloc for auxilary BD structures failed\n"); + return -ENOMEM; + } + + q->bd = + pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr); + if (!q->bd) { + IPW_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(q->bd[0]) * count); + kfree(q->txb); + q->txb = NULL; + return -ENOMEM; + } + + ipw_queue_init(priv, &q->q, count, read, write, base, size); + return 0; +} + +/** + * Free one TFD, those at index [txq->q.last_used]. + * Do NOT advance any indexes + * + * @param dev + * @param txq + */ +static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, + struct clx2_tx_queue *txq) +{ + struct tfd_frame *bd = &txq->bd[txq->q.last_used]; + struct pci_dev *dev = priv->pci_dev; + int i; + + /* classify bd */ + if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE) + /* nothing to cleanup after for host commands */ + return; + + /* sanity check */ + if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) { + IPW_ERROR("Too many chunks: %i\n", + le32_to_cpu(bd->u.data.num_chunks)); + /** @todo issue fatal error, it is quite serious situation */ + return; + } + + /* unmap chunks if any */ + for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) { + pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]), + le16_to_cpu(bd->u.data.chunk_len[i]), + PCI_DMA_TODEVICE); + if (txq->txb[txq->q.last_used]) { + ieee80211_txb_free(txq->txb[txq->q.last_used]); + txq->txb[txq->q.last_used] = NULL; + } + } +} + +/** + * Deallocate DMA queue. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * + * @param dev + * @param q + */ +static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq) +{ + struct clx2_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->first_empty != q->last_used; + q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) { + ipw_queue_tx_free_tfd(priv, txq); + } + + /* free buffers belonging to queue itself */ + pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd, + q->dma_addr); + kfree(txq->txb); + + /* 0 fill whole structure */ + memset(txq, 0, sizeof(*txq)); +} + +/** + * Destroy all DMA queues and structures + * + * @param priv + */ +static void ipw_tx_queue_free(struct ipw_priv *priv) +{ + /* Tx CMD queue */ + ipw_queue_tx_free(priv, &priv->txq_cmd); + + /* Tx queues */ + ipw_queue_tx_free(priv, &priv->txq[0]); + ipw_queue_tx_free(priv, &priv->txq[1]); + ipw_queue_tx_free(priv, &priv->txq[2]); + ipw_queue_tx_free(priv, &priv->txq[3]); +} + +static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid) +{ + /* First 3 bytes are manufacturer */ + bssid[0] = priv->mac_addr[0]; + bssid[1] = priv->mac_addr[1]; + bssid[2] = priv->mac_addr[2]; + + /* Last bytes are random */ + get_random_bytes(&bssid[3], ETH_ALEN - 3); + + bssid[0] &= 0xfe; /* clear multicast bit */ + bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */ +} + +static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) +{ + struct ipw_station_entry entry; + int i; + + for (i = 0; i < priv->num_stations; i++) { + if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { + /* Another node is active in network */ + priv->missed_adhoc_beacons = 0; + if (!(priv->config & CFG_STATIC_CHANNEL)) + /* when other nodes drop out, we drop out */ + priv->config &= ~CFG_ADHOC_PERSIST; + + return i; + } + } + + if (i == MAX_STATIONS) + return IPW_INVALID_STATION; + + IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid); + + entry.reserved = 0; + entry.support_mode = 0; + memcpy(entry.mac_addr, bssid, ETH_ALEN); + memcpy(priv->stations[i], bssid, ETH_ALEN); + ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry), + &entry, sizeof(entry)); + priv->num_stations++; + + return i; +} + +static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) +{ + int i; + + for (i = 0; i < priv->num_stations; i++) + if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) + return i; + + return IPW_INVALID_STATION; +} + +static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) +{ + int err; + + if (priv->status & STATUS_ASSOCIATING) { + IPW_DEBUG_ASSOC("Disassociating while associating.\n"); + queue_work(priv->workqueue, &priv->disassociate); + return; + } + + if (!(priv->status & STATUS_ASSOCIATED)) { + IPW_DEBUG_ASSOC("Disassociating while not associated.\n"); + return; + } + + IPW_DEBUG_ASSOC("Disassocation attempt from %pM " + "on channel %d.\n", + priv->assoc_request.bssid, + priv->assoc_request.channel); + + priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); + priv->status |= STATUS_DISASSOCIATING; + + if (quiet) + priv->assoc_request.assoc_type = HC_DISASSOC_QUIET; + else + priv->assoc_request.assoc_type = HC_DISASSOCIATE; + + err = ipw_send_associate(priv, &priv->assoc_request); + if (err) { + IPW_DEBUG_HC("Attempt to send [dis]associate command " + "failed.\n"); + return; + } + +} + +static int ipw_disassociate(void *data) +{ + struct ipw_priv *priv = data; + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) + return 0; + ipw_send_disassociate(data, 0); + return 1; +} + +static void ipw_bg_disassociate(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, disassociate); + mutex_lock(&priv->mutex); + ipw_disassociate(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_system_config(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, system_config); + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { + priv->sys_config.accept_all_data_frames = 1; + priv->sys_config.accept_non_directed_frames = 1; + priv->sys_config.accept_all_mgmt_bcpr = 1; + priv->sys_config.accept_all_mgmt_frames = 1; + } +#endif + + ipw_send_system_config(priv); +} + +struct ipw_status_code { + u16 status; + const char *reason; +}; + +static const struct ipw_status_code ipw_status_codes[] = { + {0x00, "Successful"}, + {0x01, "Unspecified failure"}, + {0x0A, "Cannot support all requested capabilities in the " + "Capability information field"}, + {0x0B, "Reassociation denied due to inability to confirm that " + "association exists"}, + {0x0C, "Association denied due to reason outside the scope of this " + "standard"}, + {0x0D, + "Responding station does not support the specified authentication " + "algorithm"}, + {0x0E, + "Received an Authentication frame with authentication sequence " + "transaction sequence number out of expected sequence"}, + {0x0F, "Authentication rejected because of challenge failure"}, + {0x10, "Authentication rejected due to timeout waiting for next " + "frame in sequence"}, + {0x11, "Association denied because AP is unable to handle additional " + "associated stations"}, + {0x12, + "Association denied due to requesting station not supporting all " + "of the datarates in the BSSBasicServiceSet Parameter"}, + {0x13, + "Association denied due to requesting station not supporting " + "short preamble operation"}, + {0x14, + "Association denied due to requesting station not supporting " + "PBCC encoding"}, + {0x15, + "Association denied due to requesting station not supporting " + "channel agility"}, + {0x19, + "Association denied due to requesting station not supporting " + "short slot operation"}, + {0x1A, + "Association denied due to requesting station not supporting " + "DSSS-OFDM operation"}, + {0x28, "Invalid Information Element"}, + {0x29, "Group Cipher is not valid"}, + {0x2A, "Pairwise Cipher is not valid"}, + {0x2B, "AKMP is not valid"}, + {0x2C, "Unsupported RSN IE version"}, + {0x2D, "Invalid RSN IE Capabilities"}, + {0x2E, "Cipher suite is rejected per security policy"}, +}; + +static const char *ipw_get_status_code(u16 status) +{ + int i; + for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++) + if (ipw_status_codes[i].status == (status & 0xff)) + return ipw_status_codes[i].reason; + return "Unknown status value."; +} + +static void inline average_init(struct average *avg) +{ + memset(avg, 0, sizeof(*avg)); +} + +#define DEPTH_RSSI 8 +#define DEPTH_NOISE 16 +static s16 exponential_average(s16 prev_avg, s16 val, u8 depth) +{ + return ((depth-1)*prev_avg + val)/depth; +} + +static void average_add(struct average *avg, s16 val) +{ + avg->sum -= avg->entries[avg->pos]; + avg->sum += val; + avg->entries[avg->pos++] = val; + if (unlikely(avg->pos == AVG_ENTRIES)) { + avg->init = 1; + avg->pos = 0; + } +} + +static s16 average_value(struct average *avg) +{ + if (!unlikely(avg->init)) { + if (avg->pos) + return avg->sum / avg->pos; + return 0; + } + + return avg->sum / AVG_ENTRIES; +} + +static void ipw_reset_stats(struct ipw_priv *priv) +{ + u32 len = sizeof(u32); + + priv->quality = 0; + + average_init(&priv->average_missed_beacons); + priv->exp_avg_rssi = -60; + priv->exp_avg_noise = -85 + 0x100; + + priv->last_rate = 0; + priv->last_missed_beacons = 0; + priv->last_rx_packets = 0; + priv->last_tx_packets = 0; + priv->last_tx_failures = 0; + + /* Firmware managed, reset only when NIC is restarted, so we have to + * normalize on the current value */ + ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, + &priv->last_rx_err, &len); + ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, + &priv->last_tx_failures, &len); + + /* Driver managed, reset with each association */ + priv->missed_adhoc_beacons = 0; + priv->missed_beacons = 0; + priv->tx_packets = 0; + priv->rx_packets = 0; + +} + +static u32 ipw_get_max_rate(struct ipw_priv *priv) +{ + u32 i = 0x80000000; + u32 mask = priv->rates_mask; + /* If currently associated in B mode, restrict the maximum + * rate match to B rates */ + if (priv->assoc_request.ieee_mode == IPW_B_MODE) + mask &= IEEE80211_CCK_RATES_MASK; + + /* TODO: Verify that the rate is supported by the current rates + * list. */ + + while (i && !(mask & i)) + i >>= 1; + switch (i) { + case IEEE80211_CCK_RATE_1MB_MASK: + return 1000000; + case IEEE80211_CCK_RATE_2MB_MASK: + return 2000000; + case IEEE80211_CCK_RATE_5MB_MASK: + return 5500000; + case IEEE80211_OFDM_RATE_6MB_MASK: + return 6000000; + case IEEE80211_OFDM_RATE_9MB_MASK: + return 9000000; + case IEEE80211_CCK_RATE_11MB_MASK: + return 11000000; + case IEEE80211_OFDM_RATE_12MB_MASK: + return 12000000; + case IEEE80211_OFDM_RATE_18MB_MASK: + return 18000000; + case IEEE80211_OFDM_RATE_24MB_MASK: + return 24000000; + case IEEE80211_OFDM_RATE_36MB_MASK: + return 36000000; + case IEEE80211_OFDM_RATE_48MB_MASK: + return 48000000; + case IEEE80211_OFDM_RATE_54MB_MASK: + return 54000000; + } + + if (priv->ieee->mode == IEEE_B) + return 11000000; + else + return 54000000; +} + +static u32 ipw_get_current_rate(struct ipw_priv *priv) +{ + u32 rate, len = sizeof(rate); + int err; + + if (!(priv->status & STATUS_ASSOCIATED)) + return 0; + + if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) { + err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate, + &len); + if (err) { + IPW_DEBUG_INFO("failed querying ordinals.\n"); + return 0; + } + } else + return ipw_get_max_rate(priv); + + switch (rate) { + case IPW_TX_RATE_1MB: + return 1000000; + case IPW_TX_RATE_2MB: + return 2000000; + case IPW_TX_RATE_5MB: + return 5500000; + case IPW_TX_RATE_6MB: + return 6000000; + case IPW_TX_RATE_9MB: + return 9000000; + case IPW_TX_RATE_11MB: + return 11000000; + case IPW_TX_RATE_12MB: + return 12000000; + case IPW_TX_RATE_18MB: + return 18000000; + case IPW_TX_RATE_24MB: + return 24000000; + case IPW_TX_RATE_36MB: + return 36000000; + case IPW_TX_RATE_48MB: + return 48000000; + case IPW_TX_RATE_54MB: + return 54000000; + } + + return 0; +} + +#define IPW_STATS_INTERVAL (2 * HZ) +static void ipw_gather_stats(struct ipw_priv *priv) +{ + u32 rx_err, rx_err_delta, rx_packets_delta; + u32 tx_failures, tx_failures_delta, tx_packets_delta; + u32 missed_beacons_percent, missed_beacons_delta; + u32 quality = 0; + u32 len = sizeof(u32); + s16 rssi; + u32 beacon_quality, signal_quality, tx_quality, rx_quality, + rate_quality; + u32 max_rate; + + if (!(priv->status & STATUS_ASSOCIATED)) { + priv->quality = 0; + return; + } + + /* Update the statistics */ + ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS, + &priv->missed_beacons, &len); + missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons; + priv->last_missed_beacons = priv->missed_beacons; + if (priv->assoc_request.beacon_interval) { + missed_beacons_percent = missed_beacons_delta * + (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) / + (IPW_STATS_INTERVAL * 10); + } else { + missed_beacons_percent = 0; + } + average_add(&priv->average_missed_beacons, missed_beacons_percent); + + ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len); + rx_err_delta = rx_err - priv->last_rx_err; + priv->last_rx_err = rx_err; + + ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len); + tx_failures_delta = tx_failures - priv->last_tx_failures; + priv->last_tx_failures = tx_failures; + + rx_packets_delta = priv->rx_packets - priv->last_rx_packets; + priv->last_rx_packets = priv->rx_packets; + + tx_packets_delta = priv->tx_packets - priv->last_tx_packets; + priv->last_tx_packets = priv->tx_packets; + + /* Calculate quality based on the following: + * + * Missed beacon: 100% = 0, 0% = 70% missed + * Rate: 60% = 1Mbs, 100% = Max + * Rx and Tx errors represent a straight % of total Rx/Tx + * RSSI: 100% = > -50, 0% = < -80 + * Rx errors: 100% = 0, 0% = 50% missed + * + * The lowest computed quality is used. + * + */ +#define BEACON_THRESHOLD 5 + beacon_quality = 100 - missed_beacons_percent; + if (beacon_quality < BEACON_THRESHOLD) + beacon_quality = 0; + else + beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 / + (100 - BEACON_THRESHOLD); + IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n", + beacon_quality, missed_beacons_percent); + + priv->last_rate = ipw_get_current_rate(priv); + max_rate = ipw_get_max_rate(priv); + rate_quality = priv->last_rate * 40 / max_rate + 60; + IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n", + rate_quality, priv->last_rate / 1000000); + + if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta) + rx_quality = 100 - (rx_err_delta * 100) / + (rx_packets_delta + rx_err_delta); + else + rx_quality = 100; + IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n", + rx_quality, rx_err_delta, rx_packets_delta); + + if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta) + tx_quality = 100 - (tx_failures_delta * 100) / + (tx_packets_delta + tx_failures_delta); + else + tx_quality = 100; + IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n", + tx_quality, tx_failures_delta, tx_packets_delta); + + rssi = priv->exp_avg_rssi; + signal_quality = + (100 * + (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * + (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) - + (priv->ieee->perfect_rssi - rssi) * + (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) + + 62 * (priv->ieee->perfect_rssi - rssi))) / + ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * + (priv->ieee->perfect_rssi - priv->ieee->worst_rssi)); + if (signal_quality > 100) + signal_quality = 100; + else if (signal_quality < 1) + signal_quality = 0; + + IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", + signal_quality, rssi); + + quality = min(beacon_quality, + min(rate_quality, + min(tx_quality, min(rx_quality, signal_quality)))); + if (quality == beacon_quality) + IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n", + quality); + if (quality == rate_quality) + IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n", + quality); + if (quality == tx_quality) + IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n", + quality); + if (quality == rx_quality) + IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n", + quality); + if (quality == signal_quality) + IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n", + quality); + + priv->quality = quality; + + queue_delayed_work(priv->workqueue, &priv->gather_stats, + IPW_STATS_INTERVAL); +} + +static void ipw_bg_gather_stats(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, gather_stats.work); + mutex_lock(&priv->mutex); + ipw_gather_stats(priv); + mutex_unlock(&priv->mutex); +} + +/* Missed beacon behavior: + * 1st missed -> roaming_threshold, just wait, don't do any scan/roam. + * roaming_threshold -> disassociate_threshold, scan and roam for better signal. + * Above disassociate threshold, give up and stop scanning. + * Roaming is disabled if disassociate_threshold <= roaming_threshold */ +static void ipw_handle_missed_beacon(struct ipw_priv *priv, + int missed_count) +{ + priv->notif_missed_beacons = missed_count; + + if (missed_count > priv->disassociate_threshold && + priv->status & STATUS_ASSOCIATED) { + /* If associated and we've hit the missed + * beacon threshold, disassociate, turn + * off roaming, and abort any active scans */ + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE | IPW_DL_ASSOC, + "Missed beacon: %d - disassociate\n", missed_count); + priv->status &= ~STATUS_ROAMING; + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE, + "Aborting scan with missed beacon.\n"); + queue_work(priv->workqueue, &priv->abort_scan); + } + + queue_work(priv->workqueue, &priv->disassociate); + return; + } + + if (priv->status & STATUS_ROAMING) { + /* If we are currently roaming, then just + * print a debug statement... */ + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, + "Missed beacon: %d - roam in progress\n", + missed_count); + return; + } + + if (roaming && + (missed_count > priv->roaming_threshold && + missed_count <= priv->disassociate_threshold)) { + /* If we are not already roaming, set the ROAM + * bit in the status and kick off a scan. + * This can happen several times before we reach + * disassociate_threshold. */ + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, + "Missed beacon: %d - initiate " + "roaming\n", missed_count); + if (!(priv->status & STATUS_ROAMING)) { + priv->status |= STATUS_ROAMING; + if (!(priv->status & STATUS_SCANNING)) + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); + } + return; + } + + if (priv->status & STATUS_SCANNING) { + /* Stop scan to keep fw from getting + * stuck (only if we aren't roaming -- + * otherwise we'll never scan more than 2 or 3 + * channels..) */ + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE, + "Aborting scan with missed beacon.\n"); + queue_work(priv->workqueue, &priv->abort_scan); + } + + IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); +} + +static void ipw_scan_event(struct work_struct *work) +{ + union iwreq_data wrqu; + + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_event.work); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); +} + +static void handle_scan_event(struct ipw_priv *priv) +{ + /* Only userspace-requested scan completion events go out immediately */ + if (!priv->user_requested_scan) { + if (!delayed_work_pending(&priv->scan_event)) + queue_delayed_work(priv->workqueue, &priv->scan_event, + round_jiffies_relative(msecs_to_jiffies(4000))); + } else { + union iwreq_data wrqu; + + priv->user_requested_scan = 0; + cancel_delayed_work(&priv->scan_event); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); + } +} + +/** + * Handle host notification packet. + * Called from interrupt routine + */ +static void ipw_rx_notification(struct ipw_priv *priv, + struct ipw_rx_notification *notif) +{ + DECLARE_SSID_BUF(ssid); + u16 size = le16_to_cpu(notif->size); + notif->size = le16_to_cpu(notif->size); + + IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size); + + switch (notif->subtype) { + case HOST_NOTIFICATION_STATUS_ASSOCIATED:{ + struct notif_association *assoc = ¬if->u.assoc; + + switch (assoc->state) { + case CMAS_ASSOCIATED:{ + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, + "associated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); + + switch (priv->ieee->iw_mode) { + case IW_MODE_INFRA: + memcpy(priv->ieee->bssid, + priv->bssid, ETH_ALEN); + break; + + case IW_MODE_ADHOC: + memcpy(priv->ieee->bssid, + priv->bssid, ETH_ALEN); + + /* clear out the station table */ + priv->num_stations = 0; + + IPW_DEBUG_ASSOC + ("queueing adhoc check\n"); + queue_delayed_work(priv-> + workqueue, + &priv-> + adhoc_check, + le16_to_cpu(priv-> + assoc_request. + beacon_interval)); + break; + } + + priv->status &= ~STATUS_ASSOCIATING; + priv->status |= STATUS_ASSOCIATED; + queue_work(priv->workqueue, + &priv->system_config); + +#ifdef CONFIG_IPW2200_QOS +#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ + le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control)) + if ((priv->status & STATUS_AUTH) && + (IPW_GET_PACKET_STYPE(¬if->u.raw) + == IEEE80211_STYPE_ASSOC_RESP)) { + if ((sizeof + (struct + ieee80211_assoc_response) + <= size) + && (size <= 2314)) { + struct + ieee80211_rx_stats + stats = { + .len = size - 1, + }; + + IPW_DEBUG_QOS + ("QoS Associate " + "size %d\n", size); + ieee80211_rx_mgt(priv-> + ieee, + (struct + ieee80211_hdr_4addr + *) + ¬if->u.raw, &stats); + } + } +#endif + + schedule_work(&priv->link_up); + + break; + } + + case CMAS_AUTHENTICATED:{ + if (priv-> + status & (STATUS_ASSOCIATED | + STATUS_AUTH)) { + struct notif_authenticate *auth + = ¬if->u.auth; + IPW_DEBUG(IPW_DL_NOTIF | + IPW_DL_STATE | + IPW_DL_ASSOC, + "deauthenticated: '%s' " + "%pM" + ": (0x%04X) - %s \n", + print_ssid(ssid, + priv-> + essid, + priv-> + essid_len), + priv->bssid, + le16_to_cpu(auth->status), + ipw_get_status_code + (le16_to_cpu + (auth->status))); + + priv->status &= + ~(STATUS_ASSOCIATING | + STATUS_AUTH | + STATUS_ASSOCIATED); + + schedule_work(&priv->link_down); + break; + } + + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, + "authenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); + break; + } + + case CMAS_INIT:{ + if (priv->status & STATUS_AUTH) { + struct + ieee80211_assoc_response + *resp; + resp = + (struct + ieee80211_assoc_response + *)¬if->u.raw; + IPW_DEBUG(IPW_DL_NOTIF | + IPW_DL_STATE | + IPW_DL_ASSOC, + "association failed (0x%04X): %s\n", + le16_to_cpu(resp->status), + ipw_get_status_code + (le16_to_cpu + (resp->status))); + } + + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); + + priv->status &= + ~(STATUS_DISASSOCIATING | + STATUS_ASSOCIATING | + STATUS_ASSOCIATED | STATUS_AUTH); + if (priv->assoc_network + && (priv->assoc_network-> + capability & + WLAN_CAPABILITY_IBSS)) + ipw_remove_current_network + (priv); + + schedule_work(&priv->link_down); + + break; + } + + case CMAS_RX_ASSOC_RESP: + break; + + default: + IPW_ERROR("assoc: unknown (%d)\n", + assoc->state); + break; + } + + break; + } + + case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{ + struct notif_authenticate *auth = ¬if->u.auth; + switch (auth->state) { + case CMAS_AUTHENTICATED: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, + "authenticated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); + priv->status |= STATUS_AUTH; + break; + + case CMAS_INIT: + if (priv->status & STATUS_AUTH) { + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, + "authentication failed (0x%04X): %s\n", + le16_to_cpu(auth->status), + ipw_get_status_code(le16_to_cpu + (auth-> + status))); + } + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, + "deauthenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); + + priv->status &= ~(STATUS_ASSOCIATING | + STATUS_AUTH | + STATUS_ASSOCIATED); + + schedule_work(&priv->link_down); + break; + + case CMAS_TX_AUTH_SEQ_1: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUTH_SEQ_1\n"); + break; + case CMAS_RX_AUTH_SEQ_2: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUTH_SEQ_2\n"); + break; + case CMAS_AUTH_SEQ_1_PASS: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n"); + break; + case CMAS_AUTH_SEQ_1_FAIL: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n"); + break; + case CMAS_TX_AUTH_SEQ_3: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUTH_SEQ_3\n"); + break; + case CMAS_RX_AUTH_SEQ_4: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n"); + break; + case CMAS_AUTH_SEQ_2_PASS: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n"); + break; + case CMAS_AUTH_SEQ_2_FAIL: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n"); + break; + case CMAS_TX_ASSOC: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "TX_ASSOC\n"); + break; + case CMAS_RX_ASSOC_RESP: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "RX_ASSOC_RESP\n"); + + break; + case CMAS_ASSOCIATED: + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | + IPW_DL_ASSOC, "ASSOCIATED\n"); + break; + default: + IPW_DEBUG_NOTIF("auth: failure - %d\n", + auth->state); + break; + } + break; + } + + case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{ + struct notif_channel_result *x = + ¬if->u.channel_result; + + if (size == sizeof(*x)) { + IPW_DEBUG_SCAN("Scan result for channel %d\n", + x->channel_num); + } else { + IPW_DEBUG_SCAN("Scan result of wrong size %d " + "(should be %zd)\n", + size, sizeof(*x)); + } + break; + } + + case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{ + struct notif_scan_complete *x = ¬if->u.scan_complete; + if (size == sizeof(*x)) { + IPW_DEBUG_SCAN + ("Scan completed: type %d, %d channels, " + "%d status\n", x->scan_type, + x->num_channels, x->status); + } else { + IPW_ERROR("Scan completed of wrong size %d " + "(should be %zd)\n", + size, sizeof(*x)); + } + + priv->status &= + ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); + + wake_up_interruptible(&priv->wait_state); + cancel_delayed_work(&priv->scan_check); + + if (priv->status & STATUS_EXIT_PENDING) + break; + + priv->ieee->scans++; + +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + priv->status |= STATUS_SCAN_FORCED; + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); + break; + } + priv->status &= ~STATUS_SCAN_FORCED; +#endif /* CONFIG_IPW2200_MONITOR */ + + /* Do queued direct scans first */ + if (priv->status & STATUS_DIRECT_SCAN_PENDING) { + queue_delayed_work(priv->workqueue, + &priv->request_direct_scan, 0); + } + + if (!(priv->status & (STATUS_ASSOCIATED | + STATUS_ASSOCIATING | + STATUS_ROAMING | + STATUS_DISASSOCIATING))) + queue_work(priv->workqueue, &priv->associate); + else if (priv->status & STATUS_ROAMING) { + if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) + /* If a scan completed and we are in roam mode, then + * the scan that completed was the one requested as a + * result of entering roam... so, schedule the + * roam work */ + queue_work(priv->workqueue, + &priv->roam); + else + /* Don't schedule if we aborted the scan */ + priv->status &= ~STATUS_ROAMING; + } else if (priv->status & STATUS_SCAN_PENDING) + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); + else if (priv->config & CFG_BACKGROUND_SCAN + && priv->status & STATUS_ASSOCIATED) + queue_delayed_work(priv->workqueue, + &priv->request_scan, + round_jiffies_relative(HZ)); + + /* Send an empty event to user space. + * We don't send the received data on the event because + * it would require us to do complex transcoding, and + * we want to minimise the work done in the irq handler + * Use a request to extract the data. + * Also, we generate this even for any scan, regardless + * on how the scan was initiated. User space can just + * sync on periodic scan to get fresh data... + * Jean II */ + if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) + handle_scan_event(priv); + break; + } + + case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{ + struct notif_frag_length *x = ¬if->u.frag_len; + + if (size == sizeof(*x)) + IPW_ERROR("Frag length: %d\n", + le16_to_cpu(x->frag_length)); + else + IPW_ERROR("Frag length of wrong size %d " + "(should be %zd)\n", + size, sizeof(*x)); + break; + } + + case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{ + struct notif_link_deterioration *x = + ¬if->u.link_deterioration; + + if (size == sizeof(*x)) { + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, + "link deterioration: type %d, cnt %d\n", + x->silence_notification_type, + x->silence_count); + memcpy(&priv->last_link_deterioration, x, + sizeof(*x)); + } else { + IPW_ERROR("Link Deterioration of wrong size %d " + "(should be %zd)\n", + size, sizeof(*x)); + } + break; + } + + case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{ + IPW_ERROR("Dino config\n"); + if (priv->hcmd + && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG) + IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n"); + + break; + } + + case HOST_NOTIFICATION_STATUS_BEACON_STATE:{ + struct notif_beacon_state *x = ¬if->u.beacon_state; + if (size != sizeof(*x)) { + IPW_ERROR + ("Beacon state of wrong size %d (should " + "be %zd)\n", size, sizeof(*x)); + break; + } + + if (le32_to_cpu(x->state) == + HOST_NOTIFICATION_STATUS_BEACON_MISSING) + ipw_handle_missed_beacon(priv, + le32_to_cpu(x-> + number)); + + break; + } + + case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{ + struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key; + if (size == sizeof(*x)) { + IPW_ERROR("TGi Tx Key: state 0x%02x sec type " + "0x%02x station %d\n", + x->key_state, x->security_type, + x->station_index); + break; + } + + IPW_ERROR + ("TGi Tx Key of wrong size %d (should be %zd)\n", + size, sizeof(*x)); + break; + } + + case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{ + struct notif_calibration *x = ¬if->u.calibration; + + if (size == sizeof(*x)) { + memcpy(&priv->calib, x, sizeof(*x)); + IPW_DEBUG_INFO("TODO: Calibration\n"); + break; + } + + IPW_ERROR + ("Calibration of wrong size %d (should be %zd)\n", + size, sizeof(*x)); + break; + } + + case HOST_NOTIFICATION_NOISE_STATS:{ + if (size == sizeof(u32)) { + priv->exp_avg_noise = + exponential_average(priv->exp_avg_noise, + (u8) (le32_to_cpu(notif->u.noise.value) & 0xff), + DEPTH_NOISE); + break; + } + + IPW_ERROR + ("Noise stat is wrong size %d (should be %zd)\n", + size, sizeof(u32)); + break; + } + + default: + IPW_DEBUG_NOTIF("Unknown notification: " + "subtype=%d,flags=0x%2x,size=%d\n", + notif->subtype, notif->flags, size); + } +} + +/** + * Destroys all DMA structures and initialise them again + * + * @param priv + * @return error code + */ +static int ipw_queue_reset(struct ipw_priv *priv) +{ + int rc = 0; + /** @todo customize queue sizes */ + int nTx = 64, nTxCmd = 8; + ipw_tx_queue_free(priv); + /* Tx CMD queue */ + rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd, + IPW_TX_CMD_QUEUE_READ_INDEX, + IPW_TX_CMD_QUEUE_WRITE_INDEX, + IPW_TX_CMD_QUEUE_BD_BASE, + IPW_TX_CMD_QUEUE_BD_SIZE); + if (rc) { + IPW_ERROR("Tx Cmd queue init failed\n"); + goto error; + } + /* Tx queue(s) */ + rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx, + IPW_TX_QUEUE_0_READ_INDEX, + IPW_TX_QUEUE_0_WRITE_INDEX, + IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE); + if (rc) { + IPW_ERROR("Tx 0 queue init failed\n"); + goto error; + } + rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx, + IPW_TX_QUEUE_1_READ_INDEX, + IPW_TX_QUEUE_1_WRITE_INDEX, + IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE); + if (rc) { + IPW_ERROR("Tx 1 queue init failed\n"); + goto error; + } + rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx, + IPW_TX_QUEUE_2_READ_INDEX, + IPW_TX_QUEUE_2_WRITE_INDEX, + IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE); + if (rc) { + IPW_ERROR("Tx 2 queue init failed\n"); + goto error; + } + rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx, + IPW_TX_QUEUE_3_READ_INDEX, + IPW_TX_QUEUE_3_WRITE_INDEX, + IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE); + if (rc) { + IPW_ERROR("Tx 3 queue init failed\n"); + goto error; + } + /* statistics */ + priv->rx_bufs_min = 0; + priv->rx_pend_max = 0; + return rc; + + error: + ipw_tx_queue_free(priv); + return rc; +} + +/** + * Reclaim Tx queue entries no more used by NIC. + * + * When FW advances 'R' index, all entries between old and + * new 'R' index need to be reclaimed. As result, some free space + * forms. If there is enough free space (> low mark), wake Tx queue. + * + * @note Need to protect against garbage in 'R' index + * @param priv + * @param txq + * @param qindex + * @return Number of used entries remains in the queue + */ +static int ipw_queue_tx_reclaim(struct ipw_priv *priv, + struct clx2_tx_queue *txq, int qindex) +{ + u32 hw_tail; + int used; + struct clx2_queue *q = &txq->q; + + hw_tail = ipw_read32(priv, q->reg_r); + if (hw_tail >= q->n_bd) { + IPW_ERROR + ("Read index for DMA queue (%d) is out of range [0-%d)\n", + hw_tail, q->n_bd); + goto done; + } + for (; q->last_used != hw_tail; + q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) { + ipw_queue_tx_free_tfd(priv, txq); + priv->tx_packets++; + } + done: + if ((ipw_tx_queue_space(q) > q->low_mark) && + (qindex >= 0)) + netif_wake_queue(priv->net_dev); + used = q->first_empty - q->last_used; + if (used < 0) + used += q->n_bd; + + return used; +} + +static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, + int len, int sync) +{ + struct clx2_tx_queue *txq = &priv->txq_cmd; + struct clx2_queue *q = &txq->q; + struct tfd_frame *tfd; + + if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) { + IPW_ERROR("No space for Tx\n"); + return -EBUSY; + } + + tfd = &txq->bd[q->first_empty]; + txq->txb[q->first_empty] = NULL; + + memset(tfd, 0, sizeof(*tfd)); + tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE; + tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; + priv->hcmd_seq++; + tfd->u.cmd.index = hcmd; + tfd->u.cmd.length = len; + memcpy(tfd->u.cmd.payload, buf, len); + q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); + ipw_write32(priv, q->reg_w, q->first_empty); + _ipw_read32(priv, 0x90); + + return 0; +} + +/* + * Rx theory of operation + * + * The host allocates 32 DMA target addresses and passes the host address + * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is + * 0 to 31 + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When + * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replensish the ipw->rxq->rx_free. + * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the + * ipw->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the ipw->rxq. The driver 'processed' index is updated. + * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ + * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * ipw_rx_queue_alloc() Allocates rx_free + * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls + * ipw_rx_queue_restock + * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules ipw_rx_queue_replenish + * + * -- enable interrupts -- + * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls ipw_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/* + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +static void ipw_rx_queue_restock(struct ipw_priv *priv) +{ + struct ipw_rx_queue *rxq = priv->rxq; + struct list_head *element; + struct ipw_rx_mem_buffer *rxb; + unsigned long flags; + int write; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write; + while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + element = rxq->rx_free.next; + rxb = list_entry(element, struct ipw_rx_mem_buffer, list); + list_del(element); + + ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE, + rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + /* If we've added more space for the firmware to place data, tell it */ + if (write != rxq->write) + ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write); +} + +/* + * Move all used packet from rx_used to rx_free, allocating a new SKB for each. + * Also restock the Rx queue via ipw_rx_queue_restock. + * + * This is called as a scheduled work item (except for during intialization) + */ +static void ipw_rx_queue_replenish(void *data) +{ + struct ipw_priv *priv = data; + struct ipw_rx_queue *rxq = priv->rxq; + struct list_head *element; + struct ipw_rx_mem_buffer *rxb; + unsigned long flags; + + spin_lock_irqsave(&rxq->lock, flags); + while (!list_empty(&rxq->rx_used)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct ipw_rx_mem_buffer, list); + rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC); + if (!rxb->skb) { + printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n", + priv->net_dev->name); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + list_del(element); + + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + ipw_rx_queue_restock(priv); +} + +static void ipw_bg_rx_queue_replenish(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rx_replenish); + mutex_lock(&priv->mutex); + ipw_rx_queue_replenish(priv); + mutex_unlock(&priv->mutex); +} + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have its SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq) +{ + int i; + + if (!rxq) + return; + + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + kfree(rxq); +} + +static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) +{ + struct ipw_rx_queue *rxq; + int i; + + rxq = kzalloc(sizeof(*rxq), GFP_KERNEL); + if (unlikely(!rxq)) { + IPW_ERROR("memory allocation failed\n"); + return NULL; + } + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + + return rxq; +} + +static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) +{ + rate &= ~IEEE80211_BASIC_RATE_MASK; + if (ieee_mode == IEEE_A) { + switch (rate) { + case IEEE80211_OFDM_RATE_6MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? + 1 : 0; + case IEEE80211_OFDM_RATE_9MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? + 1 : 0; + case IEEE80211_OFDM_RATE_12MB: + return priv-> + rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_18MB: + return priv-> + rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_24MB: + return priv-> + rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_36MB: + return priv-> + rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_48MB: + return priv-> + rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_54MB: + return priv-> + rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; + default: + return 0; + } + } + + /* B and G mixed */ + switch (rate) { + case IEEE80211_CCK_RATE_1MB: + return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0; + case IEEE80211_CCK_RATE_2MB: + return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0; + case IEEE80211_CCK_RATE_5MB: + return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0; + case IEEE80211_CCK_RATE_11MB: + return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0; + } + + /* If we are limited to B modulations, bail at this point */ + if (ieee_mode == IEEE_B) + return 0; + + /* G */ + switch (rate) { + case IEEE80211_OFDM_RATE_6MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_9MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_12MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_18MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_24MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_36MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_48MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; + case IEEE80211_OFDM_RATE_54MB: + return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; + } + + return 0; +} + +static int ipw_compatible_rates(struct ipw_priv *priv, + const struct ieee80211_network *network, + struct ipw_supported_rates *rates) +{ + int num_rates, i; + + memset(rates, 0, sizeof(*rates)); + num_rates = min(network->rates_len, (u8) IPW_MAX_RATES); + rates->num_rates = 0; + for (i = 0; i < num_rates; i++) { + if (!ipw_is_rate_in_mask(priv, network->mode, + network->rates[i])) { + + if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { + IPW_DEBUG_SCAN("Adding masked mandatory " + "rate %02X\n", + network->rates[i]); + rates->supported_rates[rates->num_rates++] = + network->rates[i]; + continue; + } + + IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", + network->rates[i], priv->rates_mask); + continue; + } + + rates->supported_rates[rates->num_rates++] = network->rates[i]; + } + + num_rates = min(network->rates_ex_len, + (u8) (IPW_MAX_RATES - num_rates)); + for (i = 0; i < num_rates; i++) { + if (!ipw_is_rate_in_mask(priv, network->mode, + network->rates_ex[i])) { + if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { + IPW_DEBUG_SCAN("Adding masked mandatory " + "rate %02X\n", + network->rates_ex[i]); + rates->supported_rates[rates->num_rates++] = + network->rates[i]; + continue; + } + + IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", + network->rates_ex[i], priv->rates_mask); + continue; + } + + rates->supported_rates[rates->num_rates++] = + network->rates_ex[i]; + } + + return 1; +} + +static void ipw_copy_rates(struct ipw_supported_rates *dest, + const struct ipw_supported_rates *src) +{ + u8 i; + for (i = 0; i < src->num_rates; i++) + dest->supported_rates[i] = src->supported_rates[i]; + dest->num_rates = src->num_rates; +} + +/* TODO: Look at sniffed packets in the air to determine if the basic rate + * mask should ever be used -- right now all callers to add the scan rates are + * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */ +static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates, + u8 modulation, u32 rate_mask) +{ + u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? + IEEE80211_BASIC_RATE_MASK : 0; + + if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + + if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + + if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK) + rates->supported_rates[rates->num_rates++] = basic_mask | + IEEE80211_CCK_RATE_5MB; + + if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK) + rates->supported_rates[rates->num_rates++] = basic_mask | + IEEE80211_CCK_RATE_11MB; +} + +static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates, + u8 modulation, u32 rate_mask) +{ + u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? + IEEE80211_BASIC_RATE_MASK : 0; + + if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK) + rates->supported_rates[rates->num_rates++] = basic_mask | + IEEE80211_OFDM_RATE_6MB; + + if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_OFDM_RATE_9MB; + + if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK) + rates->supported_rates[rates->num_rates++] = basic_mask | + IEEE80211_OFDM_RATE_12MB; + + if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_OFDM_RATE_18MB; + + if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK) + rates->supported_rates[rates->num_rates++] = basic_mask | + IEEE80211_OFDM_RATE_24MB; + + if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_OFDM_RATE_36MB; + + if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_OFDM_RATE_48MB; + + if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK) + rates->supported_rates[rates->num_rates++] = + IEEE80211_OFDM_RATE_54MB; +} + +struct ipw_network_match { + struct ieee80211_network *network; + struct ipw_supported_rates rates; +}; + +static int ipw_find_adhoc_network(struct ipw_priv *priv, + struct ipw_network_match *match, + struct ieee80211_network *network, + int roaming) +{ + struct ipw_supported_rates rates; + DECLARE_SSID_BUF(ssid); + + /* Verify that this network's capability is compatible with the + * current mode (AdHoc or Infrastructure) */ + if ((priv->ieee->iw_mode == IW_MODE_ADHOC && + !(network->capability & WLAN_CAPABILITY_IBSS))) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " + "capability mismatch.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + if (unlikely(roaming)) { + /* If we are roaming, then ensure check if this is a valid + * network to try and roam to */ + if ((network->ssid_len != match->network->ssid_len) || + memcmp(network->ssid, match->network->ssid, + network->ssid_len)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of non-network ESSID.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + } else { + /* If an ESSID has been configured then compare the broadcast + * ESSID to ours */ + if ((priv->config & CFG_STATIC_ESSID) && + ((network->ssid_len != priv->essid_len) || + memcmp(network->ssid, priv->essid, + min(network->ssid_len, priv->essid_len)))) { + char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + + strncpy(escaped, + print_ssid(ssid, network->ssid, + network->ssid_len), + sizeof(escaped)); + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of ESSID mismatch: '%s'.\n", + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); + return 0; + } + } + + /* If the old network rate is better than this one, don't bother + * testing everything else. */ + + if (network->time_stamp[0] < match->network->time_stamp[0]) { + IPW_DEBUG_MERGE("Network '%s excluded because newer than " + "current network.\n", + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); + return 0; + } else if (network->time_stamp[1] < match->network->time_stamp[1]) { + IPW_DEBUG_MERGE("Network '%s excluded because newer than " + "current network.\n", + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); + return 0; + } + + /* Now go through and see if the requested network is valid... */ + if (priv->ieee->scan_age != 0 && + time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of age: %ums.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + jiffies_to_msecs(jiffies - + network->last_scanned)); + return 0; + } + + if ((priv->config & CFG_STATIC_CHANNEL) && + (network->channel != priv->channel)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of channel mismatch: %d != %d.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + network->channel, priv->channel); + return 0; + } + + /* Verify privacy compatability */ + if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != + ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of privacy mismatch: %s != %s.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + priv-> + capability & CAP_PRIVACY_ON ? "on" : "off", + network-> + capability & WLAN_CAPABILITY_PRIVACY ? "on" : + "off"); + return 0; + } + + if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of the same BSSID match: %pM" + ".\n", print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + priv->bssid); + return 0; + } + + /* Filter out any incompatible freq / mode combinations */ + if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of invalid frequency/mode " + "combination.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + /* Ensure that the rates supported by the driver are compatible with + * this AP, including verification of basic rates (mandatory) */ + if (!ipw_compatible_rates(priv, network, &rates)) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because configured rate mask excludes " + "AP mandatory rate.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + if (rates.num_rates == 0) { + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of no compatible rates.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + /* TODO: Perform any further minimal comparititive tests. We do not + * want to put too much policy logic here; intelligent scan selection + * should occur within a generic IEEE 802.11 user space tool. */ + + /* Set up 'new' AP to this network */ + ipw_copy_rates(&match->rates, &rates); + match->network = network; + IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); + + return 1; +} + +static void ipw_merge_adhoc_network(struct work_struct *work) +{ + DECLARE_SSID_BUF(ssid); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, merge_networks); + struct ieee80211_network *network = NULL; + struct ipw_network_match match = { + .network = priv->assoc_network + }; + + if ((priv->status & STATUS_ASSOCIATED) && + (priv->ieee->iw_mode == IW_MODE_ADHOC)) { + /* First pass through ROAM process -- look for a better + * network */ + unsigned long flags; + + spin_lock_irqsave(&priv->ieee->lock, flags); + list_for_each_entry(network, &priv->ieee->network_list, list) { + if (network != priv->assoc_network) + ipw_find_adhoc_network(priv, &match, network, + 1); + } + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + if (match.network == priv->assoc_network) { + IPW_DEBUG_MERGE("No better ADHOC in this network to " + "merge to.\n"); + return; + } + + mutex_lock(&priv->mutex); + if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { + IPW_DEBUG_MERGE("remove network %s\n", + print_ssid(ssid, priv->essid, + priv->essid_len)); + ipw_remove_current_network(priv); + } + + ipw_disassociate(priv); + priv->assoc_network = match.network; + mutex_unlock(&priv->mutex); + return; + } +} + +static int ipw_best_network(struct ipw_priv *priv, + struct ipw_network_match *match, + struct ieee80211_network *network, int roaming) +{ + struct ipw_supported_rates rates; + DECLARE_SSID_BUF(ssid); + + /* Verify that this network's capability is compatible with the + * current mode (AdHoc or Infrastructure) */ + if ((priv->ieee->iw_mode == IW_MODE_INFRA && + !(network->capability & WLAN_CAPABILITY_ESS)) || + (priv->ieee->iw_mode == IW_MODE_ADHOC && + !(network->capability & WLAN_CAPABILITY_IBSS))) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " + "capability mismatch.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + if (unlikely(roaming)) { + /* If we are roaming, then ensure check if this is a valid + * network to try and roam to */ + if ((network->ssid_len != match->network->ssid_len) || + memcmp(network->ssid, match->network->ssid, + network->ssid_len)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of non-network ESSID.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + } else { + /* If an ESSID has been configured then compare the broadcast + * ESSID to ours */ + if ((priv->config & CFG_STATIC_ESSID) && + ((network->ssid_len != priv->essid_len) || + memcmp(network->ssid, priv->essid, + min(network->ssid_len, priv->essid_len)))) { + char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + strncpy(escaped, + print_ssid(ssid, network->ssid, + network->ssid_len), + sizeof(escaped)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of ESSID mismatch: '%s'.\n", + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); + return 0; + } + } + + /* If the old network rate is better than this one, don't bother + * testing everything else. */ + if (match->network && match->network->stats.rssi > network->stats.rssi) { + char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + strncpy(escaped, + print_ssid(ssid, network->ssid, network->ssid_len), + sizeof(escaped)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " + "'%s (%pM)' has a stronger signal.\n", + escaped, network->bssid, + print_ssid(ssid, match->network->ssid, + match->network->ssid_len), + match->network->bssid); + return 0; + } + + /* If this network has already had an association attempt within the + * last 3 seconds, do not try and associate again... */ + if (network->last_associate && + time_after(network->last_associate + (HZ * 3UL), jiffies)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of storming (%ums since last " + "assoc attempt).\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + jiffies_to_msecs(jiffies - + network->last_associate)); + return 0; + } + + /* Now go through and see if the requested network is valid... */ + if (priv->ieee->scan_age != 0 && + time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of age: %ums.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + jiffies_to_msecs(jiffies - + network->last_scanned)); + return 0; + } + + if ((priv->config & CFG_STATIC_CHANNEL) && + (network->channel != priv->channel)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of channel mismatch: %d != %d.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + network->channel, priv->channel); + return 0; + } + + /* Verify privacy compatability */ + if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != + ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of privacy mismatch: %s != %s.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + priv->capability & CAP_PRIVACY_ON ? "on" : + "off", + network->capability & + WLAN_CAPABILITY_PRIVACY ? "on" : "off"); + return 0; + } + + if ((priv->config & CFG_STATIC_BSSID) && + memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of BSSID mismatch: %pM.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv->bssid); + return 0; + } + + /* Filter out any incompatible freq / mode combinations */ + if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of invalid frequency/mode " + "combination.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + /* Filter out invalid channel in current GEO */ + if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of invalid channel in current GEO\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + /* Ensure that the rates supported by the driver are compatible with + * this AP, including verification of basic rates (mandatory) */ + if (!ipw_compatible_rates(priv, network, &rates)) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because configured rate mask excludes " + "AP mandatory rate.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + if (rates.num_rates == 0) { + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of no compatible rates.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 0; + } + + /* TODO: Perform any further minimal comparititive tests. We do not + * want to put too much policy logic here; intelligent scan selection + * should occur within a generic IEEE 802.11 user space tool. */ + + /* Set up 'new' AP to this network */ + ipw_copy_rates(&match->rates, &rates); + match->network = network; + + IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); + + return 1; +} + +static void ipw_adhoc_create(struct ipw_priv *priv, + struct ieee80211_network *network) +{ + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + int i; + + /* + * For the purposes of scanning, we can set our wireless mode + * to trigger scans across combinations of bands, but when it + * comes to creating a new ad-hoc network, we have tell the FW + * exactly which band to use. + * + * We also have the possibility of an invalid channel for the + * chossen band. Attempting to create a new ad-hoc network + * with an invalid channel for wireless mode will trigger a + * FW fatal error. + * + */ + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + case IEEE80211_52GHZ_BAND: + network->mode = IEEE_A; + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + BUG_ON(i == -1); + if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + IPW_WARNING("Overriding invalid channel\n"); + priv->channel = geo->a[0].channel; + } + break; + + case IEEE80211_24GHZ_BAND: + if (priv->ieee->mode & IEEE_G) + network->mode = IEEE_G; + else + network->mode = IEEE_B; + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + BUG_ON(i == -1); + if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + IPW_WARNING("Overriding invalid channel\n"); + priv->channel = geo->bg[0].channel; + } + break; + + default: + IPW_WARNING("Overriding invalid channel\n"); + if (priv->ieee->mode & IEEE_A) { + network->mode = IEEE_A; + priv->channel = geo->a[0].channel; + } else if (priv->ieee->mode & IEEE_G) { + network->mode = IEEE_G; + priv->channel = geo->bg[0].channel; + } else { + network->mode = IEEE_B; + priv->channel = geo->bg[0].channel; + } + break; + } + + network->channel = priv->channel; + priv->config |= CFG_ADHOC_PERSIST; + ipw_create_bssid(priv, network->bssid); + network->ssid_len = priv->essid_len; + memcpy(network->ssid, priv->essid, priv->essid_len); + memset(&network->stats, 0, sizeof(network->stats)); + network->capability = WLAN_CAPABILITY_IBSS; + if (!(priv->config & CFG_PREAMBLE_LONG)) + network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; + if (priv->capability & CAP_PRIVACY_ON) + network->capability |= WLAN_CAPABILITY_PRIVACY; + network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH); + memcpy(network->rates, priv->rates.supported_rates, network->rates_len); + network->rates_ex_len = priv->rates.num_rates - network->rates_len; + memcpy(network->rates_ex, + &priv->rates.supported_rates[network->rates_len], + network->rates_ex_len); + network->last_scanned = 0; + network->flags = 0; + network->last_associate = 0; + network->time_stamp[0] = 0; + network->time_stamp[1] = 0; + network->beacon_interval = 100; /* Default */ + network->listen_interval = 10; /* Default */ + network->atim_window = 0; /* Default */ + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; +} + +static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index) +{ + struct ipw_tgi_tx_key key; + + if (!(priv->ieee->sec.flags & (1 << index))) + return; + + key.key_id = index; + memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); + key.security_type = type; + key.station_index = 0; /* always 0 for BSS */ + key.flags = 0; + /* 0 for new key; previous value of counter (after fatal error) */ + key.tx_counter[0] = cpu_to_le32(0); + key.tx_counter[1] = cpu_to_le32(0); + + ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key); +} + +static void ipw_send_wep_keys(struct ipw_priv *priv, int type) +{ + struct ipw_wep_key key; + int i; + + key.cmd_id = DINO_CMD_WEP_KEY; + key.seq_num = 0; + + /* Note: AES keys cannot be set for multiple times. + * Only set it at the first time. */ + for (i = 0; i < 4; i++) { + key.key_index = i | type; + if (!(priv->ieee->sec.flags & (1 << i))) { + key.key_size = 0; + continue; + } + + key.key_size = priv->ieee->sec.key_sizes[i]; + memcpy(key.key, priv->ieee->sec.keys[i], key.key_size); + + ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key); + } +} + +static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level) +{ + if (priv->ieee->host_encrypt) + return; + + switch (level) { + case SEC_LEVEL_3: + priv->sys_config.disable_unicast_decryption = 0; + priv->ieee->host_decrypt = 0; + break; + case SEC_LEVEL_2: + priv->sys_config.disable_unicast_decryption = 1; + priv->ieee->host_decrypt = 1; + break; + case SEC_LEVEL_1: + priv->sys_config.disable_unicast_decryption = 0; + priv->ieee->host_decrypt = 0; + break; + case SEC_LEVEL_0: + priv->sys_config.disable_unicast_decryption = 1; + break; + default: + break; + } +} + +static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level) +{ + if (priv->ieee->host_encrypt) + return; + + switch (level) { + case SEC_LEVEL_3: + priv->sys_config.disable_multicast_decryption = 0; + break; + case SEC_LEVEL_2: + priv->sys_config.disable_multicast_decryption = 1; + break; + case SEC_LEVEL_1: + priv->sys_config.disable_multicast_decryption = 0; + break; + case SEC_LEVEL_0: + priv->sys_config.disable_multicast_decryption = 1; + break; + default: + break; + } +} + +static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) +{ + switch (priv->ieee->sec.level) { + case SEC_LEVEL_3: + if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) + ipw_send_tgi_tx_key(priv, + DCT_FLAG_EXT_SECURITY_CCM, + priv->ieee->sec.active_key); + + if (!priv->ieee->host_mc_decrypt) + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); + break; + case SEC_LEVEL_2: + if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) + ipw_send_tgi_tx_key(priv, + DCT_FLAG_EXT_SECURITY_TKIP, + priv->ieee->sec.active_key); + break; + case SEC_LEVEL_1: + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); + ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level); + ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level); + break; + case SEC_LEVEL_0: + default: + break; + } +} + +static void ipw_adhoc_check(void *data) +{ + struct ipw_priv *priv = data; + + if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold && + !(priv->config & CFG_ADHOC_PERSIST)) { + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE | IPW_DL_ASSOC, + "Missed beacon: %d - disassociate\n", + priv->missed_adhoc_beacons); + ipw_remove_current_network(priv); + ipw_disassociate(priv); + return; + } + + queue_delayed_work(priv->workqueue, &priv->adhoc_check, + le16_to_cpu(priv->assoc_request.beacon_interval)); +} + +static void ipw_bg_adhoc_check(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adhoc_check.work); + mutex_lock(&priv->mutex); + ipw_adhoc_check(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_debug_config(struct ipw_priv *priv) +{ + DECLARE_SSID_BUF(ssid); + IPW_DEBUG_INFO("Scan completed, no valid APs matched " + "[CFG 0x%08X]\n", priv->config); + if (priv->config & CFG_STATIC_CHANNEL) + IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel); + else + IPW_DEBUG_INFO("Channel unlocked.\n"); + if (priv->config & CFG_STATIC_ESSID) + IPW_DEBUG_INFO("ESSID locked to '%s'\n", + print_ssid(ssid, priv->essid, priv->essid_len)); + else + IPW_DEBUG_INFO("ESSID unlocked.\n"); + if (priv->config & CFG_STATIC_BSSID) + IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid); + else + IPW_DEBUG_INFO("BSSID unlocked.\n"); + if (priv->capability & CAP_PRIVACY_ON) + IPW_DEBUG_INFO("PRIVACY on\n"); + else + IPW_DEBUG_INFO("PRIVACY off\n"); + IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask); +} + +static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) +{ + /* TODO: Verify that this works... */ + struct ipw_fixed_rate fr = { + .tx_rates = priv->rates_mask + }; + u32 reg; + u16 mask = 0; + + /* Identify 'current FW band' and match it with the fixed + * Tx rates */ + + switch (priv->ieee->freq_band) { + case IEEE80211_52GHZ_BAND: /* A only */ + /* IEEE_A */ + if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { + /* Invalid fixed rate mask */ + IPW_DEBUG_WX + ("invalid fixed rate mask in ipw_set_fixed_rate\n"); + fr.tx_rates = 0; + break; + } + + fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; + break; + + default: /* 2.4Ghz or Mixed */ + /* IEEE_B */ + if (mode == IEEE_B) { + if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { + /* Invalid fixed rate mask */ + IPW_DEBUG_WX + ("invalid fixed rate mask in ipw_set_fixed_rate\n"); + fr.tx_rates = 0; + } + break; + } + + /* IEEE_G */ + if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | + IEEE80211_OFDM_RATES_MASK)) { + /* Invalid fixed rate mask */ + IPW_DEBUG_WX + ("invalid fixed rate mask in ipw_set_fixed_rate\n"); + fr.tx_rates = 0; + break; + } + + if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) { + mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); + fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; + } + + if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) { + mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); + fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; + } + + if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) { + mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); + fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; + } + + fr.tx_rates |= mask; + break; + } + + reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE); + ipw_write_reg32(priv, reg, *(u32 *) & fr); +} + +static void ipw_abort_scan(struct ipw_priv *priv) +{ + int err; + + if (priv->status & STATUS_SCAN_ABORTING) { + IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); + return; + } + priv->status |= STATUS_SCAN_ABORTING; + + err = ipw_send_scan_abort(priv); + if (err) + IPW_DEBUG_HC("Request to abort scan failed.\n"); +} + +static void ipw_add_scan_channels(struct ipw_priv *priv, + struct ipw_scan_request_ext *scan, + int scan_type) +{ + int channel_index = 0; + const struct ieee80211_geo *geo; + int i; + + geo = ieee80211_get_geo(priv->ieee); + + if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { + int start = channel_index; + for (i = 0; i < geo->a_channels; i++) { + if ((priv->status & STATUS_ASSOCIATED) && + geo->a[i].channel == priv->channel) + continue; + channel_index++; + scan->channels_list[channel_index] = geo->a[i].channel; + ipw_set_scan_type(scan, channel_index, + geo->a[i]. + flags & IEEE80211_CH_PASSIVE_ONLY ? + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : + scan_type); + } + + if (start != channel_index) { + scan->channels_list[start] = (u8) (IPW_A_MODE << 6) | + (channel_index - start); + channel_index++; + } + } + + if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { + int start = channel_index; + if (priv->config & CFG_SPEED_SCAN) { + int index; + u8 channels[IEEE80211_24GHZ_CHANNELS] = { + /* nop out the list */ + [0] = 0 + }; + + u8 channel; + while (channel_index < IPW_SCAN_CHANNELS) { + channel = + priv->speed_scan[priv->speed_scan_pos]; + if (channel == 0) { + priv->speed_scan_pos = 0; + channel = priv->speed_scan[0]; + } + if ((priv->status & STATUS_ASSOCIATED) && + channel == priv->channel) { + priv->speed_scan_pos++; + continue; + } + + /* If this channel has already been + * added in scan, break from loop + * and this will be the first channel + * in the next scan. + */ + if (channels[channel - 1] != 0) + break; + + channels[channel - 1] = 1; + priv->speed_scan_pos++; + channel_index++; + scan->channels_list[channel_index] = channel; + index = + ieee80211_channel_to_index(priv->ieee, channel); + ipw_set_scan_type(scan, channel_index, + geo->bg[index]. + flags & + IEEE80211_CH_PASSIVE_ONLY ? + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN + : scan_type); + } + } else { + for (i = 0; i < geo->bg_channels; i++) { + if ((priv->status & STATUS_ASSOCIATED) && + geo->bg[i].channel == priv->channel) + continue; + channel_index++; + scan->channels_list[channel_index] = + geo->bg[i].channel; + ipw_set_scan_type(scan, channel_index, + geo->bg[i]. + flags & + IEEE80211_CH_PASSIVE_ONLY ? + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN + : scan_type); + } + } + + if (start != channel_index) { + scan->channels_list[start] = (u8) (IPW_B_MODE << 6) | + (channel_index - start); + } + } +} + +static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) +{ + struct ipw_scan_request_ext scan; + int err = 0, scan_type; + + if (!(priv->status & STATUS_INIT) || + (priv->status & STATUS_EXIT_PENDING)) + return 0; + + mutex_lock(&priv->mutex); + + if (direct && (priv->direct_scan_ssid_len == 0)) { + IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n"); + priv->status &= ~STATUS_DIRECT_SCAN_PENDING; + goto done; + } + + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; + goto done; + } + + if (!(priv->status & STATUS_SCAN_FORCED) && + priv->status & STATUS_SCAN_ABORTING) { + IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; + goto done; + } + + if (priv->status & STATUS_RF_KILL_MASK) { + IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; + goto done; + } + + memset(&scan, 0, sizeof(scan)); + scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); + + if (type == IW_SCAN_TYPE_PASSIVE) { + IPW_DEBUG_WX("use passive scanning\n"); + scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(120); + ipw_add_scan_channels(priv, &scan, scan_type); + goto send_request; + } + + /* Use active scan by default. */ + if (priv->config & CFG_SPEED_SCAN) + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = + cpu_to_le16(30); + else + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = + cpu_to_le16(20); + + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = + cpu_to_le16(20); + + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); + +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + u8 channel; + u8 band = 0; + + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + case IEEE80211_52GHZ_BAND: + band = (u8) (IPW_A_MODE << 6) | 1; + channel = priv->channel; + break; + + case IEEE80211_24GHZ_BAND: + band = (u8) (IPW_B_MODE << 6) | 1; + channel = priv->channel; + break; + + default: + band = (u8) (IPW_B_MODE << 6) | 1; + channel = 9; + break; + } + + scan.channels_list[0] = band; + scan.channels_list[1] = channel; + ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); + + /* NOTE: The card will sit on this channel for this time + * period. Scan aborts are timing sensitive and frequently + * result in firmware restarts. As such, it is best to + * set a small dwell_time here and just keep re-issuing + * scans. Otherwise fast channel hopping will not actually + * hop channels. + * + * TODO: Move SPEED SCAN support to all modes and bands */ + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(2000); + } else { +#endif /* CONFIG_IPW2200_MONITOR */ + /* Honor direct scans first, otherwise if we are roaming make + * this a direct scan for the current network. Finally, + * ensure that every other scan is a fast channel hop scan */ + if (direct) { + err = ipw_send_ssid(priv, priv->direct_scan_ssid, + priv->direct_scan_ssid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command " + "failed\n"); + goto done; + } + + scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; + } else if ((priv->status & STATUS_ROAMING) + || (!(priv->status & STATUS_ASSOCIATED) + && (priv->config & CFG_STATIC_ESSID) + && (le32_to_cpu(scan.full_scan_index) % 2))) { + err = ipw_send_ssid(priv, priv->essid, priv->essid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command " + "failed.\n"); + goto done; + } + + scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; + } else + scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; + + ipw_add_scan_channels(priv, &scan, scan_type); +#ifdef CONFIG_IPW2200_MONITOR + } +#endif + +send_request: + err = ipw_send_scan_request_ext(priv, &scan); + if (err) { + IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); + goto done; + } + + priv->status |= STATUS_SCANNING; + if (direct) { + priv->status &= ~STATUS_DIRECT_SCAN_PENDING; + priv->direct_scan_ssid_len = 0; + } else + priv->status &= ~STATUS_SCAN_PENDING; + + queue_delayed_work(priv->workqueue, &priv->scan_check, + IPW_SCAN_CHECK_WATCHDOG); +done: + mutex_unlock(&priv->mutex); + return err; +} + +static void ipw_request_passive_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_passive_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0); +} + +static void ipw_request_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0); +} + +static void ipw_request_direct_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_direct_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1); +} + +static void ipw_bg_abort_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, abort_scan); + mutex_lock(&priv->mutex); + ipw_abort_scan(priv); + mutex_unlock(&priv->mutex); +} + +static int ipw_wpa_enable(struct ipw_priv *priv, int value) +{ + /* This is called when wpa_supplicant loads and closes the driver + * interface. */ + priv->ieee->wpa_enabled = value; + return 0; +} + +static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) +{ + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_security sec = { + .flags = SEC_AUTH_MODE, + }; + int ret = 0; + + if (value & IW_AUTH_ALG_SHARED_KEY) { + sec.auth_mode = WLAN_AUTH_SHARED_KEY; + ieee->open_wep = 0; + } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { + sec.auth_mode = WLAN_AUTH_OPEN; + ieee->open_wep = 1; + } else if (value & IW_AUTH_ALG_LEAP) { + sec.auth_mode = WLAN_AUTH_LEAP; + ieee->open_wep = 1; + } else + return -EINVAL; + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + else + ret = -EOPNOTSUPP; + + return ret; +} + +static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, + int wpa_ie_len) +{ + /* make sure WPA is enabled */ + ipw_wpa_enable(priv, 1); +} + +static int ipw_set_rsn_capa(struct ipw_priv *priv, + char *capabilities, int length) +{ + IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); + + return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length, + capabilities); +} + +/* + * WE-18 support + */ + +/* SIOCSIWGENIE */ +static int ipw_wx_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + u8 *buf; + int err = 0; + + if (wrqu->data.length > MAX_WPA_IE_LEN || + (wrqu->data.length && extra == NULL)) + return -EINVAL; + + if (wrqu->data.length) { + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto out; + } + + memcpy(buf, extra, wrqu->data.length); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = wrqu->data.length; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); + out: + return err; +} + +/* SIOCGIWGENIE */ +static int ipw_wx_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + int err = 0; + + if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { + wrqu->data.length = 0; + goto out; + } + + if (wrqu->data.length < ieee->wpa_ie_len) { + err = -E2BIG; + goto out; + } + + wrqu->data.length = ieee->wpa_ie_len; + memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); + + out: + return err; +} + +static int wext_cipher2level(int cipher) +{ + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + return SEC_LEVEL_0; + case IW_AUTH_CIPHER_WEP40: + case IW_AUTH_CIPHER_WEP104: + return SEC_LEVEL_1; + case IW_AUTH_CIPHER_TKIP: + return SEC_LEVEL_2; + case IW_AUTH_CIPHER_CCMP: + return SEC_LEVEL_3; + default: + return -1; + } +} + +/* SIOCSIWAUTH */ +static int ipw_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct iw_param *param = &wrqu->param; + struct lib80211_crypt_data *crypt; + unsigned long flags; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + break; + case IW_AUTH_CIPHER_PAIRWISE: + ipw_set_hw_decrypt_unicast(priv, + wext_cipher2level(param->value)); + break; + case IW_AUTH_CIPHER_GROUP: + ipw_set_hw_decrypt_multicast(priv, + wext_cipher2level(param->value)); + break; + case IW_AUTH_KEY_MGMT: + /* + * ipw2200 does not use these parameters + */ + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) + break; + + flags = crypt->ops->get_flags(crypt->priv); + + if (param->value) + flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + else + flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + + crypt->ops->set_flags(flags, crypt->priv); + + break; + + case IW_AUTH_DROP_UNENCRYPTED:{ + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = param->value, + }; + priv->ieee->drop_unencrypted = param->value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!param->value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (priv->ieee->set_security) + priv->ieee->set_security(priv->ieee->dev, &sec); + break; + } + + case IW_AUTH_80211_AUTH_ALG: + ret = ipw_wpa_set_auth_algs(priv, param->value); + break; + + case IW_AUTH_WPA_ENABLED: + ret = ipw_wpa_enable(priv, param->value); + ipw_disassociate(priv); + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = param->value; + break; + + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = param->value; + break; + + default: + return -EOPNOTSUPP; + } + return ret; +} + +/* SIOCGIWAUTH */ +static int ipw_wx_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct lib80211_crypt_data *crypt; + struct iw_param *param = &wrqu->param; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * wpa_supplicant will control these internally + */ + ret = -EOPNOTSUPP; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; + if (!crypt || !crypt->ops->get_flags) + break; + + param->value = (crypt->ops->get_flags(crypt->priv) & + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; + + break; + + case IW_AUTH_DROP_UNENCRYPTED: + param->value = ieee->drop_unencrypted; + break; + + case IW_AUTH_80211_AUTH_ALG: + param->value = ieee->sec.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = ieee->wpa_enabled; + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + param->value = ieee->ieee802_1x; + break; + + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + param->value = ieee->privacy_invoked; + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* SIOCSIWENCODEEXT */ +static int ipw_wx_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + + if (hwcrypto) { + if (ext->alg == IW_ENCODE_ALG_TKIP) { + /* IPW HW can't build TKIP MIC, + host decryption still needed */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + priv->ieee->host_mc_decrypt = 1; + else { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 1; + priv->ieee->host_decrypt = 1; + } + } else { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 0; + priv->ieee->host_decrypt = 0; + priv->ieee->host_mc_decrypt = 0; + } + } + + return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCGIWENCODEEXT */ +static int ipw_wx_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCSIWMLME */ +static int ipw_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + __le16 reason; + + reason = cpu_to_le16(mlme->reason_code); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + /* silently ignore */ + break; + + case IW_MLME_DISASSOC: + ipw_disassociate(priv); + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +#ifdef CONFIG_IPW2200_QOS + +/* QoS */ +/* +* get the modulation type of the current network or +* the card current mode +*/ +static u8 ipw_qos_current_mode(struct ipw_priv * priv) +{ + u8 mode = 0; + + if (priv->status & STATUS_ASSOCIATED) { + unsigned long flags; + + spin_lock_irqsave(&priv->ieee->lock, flags); + mode = priv->assoc_network->mode; + spin_unlock_irqrestore(&priv->ieee->lock, flags); + } else { + mode = priv->ieee->mode; + } + IPW_DEBUG_QOS("QoS network/card mode %d \n", mode); + return mode; +} + +/* +* Handle management frame beacon and probe response +*/ +static int ipw_qos_handle_probe_response(struct ipw_priv *priv, + int active_network, + struct ieee80211_network *network) +{ + u32 size = sizeof(struct ieee80211_qos_parameters); + + if (network->capability & WLAN_CAPABILITY_IBSS) + network->qos_data.active = network->qos_data.supported; + + if (network->flags & NETWORK_HAS_QOS_MASK) { + if (active_network && + (network->flags & NETWORK_HAS_QOS_PARAMETERS)) + network->qos_data.active = network->qos_data.supported; + + if ((network->qos_data.active == 1) && (active_network == 1) && + (network->flags & NETWORK_HAS_QOS_PARAMETERS) && + (network->qos_data.old_param_count != + network->qos_data.param_count)) { + network->qos_data.old_param_count = + network->qos_data.param_count; + schedule_work(&priv->qos_activate); + IPW_DEBUG_QOS("QoS parameters change call " + "qos_activate\n"); + } + } else { + if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) + memcpy(&network->qos_data.parameters, + &def_parameters_CCK, size); + else + memcpy(&network->qos_data.parameters, + &def_parameters_OFDM, size); + + if ((network->qos_data.active == 1) && (active_network == 1)) { + IPW_DEBUG_QOS("QoS was disabled call qos_activate \n"); + schedule_work(&priv->qos_activate); + } + + network->qos_data.active = 0; + network->qos_data.supported = 0; + } + if ((priv->status & STATUS_ASSOCIATED) && + (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { + if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) + if (network->capability & WLAN_CAPABILITY_IBSS) + if ((network->ssid_len == + priv->assoc_network->ssid_len) && + !memcmp(network->ssid, + priv->assoc_network->ssid, + network->ssid_len)) { + queue_work(priv->workqueue, + &priv->merge_networks); + } + } + + return 0; +} + +/* +* This function set up the firmware to support QoS. It sends +* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO +*/ +static int ipw_qos_activate(struct ipw_priv *priv, + struct ieee80211_qos_data *qos_network_data) +{ + int err; + struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS]; + struct ieee80211_qos_parameters *active_one = NULL; + u32 size = sizeof(struct ieee80211_qos_parameters); + u32 burst_duration; + int i; + u8 type; + + type = ipw_qos_current_mode(priv); + + active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]); + memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size); + active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]); + memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size); + + if (qos_network_data == NULL) { + if (type == IEEE_B) { + IPW_DEBUG_QOS("QoS activate network mode %d\n", type); + active_one = &def_parameters_CCK; + } else + active_one = &def_parameters_OFDM; + + memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); + burst_duration = ipw_qos_get_burst_duration(priv); + for (i = 0; i < QOS_QUEUE_NUM; i++) + qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] = + cpu_to_le16(burst_duration); + } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + if (type == IEEE_B) { + IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", + type); + if (priv->qos_data.qos_enable == 0) + active_one = &def_parameters_CCK; + else + active_one = priv->qos_data.def_qos_parm_CCK; + } else { + if (priv->qos_data.qos_enable == 0) + active_one = &def_parameters_OFDM; + else + active_one = priv->qos_data.def_qos_parm_OFDM; + } + memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); + } else { + unsigned long flags; + int active; + + spin_lock_irqsave(&priv->ieee->lock, flags); + active_one = &(qos_network_data->parameters); + qos_network_data->old_param_count = + qos_network_data->param_count; + memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); + active = qos_network_data->supported; + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + if (active == 0) { + burst_duration = ipw_qos_get_burst_duration(priv); + for (i = 0; i < QOS_QUEUE_NUM; i++) + qos_parameters[QOS_PARAM_SET_ACTIVE]. + tx_op_limit[i] = cpu_to_le16(burst_duration); + } + } + + IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); + err = ipw_send_qos_params_command(priv, + (struct ieee80211_qos_parameters *) + &(qos_parameters[0])); + if (err) + IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); + + return err; +} + +/* +* send IPW_CMD_WME_INFO to the firmware +*/ +static int ipw_qos_set_info_element(struct ipw_priv *priv) +{ + int ret = 0; + struct ieee80211_qos_information_element qos_info; + + if (priv == NULL) + return -1; + + qos_info.elementID = QOS_ELEMENT_ID; + qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2; + + qos_info.version = QOS_VERSION_1; + qos_info.ac_info = 0; + + memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN); + qos_info.qui_type = QOS_OUI_TYPE; + qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE; + + ret = ipw_send_qos_info_command(priv, &qos_info); + if (ret != 0) { + IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n"); + } + return ret; +} + +/* +* Set the QoS parameter with the association request structure +*/ +static int ipw_qos_association(struct ipw_priv *priv, + struct ieee80211_network *network) +{ + int err = 0; + struct ieee80211_qos_data *qos_data = NULL; + struct ieee80211_qos_data ibss_data = { + .supported = 1, + .active = 1, + }; + + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS)); + + qos_data = &ibss_data; + break; + + case IW_MODE_INFRA: + qos_data = &network->qos_data; + break; + + default: + BUG(); + break; + } + + err = ipw_qos_activate(priv, qos_data); + if (err) { + priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC; + return err; + } + + if (priv->qos_data.qos_enable && qos_data->supported) { + IPW_DEBUG_QOS("QoS will be enabled for this association\n"); + priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC; + return ipw_qos_set_info_element(priv); + } + + return 0; +} + +/* +* handling the beaconing responses. if we get different QoS setting +* off the network from the associated setting, adjust the QoS +* setting +*/ +static int ipw_qos_association_resp(struct ipw_priv *priv, + struct ieee80211_network *network) +{ + int ret = 0; + unsigned long flags; + u32 size = sizeof(struct ieee80211_qos_parameters); + int set_qos_param = 0; + + if ((priv == NULL) || (network == NULL) || + (priv->assoc_network == NULL)) + return ret; + + if (!(priv->status & STATUS_ASSOCIATED)) + return ret; + + if ((priv->ieee->iw_mode != IW_MODE_INFRA)) + return ret; + + spin_lock_irqsave(&priv->ieee->lock, flags); + if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { + memcpy(&priv->assoc_network->qos_data, &network->qos_data, + sizeof(struct ieee80211_qos_data)); + priv->assoc_network->qos_data.active = 1; + if ((network->qos_data.old_param_count != + network->qos_data.param_count)) { + set_qos_param = 1; + network->qos_data.old_param_count = + network->qos_data.param_count; + } + + } else { + if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) + memcpy(&priv->assoc_network->qos_data.parameters, + &def_parameters_CCK, size); + else + memcpy(&priv->assoc_network->qos_data.parameters, + &def_parameters_OFDM, size); + priv->assoc_network->qos_data.active = 0; + priv->assoc_network->qos_data.supported = 0; + set_qos_param = 1; + } + + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + if (set_qos_param == 1) + schedule_work(&priv->qos_activate); + + return ret; +} + +static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) +{ + u32 ret = 0; + + if ((priv == NULL)) + return 0; + + if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) + ret = priv->qos_data.burst_duration_CCK; + else + ret = priv->qos_data.burst_duration_OFDM; + + return ret; +} + +/* +* Initialize the setting of QoS global +*/ +static void ipw_qos_init(struct ipw_priv *priv, int enable, + int burst_enable, u32 burst_duration_CCK, + u32 burst_duration_OFDM) +{ + priv->qos_data.qos_enable = enable; + + if (priv->qos_data.qos_enable) { + priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK; + priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM; + IPW_DEBUG_QOS("QoS is enabled\n"); + } else { + priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK; + priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM; + IPW_DEBUG_QOS("QoS is not enabled\n"); + } + + priv->qos_data.burst_enable = burst_enable; + + if (burst_enable) { + priv->qos_data.burst_duration_CCK = burst_duration_CCK; + priv->qos_data.burst_duration_OFDM = burst_duration_OFDM; + } else { + priv->qos_data.burst_duration_CCK = 0; + priv->qos_data.burst_duration_OFDM = 0; + } +} + +/* +* map the packet priority to the right TX Queue +*/ +static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) +{ + if (priority > 7 || !priv->qos_data.qos_enable) + priority = 0; + + return from_priority_to_tx_queue[priority] - 1; +} + +static int ipw_is_qos_active(struct net_device *dev, + struct sk_buff *skb) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_qos_data *qos_data = NULL; + int active, supported; + u8 *daddr = skb->data + ETH_ALEN; + int unicast = !is_multicast_ether_addr(daddr); + + if (!(priv->status & STATUS_ASSOCIATED)) + return 0; + + qos_data = &priv->assoc_network->qos_data; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + if (unicast == 0) + qos_data->active = 0; + else + qos_data->active = qos_data->supported; + } + active = qos_data->active; + supported = qos_data->supported; + IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " + "unicast %d\n", + priv->qos_data.qos_enable, active, supported, unicast); + if (active && priv->qos_data.qos_enable) + return 1; + + return 0; + +} +/* +* add QoS parameter to the TX command +*/ +static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, + u16 priority, + struct tfd_data *tfd) +{ + int tx_queue_id = 0; + + + tx_queue_id = from_priority_to_tx_queue[priority] - 1; + tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; + + if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) { + tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; + tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK); + } + return 0; +} + +/* +* background support to run QoS activate functionality +*/ +static void ipw_bg_qos_activate(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, qos_activate); + + if (priv == NULL) + return; + + mutex_lock(&priv->mutex); + + if (priv->status & STATUS_ASSOCIATED) + ipw_qos_activate(priv, &(priv->assoc_network->qos_data)); + + mutex_unlock(&priv->mutex); +} + +static int ipw_handle_probe_response(struct net_device *dev, + struct ieee80211_probe_response *resp, + struct ieee80211_network *network) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int active_network = ((priv->status & STATUS_ASSOCIATED) && + (network == priv->assoc_network)); + + ipw_qos_handle_probe_response(priv, active_network, network); + + return 0; +} + +static int ipw_handle_beacon(struct net_device *dev, + struct ieee80211_beacon *resp, + struct ieee80211_network *network) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int active_network = ((priv->status & STATUS_ASSOCIATED) && + (network == priv->assoc_network)); + + ipw_qos_handle_probe_response(priv, active_network, network); + + return 0; +} + +static int ipw_handle_assoc_response(struct net_device *dev, + struct ieee80211_assoc_response *resp, + struct ieee80211_network *network) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + ipw_qos_association_resp(priv, network); + return 0; +} + +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters + *qos_param) +{ + return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, + sizeof(*qos_param) * 3, qos_param); +} + +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element + *qos_param) +{ + return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param), + qos_param); +} + +#endif /* CONFIG_IPW2200_QOS */ + +static int ipw_associate_network(struct ipw_priv *priv, + struct ieee80211_network *network, + struct ipw_supported_rates *rates, int roaming) +{ + int err; + DECLARE_SSID_BUF(ssid); + + if (priv->config & CFG_FIXED_RATE) + ipw_set_fixed_rate(priv, network->mode); + + if (!(priv->config & CFG_STATIC_ESSID)) { + priv->essid_len = min(network->ssid_len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->essid, network->ssid, priv->essid_len); + } + + network->last_associate = jiffies; + + memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); + priv->assoc_request.channel = network->channel; + priv->assoc_request.auth_key = 0; + + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) { + priv->assoc_request.auth_type = AUTH_SHARED_KEY; + priv->assoc_request.auth_key = priv->ieee->sec.active_key; + + if (priv->ieee->sec.level == SEC_LEVEL_1) + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); + + } else if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)) + priv->assoc_request.auth_type = AUTH_LEAP; + else + priv->assoc_request.auth_type = AUTH_OPEN; + + if (priv->ieee->wpa_ie_len) { + priv->assoc_request.policy_support = cpu_to_le16(0x02); /* RSN active */ + ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, + priv->ieee->wpa_ie_len); + } + + /* + * It is valid for our ieee device to support multiple modes, but + * when it comes to associating to a given network we have to choose + * just one mode. + */ + if (network->mode & priv->ieee->mode & IEEE_A) + priv->assoc_request.ieee_mode = IPW_A_MODE; + else if (network->mode & priv->ieee->mode & IEEE_G) + priv->assoc_request.ieee_mode = IPW_G_MODE; + else if (network->mode & priv->ieee->mode & IEEE_B) + priv->assoc_request.ieee_mode = IPW_B_MODE; + + priv->assoc_request.capability = cpu_to_le16(network->capability); + if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + && !(priv->config & CFG_PREAMBLE_LONG)) { + priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE; + } else { + priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE; + + /* Clear the short preamble if we won't be supporting it */ + priv->assoc_request.capability &= + ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); + } + + /* Clear capability bits that aren't used in Ad Hoc */ + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + priv->assoc_request.capability &= + ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); + + IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " + "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", + roaming ? "Rea" : "A", + print_ssid(ssid, priv->essid, priv->essid_len), + network->channel, + ipw_modes[priv->assoc_request.ieee_mode], + rates->num_rates, + (priv->assoc_request.preamble_length == + DCT_FLAG_LONG_PREAMBLE) ? "long" : "short", + network->capability & + WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long", + priv->capability & CAP_PRIVACY_ON ? "on " : "off", + priv->capability & CAP_PRIVACY_ON ? + (priv->capability & CAP_SHARED_KEY ? "(shared)" : + "(open)") : "", + priv->capability & CAP_PRIVACY_ON ? " key=" : "", + priv->capability & CAP_PRIVACY_ON ? + '1' + priv->ieee->sec.active_key : '.', + priv->capability & CAP_PRIVACY_ON ? '.' : ' '); + + priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval); + if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && + (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) { + priv->assoc_request.assoc_type = HC_IBSS_START; + priv->assoc_request.assoc_tsf_msw = 0; + priv->assoc_request.assoc_tsf_lsw = 0; + } else { + if (unlikely(roaming)) + priv->assoc_request.assoc_type = HC_REASSOCIATE; + else + priv->assoc_request.assoc_type = HC_ASSOCIATE; + priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]); + priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]); + } + + memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN); + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); + priv->assoc_request.atim_window = cpu_to_le16(network->atim_window); + } else { + memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN); + priv->assoc_request.atim_window = 0; + } + + priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval); + + err = ipw_send_ssid(priv, priv->essid, priv->essid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); + return err; + } + + rates->ieee_mode = priv->assoc_request.ieee_mode; + rates->purpose = IPW_RATE_CONNECT; + ipw_send_supported_rates(priv, rates); + + if (priv->assoc_request.ieee_mode == IPW_G_MODE) + priv->sys_config.dot11g_auto_detection = 1; + else + priv->sys_config.dot11g_auto_detection = 0; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + priv->sys_config.answer_broadcast_ssid_probe = 1; + else + priv->sys_config.answer_broadcast_ssid_probe = 0; + + err = ipw_send_system_config(priv); + if (err) { + IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); + return err; + } + + IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); + err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM); + if (err) { + IPW_DEBUG_HC("Attempt to send associate command failed.\n"); + return err; + } + + /* + * If preemption is enabled, it is possible for the association + * to complete before we return from ipw_send_associate. Therefore + * we have to be sure and update our priviate data first. + */ + priv->channel = network->channel; + memcpy(priv->bssid, network->bssid, ETH_ALEN); + priv->status |= STATUS_ASSOCIATING; + priv->status &= ~STATUS_SECURITY_UPDATED; + + priv->assoc_network = network; + +#ifdef CONFIG_IPW2200_QOS + ipw_qos_association(priv, network); +#endif + + err = ipw_send_associate(priv, &priv->assoc_request); + if (err) { + IPW_DEBUG_HC("Attempt to send associate command failed.\n"); + return err; + } + + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); + + return 0; +} + +static void ipw_roam(void *data) +{ + struct ipw_priv *priv = data; + struct ieee80211_network *network = NULL; + struct ipw_network_match match = { + .network = priv->assoc_network + }; + + /* The roaming process is as follows: + * + * 1. Missed beacon threshold triggers the roaming process by + * setting the status ROAM bit and requesting a scan. + * 2. When the scan completes, it schedules the ROAM work + * 3. The ROAM work looks at all of the known networks for one that + * is a better network than the currently associated. If none + * found, the ROAM process is over (ROAM bit cleared) + * 4. If a better network is found, a disassociation request is + * sent. + * 5. When the disassociation completes, the roam work is again + * scheduled. The second time through, the driver is no longer + * associated, and the newly selected network is sent an + * association request. + * 6. At this point ,the roaming process is complete and the ROAM + * status bit is cleared. + */ + + /* If we are no longer associated, and the roaming bit is no longer + * set, then we are not actively roaming, so just return */ + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING))) + return; + + if (priv->status & STATUS_ASSOCIATED) { + /* First pass through ROAM process -- look for a better + * network */ + unsigned long flags; + u8 rssi = priv->assoc_network->stats.rssi; + priv->assoc_network->stats.rssi = -128; + spin_lock_irqsave(&priv->ieee->lock, flags); + list_for_each_entry(network, &priv->ieee->network_list, list) { + if (network != priv->assoc_network) + ipw_best_network(priv, &match, network, 1); + } + spin_unlock_irqrestore(&priv->ieee->lock, flags); + priv->assoc_network->stats.rssi = rssi; + + if (match.network == priv->assoc_network) { + IPW_DEBUG_ASSOC("No better APs in this network to " + "roam to.\n"); + priv->status &= ~STATUS_ROAMING; + ipw_debug_config(priv); + return; + } + + ipw_send_disassociate(priv, 1); + priv->assoc_network = match.network; + + return; + } + + /* Second pass through ROAM process -- request association */ + ipw_compatible_rates(priv, priv->assoc_network, &match.rates); + ipw_associate_network(priv, priv->assoc_network, &match.rates, 1); + priv->status &= ~STATUS_ROAMING; +} + +static void ipw_bg_roam(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, roam); + mutex_lock(&priv->mutex); + ipw_roam(priv); + mutex_unlock(&priv->mutex); +} + +static int ipw_associate(void *data) +{ + struct ipw_priv *priv = data; + + struct ieee80211_network *network = NULL; + struct ipw_network_match match = { + .network = NULL + }; + struct ipw_supported_rates *rates; + struct list_head *element; + unsigned long flags; + DECLARE_SSID_BUF(ssid); + + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n"); + return 0; + } + + if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { + IPW_DEBUG_ASSOC("Not attempting association (already in " + "progress)\n"); + return 0; + } + + if (priv->status & STATUS_DISASSOCIATING) { + IPW_DEBUG_ASSOC("Not attempting association (in " + "disassociating)\n "); + queue_work(priv->workqueue, &priv->associate); + return 0; + } + + if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { + IPW_DEBUG_ASSOC("Not attempting association (scanning or not " + "initialized)\n"); + return 0; + } + + if (!(priv->config & CFG_ASSOCIATE) && + !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) { + IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); + return 0; + } + + /* Protect our use of the network_list */ + spin_lock_irqsave(&priv->ieee->lock, flags); + list_for_each_entry(network, &priv->ieee->network_list, list) + ipw_best_network(priv, &match, network, 0); + + network = match.network; + rates = &match.rates; + + if (network == NULL && + priv->ieee->iw_mode == IW_MODE_ADHOC && + priv->config & CFG_ADHOC_CREATE && + priv->config & CFG_STATIC_ESSID && + priv->config & CFG_STATIC_CHANNEL) { + /* Use oldest network if the free list is empty */ + if (list_empty(&priv->ieee->network_free_list)) { + struct ieee80211_network *oldest = NULL; + struct ieee80211_network *target; + + list_for_each_entry(target, &priv->ieee->network_list, list) { + if ((oldest == NULL) || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + /* If there are no more slots, expire the oldest */ + list_del(&oldest->list); + target = oldest; + IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " + "network list.\n", + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); + list_add_tail(&target->list, + &priv->ieee->network_free_list); + } + + element = priv->ieee->network_free_list.next; + network = list_entry(element, struct ieee80211_network, list); + ipw_adhoc_create(priv, network); + rates = &priv->rates; + list_del(element); + list_add_tail(&network->list, &priv->ieee->network_list); + } + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + /* If we reached the end of the list, then we don't have any valid + * matching APs */ + if (!network) { + ipw_debug_config(priv); + + if (!(priv->status & STATUS_SCANNING)) { + if (!(priv->config & CFG_SPEED_SCAN)) + queue_delayed_work(priv->workqueue, + &priv->request_scan, + SCAN_INTERVAL); + else + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); + } + + return 0; + } + + ipw_associate_network(priv, network, rates, 0); + + return 1; +} + +static void ipw_bg_associate(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, associate); + mutex_lock(&priv->mutex); + ipw_associate(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + u16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = le16_to_cpu(hdr->frame_control); + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return; + + fc &= ~IEEE80211_FCTL_PROTECTED; + hdr->frame_control = cpu_to_le16(fc); + switch (priv->ieee->sec.level) { + case SEC_LEVEL_3: + /* Remove CCMP HDR */ + memmove(skb->data + IEEE80211_3ADDR_LEN, + skb->data + IEEE80211_3ADDR_LEN + 8, + skb->len - IEEE80211_3ADDR_LEN - 8); + skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */ + break; + case SEC_LEVEL_2: + break; + case SEC_LEVEL_1: + /* Remove IV */ + memmove(skb->data + IEEE80211_3ADDR_LEN, + skb->data + IEEE80211_3ADDR_LEN + 4, + skb->len - IEEE80211_3ADDR_LEN - 4); + skb_trim(skb, skb->len - 8); /* IV + ICV */ + break; + case SEC_LEVEL_0: + break; + default: + printk(KERN_ERR "Unknow security level %d\n", + priv->ieee->sec.level); + break; + } +} + +static void ipw_handle_data_packet(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct ieee80211_hdr_4addr *hdr; + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; + + /* We received data from the HW, so stop the watchdog */ + priv->net_dev->trans_start = jiffies; + + /* We only process data packets if the + * interface is open */ + if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > + skb_tailroom(rxb->skb))) { + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); + return; + } else if (unlikely(!netif_running(priv->net_dev))) { + priv->ieee->stats.rx_dropped++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + /* Advance skb->data to the start of the actual payload */ + skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data)); + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length)); + + IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ + hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data; + if (priv->ieee->iw_mode != IW_MODE_MONITOR && + (is_multicast_ether_addr(hdr->addr1) ? + !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt)) + ipw_rebuild_decrypted_skb(priv, rxb->skb); + + if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + priv->ieee->stats.rx_errors++; + else { /* ieee80211_rx succeeded, so it now owns the SKB */ + rxb->skb = NULL; + __ipw_led_activity_on(priv); + } +} + +#ifdef CONFIG_IPW2200_RADIOTAP +static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; + struct ipw_rx_frame *frame = &pkt->u.frame; + + /* initial pull of some data */ + u16 received_channel = frame->received_channel; + u8 antennaAndPhy = frame->antennaAndPhy; + s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */ + u16 pktrate = frame->rate; + + /* Magic struct that slots into the radiotap header -- no reason + * to build this manually element by element, we can write it much + * more efficiently than we can parse it. ORDER MATTERS HERE */ + struct ipw_rt_hdr *ipw_rt; + + short len = le16_to_cpu(pkt->u.frame.length); + + /* We received data from the HW, so stop the watchdog */ + priv->net_dev->trans_start = jiffies; + + /* We only process data packets if the + * interface is open */ + if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > + skb_tailroom(rxb->skb))) { + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); + return; + } else if (unlikely(!netif_running(priv->net_dev))) { + priv->ieee->stats.rx_dropped++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use + * that now */ + if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { + /* FIXME: Should alloc bigger skb instead */ + priv->ieee->stats.rx_dropped++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + /* copy the frame itself */ + memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), + rxb->skb->data + IPW_RX_FRAME_SIZE, len); + + /* Zero the radiotap static buffer ... We only need to zero the bytes NOT + * part of our real header, saves a little time. + * + * No longer necessary since we fill in all our data. Purge before merging + * patch officially. + * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, + * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); + */ + + ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; + + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ + ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total header+data */ + + /* Big bitfield of all the fields we provide in radiotap */ + ipw_rt->rt_hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + ipw_rt->rt_flags = 0; + ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 | + frame->parent_tsf[2] << 16 | + frame->parent_tsf[1] << 8 | + frame->parent_tsf[0]); + + /* Convert signal to DBM */ + ipw_rt->rt_dbmsignal = antsignal; + ipw_rt->rt_dbmnoise = frame->noise; + + /* Convert the channel data and set the flags */ + ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); + if (received_channel > 14) { /* 802.11a */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + } else if (antennaAndPhy & 32) { /* 802.11b */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + } else { /* 802.11g */ + ipw_rt->rt_chbitmask = + cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); + } + + /* set the rate in multiples of 500k/s */ + switch (pktrate) { + case IPW_TX_RATE_1MB: + ipw_rt->rt_rate = 2; + break; + case IPW_TX_RATE_2MB: + ipw_rt->rt_rate = 4; + break; + case IPW_TX_RATE_5MB: + ipw_rt->rt_rate = 10; + break; + case IPW_TX_RATE_6MB: + ipw_rt->rt_rate = 12; + break; + case IPW_TX_RATE_9MB: + ipw_rt->rt_rate = 18; + break; + case IPW_TX_RATE_11MB: + ipw_rt->rt_rate = 22; + break; + case IPW_TX_RATE_12MB: + ipw_rt->rt_rate = 24; + break; + case IPW_TX_RATE_18MB: + ipw_rt->rt_rate = 36; + break; + case IPW_TX_RATE_24MB: + ipw_rt->rt_rate = 48; + break; + case IPW_TX_RATE_36MB: + ipw_rt->rt_rate = 72; + break; + case IPW_TX_RATE_48MB: + ipw_rt->rt_rate = 96; + break; + case IPW_TX_RATE_54MB: + ipw_rt->rt_rate = 108; + break; + default: + ipw_rt->rt_rate = 0; + break; + } + + /* antenna number */ + ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */ + + /* set the preamble flag if we have it */ + if ((antennaAndPhy & 64)) + ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr)); + + IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + priv->ieee->stats.rx_errors++; + else { /* ieee80211_rx succeeded, so it now owns the SKB */ + rxb->skb = NULL; + /* no LED during capture */ + } +} +#endif + +#ifdef CONFIG_IPW2200_PROMISCUOUS +#define ieee80211_is_probe_response(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \ + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP ) + +#define ieee80211_is_management(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + +#define ieee80211_is_control(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) + +#define ieee80211_is_data(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) + +#define ieee80211_is_assoc_request(fc) \ + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ) + +#define ieee80211_is_reassoc_request(fc) \ + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + +static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; + struct ipw_rx_frame *frame = &pkt->u.frame; + struct ipw_rt_hdr *ipw_rt; + + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + struct ieee80211_hdr *hdr; + u16 channel = frame->received_channel; + u8 phy_flags = frame->antennaAndPhy; + s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; + s8 noise = frame->noise; + u8 rate = frame->rate; + short len = le16_to_cpu(pkt->u.frame.length); + struct sk_buff *skb; + int hdr_only = 0; + u16 filter = priv->prom_priv->filter; + + /* If the filter is set to not include Rx frames then return */ + if (filter & IPW_PROM_NO_RX) + return; + + /* We received data from the HW, so stop the watchdog */ + priv->prom_net_dev->trans_start = jiffies; + + if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { + priv->prom_priv->ieee->stats.rx_errors++; + IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); + return; + } + + /* We only process data packets if the interface is open */ + if (unlikely(!netif_running(priv->prom_net_dev))) { + priv->prom_priv->ieee->stats.rx_dropped++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use + * that now */ + if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { + /* FIXME: Should alloc bigger skb instead */ + priv->prom_priv->ieee->stats.rx_dropped++; + IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { + if (filter & IPW_PROM_NO_MGMT) + return; + if (filter & IPW_PROM_MGMT_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { + if (filter & IPW_PROM_NO_CTL) + return; + if (filter & IPW_PROM_CTL_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { + if (filter & IPW_PROM_NO_DATA) + return; + if (filter & IPW_PROM_DATA_HEADER_ONLY) + hdr_only = 1; + } + + /* Copy the SKB since this is for the promiscuous side */ + skb = skb_copy(rxb->skb, GFP_ATOMIC); + if (skb == NULL) { + IPW_ERROR("skb_clone failed for promiscuous copy.\n"); + return; + } + + /* copy the frame data to write after where the radiotap header goes */ + ipw_rt = (void *)skb->data; + + if (hdr_only) + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + + memcpy(ipw_rt->payload, hdr, len); + + /* Zero the radiotap static buffer ... We only need to zero the bytes + * NOT part of our real header, saves a little time. + * + * No longer necessary since we fill in all our data. Purge before + * merging patch officially. + * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, + * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); + */ + + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ + ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */ + + /* Set the size of the skb to the size of the frame */ + skb_put(skb, sizeof(*ipw_rt) + len); + + /* Big bitfield of all the fields we provide in radiotap */ + ipw_rt->rt_hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + ipw_rt->rt_flags = 0; + ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 | + frame->parent_tsf[2] << 16 | + frame->parent_tsf[1] << 8 | + frame->parent_tsf[0]); + + /* Convert to DBM */ + ipw_rt->rt_dbmsignal = signal; + ipw_rt->rt_dbmnoise = noise; + + /* Convert the channel data and set the flags */ + ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel)); + if (channel > 14) { /* 802.11a */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + } else if (phy_flags & (1 << 5)) { /* 802.11b */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + } else { /* 802.11g */ + ipw_rt->rt_chbitmask = + cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); + } + + /* set the rate in multiples of 500k/s */ + switch (rate) { + case IPW_TX_RATE_1MB: + ipw_rt->rt_rate = 2; + break; + case IPW_TX_RATE_2MB: + ipw_rt->rt_rate = 4; + break; + case IPW_TX_RATE_5MB: + ipw_rt->rt_rate = 10; + break; + case IPW_TX_RATE_6MB: + ipw_rt->rt_rate = 12; + break; + case IPW_TX_RATE_9MB: + ipw_rt->rt_rate = 18; + break; + case IPW_TX_RATE_11MB: + ipw_rt->rt_rate = 22; + break; + case IPW_TX_RATE_12MB: + ipw_rt->rt_rate = 24; + break; + case IPW_TX_RATE_18MB: + ipw_rt->rt_rate = 36; + break; + case IPW_TX_RATE_24MB: + ipw_rt->rt_rate = 48; + break; + case IPW_TX_RATE_36MB: + ipw_rt->rt_rate = 72; + break; + case IPW_TX_RATE_48MB: + ipw_rt->rt_rate = 96; + break; + case IPW_TX_RATE_54MB: + ipw_rt->rt_rate = 108; + break; + default: + ipw_rt->rt_rate = 0; + break; + } + + /* antenna number */ + ipw_rt->rt_antenna = (phy_flags & 3); + + /* set the preamble flag if we have it */ + if (phy_flags & (1 << 6)) + ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len); + + if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) { + priv->prom_priv->ieee->stats.rx_errors++; + dev_kfree_skb_any(skb); + } +} +#endif + +static int is_network_packet(struct ipw_priv *priv, + struct ieee80211_hdr_4addr *header) +{ + /* Filter incoming packets to determine if they are targetted toward + * this network, discarding packets coming from ourselves */ + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ + /* packets from our adapter are dropped (echo) */ + if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) + return 0; + + /* {broad,multi}cast packets to our BSSID go through */ + if (is_multicast_ether_addr(header->addr1)) + return !memcmp(header->addr3, priv->bssid, ETH_ALEN); + + /* packets to our adapter go through */ + return !memcmp(header->addr1, priv->net_dev->dev_addr, + ETH_ALEN); + + case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */ + /* packets from our adapter are dropped (echo) */ + if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN)) + return 0; + + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !memcmp(header->addr2, priv->bssid, ETH_ALEN); + + /* packets to our adapter go through */ + return !memcmp(header->addr1, priv->net_dev->dev_addr, + ETH_ALEN); + } + + return 1; +} + +#define IPW_PACKET_RETRY_TIME HZ + +static int is_duplicate_packet(struct ipw_priv *priv, + struct ieee80211_hdr_4addr *header) +{ + u16 sc = le16_to_cpu(header->seq_ctl); + u16 seq = WLAN_GET_SEQ_SEQ(sc); + u16 frag = WLAN_GET_SEQ_FRAG(sc); + u16 *last_seq, *last_frag; + unsigned long *last_time; + + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + { + struct list_head *p; + struct ipw_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE; + + __list_for_each(p, &priv->ibss_mac_hash[index]) { + entry = + list_entry(p, struct ipw_ibss_seq, list); + if (!memcmp(entry->mac, mac, ETH_ALEN)) + break; + } + if (p == &priv->ibss_mac_hash[index]) { + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + IPW_ERROR + ("Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num = seq; + entry->frag_num = frag; + entry->packet_time = jiffies; + list_add(&entry->list, + &priv->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num; + last_frag = &entry->frag_num; + last_time = &entry->packet_time; + break; + } + case IW_MODE_INFRA: + last_seq = &priv->last_seq_num; + last_frag = &priv->last_frag_num; + last_time = &priv->last_packet_time; + break; + default: + return 0; + } + if ((*last_seq == seq) && + time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + + drop: + /* Comment this line now since we observed the card receives + * duplicate packets but the FCTL_RETRY bit is not set in the + * IBSS mode with fragmentation enabled. + BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */ + return 1; +} + +static void ipw_handle_mgmt_packet(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct sk_buff *skb = rxb->skb; + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data; + struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *) + (skb->data + IPW_RX_FRAME_SIZE); + + ieee80211_rx_mgt(priv->ieee, header, stats); + + if (priv->ieee->iw_mode == IW_MODE_ADHOC && + ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == + IEEE80211_STYPE_PROBE_RESP) || + (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == + IEEE80211_STYPE_BEACON))) { + if (!memcmp(header->addr3, priv->bssid, ETH_ALEN)) + ipw_add_station(priv, header->addr2); + } + + if (priv->config & CFG_NET_STATS) { + IPW_DEBUG_HC("sending stat packet\n"); + + /* Set the size of the skb to the size of the full + * ipw header and 802.11 frame */ + skb_put(skb, le16_to_cpu(pkt->u.frame.length) + + IPW_RX_FRAME_SIZE); + + /* Advance past the ipw packet header to the 802.11 frame */ + skb_pull(skb, IPW_RX_FRAME_SIZE); + + /* Push the ieee80211_rx_stats before the 802.11 frame */ + memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats)); + + skb->dev = priv->ieee->dev; + + /* Point raw at the ieee80211_stats */ + skb_reset_mac_header(skb); + + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_80211_STATS); + memset(skb->cb, 0, sizeof(rxb->skb->cb)); + netif_rx(skb); + rxb->skb = NULL; + } +} + +/* + * Main entry function for recieving a packet with 80211 headers. This + * should be called when ever the FW has notified us that there is a new + * skb in the recieve queue. + */ +static void ipw_rx(struct ipw_priv *priv) +{ + struct ipw_rx_mem_buffer *rxb; + struct ipw_rx_packet *pkt; + struct ieee80211_hdr_4addr *header; + u32 r, w, i; + u8 network_packet; + u8 fill_rx = 0; + + r = ipw_read32(priv, IPW_RX_READ_INDEX); + w = ipw_read32(priv, IPW_RX_WRITE_INDEX); + i = priv->rxq->read; + + if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; + + while (i != r) { + rxb = priv->rxq->queue[i]; + if (unlikely(rxb == NULL)) { + printk(KERN_CRIT "Queue not allocated!\n"); + break; + } + priv->rxq->queue[i] = NULL; + + pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, + IPW_RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + pkt = (struct ipw_rx_packet *)rxb->skb->data; + IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n", + pkt->header.message_type, + pkt->header.rx_seq_num, pkt->header.control_bits); + + switch (pkt->header.message_type) { + case RX_FRAME_TYPE: /* 802.11 frame */ { + struct ieee80211_rx_stats stats = { + .rssi = pkt->u.frame.rssi_dbm - + IPW_RSSI_TO_DBM, + .signal = + le16_to_cpu(pkt->u.frame.rssi_dbm) - + IPW_RSSI_TO_DBM + 0x100, + .noise = + le16_to_cpu(pkt->u.frame.noise), + .rate = pkt->u.frame.rate, + .mac_time = jiffies, + .received_channel = + pkt->u.frame.received_channel, + .freq = + (pkt->u.frame. + control & (1 << 0)) ? + IEEE80211_24GHZ_BAND : + IEEE80211_52GHZ_BAND, + .len = le16_to_cpu(pkt->u.frame.length), + }; + + if (stats.rssi != 0) + stats.mask |= IEEE80211_STATMASK_RSSI; + if (stats.signal != 0) + stats.mask |= IEEE80211_STATMASK_SIGNAL; + if (stats.noise != 0) + stats.mask |= IEEE80211_STATMASK_NOISE; + if (stats.rate != 0) + stats.mask |= IEEE80211_STATMASK_RATE; + + priv->rx_packets++; + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) + ipw_handle_promiscuous_rx(priv, rxb, &stats); +#endif + +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { +#ifdef CONFIG_IPW2200_RADIOTAP + + ipw_handle_data_packet_monitor(priv, + rxb, + &stats); +#else + ipw_handle_data_packet(priv, rxb, + &stats); +#endif + break; + } +#endif + + header = + (struct ieee80211_hdr_4addr *)(rxb->skb-> + data + + IPW_RX_FRAME_SIZE); + /* TODO: Check Ad-Hoc dest/source and make sure + * that we are actually parsing these packets + * correctly -- we should probably use the + * frame control of the packet and disregard + * the current iw_mode */ + + network_packet = + is_network_packet(priv, header); + if (network_packet && priv->assoc_network) { + priv->assoc_network->stats.rssi = + stats.rssi; + priv->exp_avg_rssi = + exponential_average(priv->exp_avg_rssi, + stats.rssi, DEPTH_RSSI); + } + + IPW_DEBUG_RX("Frame: len=%u\n", + le16_to_cpu(pkt->u.frame.length)); + + if (le16_to_cpu(pkt->u.frame.length) < + ieee80211_get_hdrlen(le16_to_cpu( + header->frame_ctl))) { + IPW_DEBUG_DROP + ("Received packet is too small. " + "Dropping.\n"); + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + break; + } + + switch (WLAN_FC_GET_TYPE + (le16_to_cpu(header->frame_ctl))) { + + case IEEE80211_FTYPE_MGMT: + ipw_handle_mgmt_packet(priv, rxb, + &stats); + break; + + case IEEE80211_FTYPE_CTL: + break; + + case IEEE80211_FTYPE_DATA: + if (unlikely(!network_packet || + is_duplicate_packet(priv, + header))) + { + IPW_DEBUG_DROP("Dropping: " + "%pM, " + "%pM, " + "%pM\n", + header->addr1, + header->addr2, + header->addr3); + break; + } + + ipw_handle_data_packet(priv, rxb, + &stats); + + break; + } + break; + } + + case RX_HOST_NOTIFICATION_TYPE:{ + IPW_DEBUG_RX + ("Notification: subtype=%02X flags=%02X size=%d\n", + pkt->u.notification.subtype, + pkt->u.notification.flags, + le16_to_cpu(pkt->u.notification.size)); + ipw_rx_notification(priv, &pkt->u.notification); + break; + } + + default: + IPW_DEBUG_RX("Bad Rx packet of type %d\n", + pkt->header.message_type); + break; + } + + /* For now we just don't re-use anything. We can tweak this + * later to try and re-use notification packets and SKBs that + * fail to Rx correctly */ + if (rxb->skb != NULL) { + dev_kfree_skb_any(rxb->skb); + rxb->skb = NULL; + } + + pci_unmap_single(priv->pci_dev, rxb->dma_addr, + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &priv->rxq->rx_used); + + i = (i + 1) % RX_QUEUE_SIZE; + + /* If there are a lot of unsued frames, restock the Rx queue + * so the ucode won't assert */ + if (fill_rx) { + priv->rxq->read = i; + ipw_rx_queue_replenish(priv); + } + } + + /* Backtrack one entry */ + priv->rxq->read = i; + ipw_rx_queue_restock(priv); +} + +#define DEFAULT_RTS_THRESHOLD 2304U +#define MIN_RTS_THRESHOLD 1U +#define MAX_RTS_THRESHOLD 2304U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +/** + * ipw_sw_reset + * @option: options to control different reset behaviour + * 0 = reset everything except the 'disable' module_param + * 1 = reset everything and print out driver info (for probe only) + * 2 = reset everything + */ +static int ipw_sw_reset(struct ipw_priv *priv, int option) +{ + int band, modulation; + int old_mode = priv->ieee->iw_mode; + + /* Initialize module parameter values here */ + priv->config = 0; + + /* We default to disabling the LED code as right now it causes + * too many systems to lock up... */ + if (!led) + priv->config |= CFG_NO_LED; + + if (associate) + priv->config |= CFG_ASSOCIATE; + else + IPW_DEBUG_INFO("Auto associate disabled.\n"); + + if (auto_create) + priv->config |= CFG_ADHOC_CREATE; + else + IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); + + priv->config &= ~CFG_STATIC_ESSID; + priv->essid_len = 0; + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + + if (disable && option) { + priv->status |= STATUS_RF_KILL_SW; + IPW_DEBUG_INFO("Radio disabled.\n"); + } + + if (channel != 0) { + priv->config |= CFG_STATIC_CHANNEL; + priv->channel = channel; + IPW_DEBUG_INFO("Bind to static channel %d\n", channel); + /* TODO: Validate that provided channel is in range */ + } +#ifdef CONFIG_IPW2200_QOS + ipw_qos_init(priv, qos_enable, qos_burst_enable, + burst_duration_CCK, burst_duration_OFDM); +#endif /* CONFIG_IPW2200_QOS */ + + switch (mode) { + case 1: + priv->ieee->iw_mode = IW_MODE_ADHOC; + priv->net_dev->type = ARPHRD_ETHER; + + break; +#ifdef CONFIG_IPW2200_MONITOR + case 2: + priv->ieee->iw_mode = IW_MODE_MONITOR; +#ifdef CONFIG_IPW2200_RADIOTAP + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; +#else + priv->net_dev->type = ARPHRD_IEEE80211; +#endif + break; +#endif + default: + case 0: + priv->net_dev->type = ARPHRD_ETHER; + priv->ieee->iw_mode = IW_MODE_INFRA; + break; + } + + if (hwcrypto) { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 0; + priv->ieee->host_decrypt = 0; + priv->ieee->host_mc_decrypt = 0; + } + IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); + + /* IPW2200/2915 is abled to do hardware fragmentation. */ + priv->ieee->host_open_frag = 0; + + if ((priv->pci_dev->device == 0x4223) || + (priv->pci_dev->device == 0x4224)) { + if (option == 1) + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2915ABG Network " + "Connection\n"); + priv->ieee->abg_true = 1; + band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; + modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + priv->adapter = IPW_2915ABG; + priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; + } else { + if (option == 1) + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2200BG Network " + "Connection\n"); + + priv->ieee->abg_true = 0; + band = IEEE80211_24GHZ_BAND; + modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + priv->adapter = IPW_2200BG; + priv->ieee->mode = IEEE_G | IEEE_B; + } + + priv->ieee->freq_band = band; + priv->ieee->modulation = modulation; + + priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; + + priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; + priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; + + priv->rts_threshold = DEFAULT_RTS_THRESHOLD; + priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; + priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; + + /* If power management is turned on, default to AC mode */ + priv->power_mode = IPW_POWER_AC; + priv->tx_power = IPW_TX_POWER_DEFAULT; + + return old_mode == priv->ieee->iw_mode; +} + +/* + * This file defines the Wireless Extension handlers. It does not + * define any methods of hardware manipulation and relies on the + * functions defined in ipw_main to provide the HW interaction. + * + * The exception to this is the use of the ipw_get_ordinal() + * function used to poll the hardware vs. making unecessary calls. + * + */ + +static int ipw_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + if (priv->status & STATUS_RF_KILL_MASK) + strcpy(wrqu->name, "radio off"); + else if (!(priv->status & STATUS_ASSOCIATED)) + strcpy(wrqu->name, "unassociated"); + else + snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", + ipw_modes[priv->assoc_request.ieee_mode]); + IPW_DEBUG_WX("Name: %s\n", wrqu->name); + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_set_channel(struct ipw_priv *priv, u8 channel) +{ + if (channel == 0) { + IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); + priv->config &= ~CFG_STATIC_CHANNEL; + IPW_DEBUG_ASSOC("Attempting to associate with new " + "parameters.\n"); + ipw_associate(priv); + return 0; + } + + priv->config |= CFG_STATIC_CHANNEL; + + if (priv->channel == channel) { + IPW_DEBUG_INFO("Request to set channel to current value (%d)\n", + channel); + return 0; + } + + IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); + priv->channel = channel; + +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + int i; + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_SCAN("Scan abort triggered due to " + "channel change.\n"); + ipw_abort_scan(priv); + } + + for (i = 1000; i && (priv->status & STATUS_SCANNING); i--) + udelay(10); + + if (priv->status & STATUS_SCANNING) + IPW_DEBUG_SCAN("Still scanning...\n"); + else + IPW_DEBUG_SCAN("Took %dms to abort current scan\n", + 1000 - i); + + return 0; + } +#endif /* CONFIG_IPW2200_MONITOR */ + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + + return 0; +} + +static int ipw_wx_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + struct iw_freq *fwrq = &wrqu->freq; + int ret = 0, i; + u8 channel, flags; + int band; + + if (fwrq->m == 0) { + IPW_DEBUG_WX("SET Freq/Channel -> any\n"); + mutex_lock(&priv->mutex); + ret = ipw_set_channel(priv, 0); + mutex_unlock(&priv->mutex); + return ret; + } + /* if setting by freq convert to channel */ + if (fwrq->e == 1) { + channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); + if (channel == 0) + return -EINVAL; + } else + channel = fwrq->m; + + if (!(band = ieee80211_is_valid_channel(priv->ieee, channel))) + return -EINVAL; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + i = ieee80211_channel_to_index(priv->ieee, channel); + if (i == -1) + return -EINVAL; + + flags = (band == IEEE80211_24GHZ_BAND) ? + geo->bg[i].flags : geo->a[i].flags; + if (flags & IEEE80211_CH_PASSIVE_ONLY) { + IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); + return -EINVAL; + } + } + + IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); + mutex_lock(&priv->mutex); + ret = ipw_set_channel(priv, channel); + mutex_unlock(&priv->mutex); + return ret; +} + +static int ipw_wx_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + wrqu->freq.e = 0; + + /* If we are associated, trying to associate, or have a statically + * configured CHANNEL then return that; otherwise return ANY */ + mutex_lock(&priv->mutex); + if (priv->config & CFG_STATIC_CHANNEL || + priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) { + int i; + + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + BUG_ON(i == -1); + wrqu->freq.e = 1; + + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + case IEEE80211_52GHZ_BAND: + wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000; + break; + + case IEEE80211_24GHZ_BAND: + wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000; + break; + + default: + BUG(); + } + } else + wrqu->freq.m = 0; + + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); + return 0; +} + +static int ipw_wx_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int err = 0; + + IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); + + switch (wrqu->mode) { +#ifdef CONFIG_IPW2200_MONITOR + case IW_MODE_MONITOR: +#endif + case IW_MODE_ADHOC: + case IW_MODE_INFRA: + break; + case IW_MODE_AUTO: + wrqu->mode = IW_MODE_INFRA; + break; + default: + return -EINVAL; + } + if (wrqu->mode == priv->ieee->iw_mode) + return 0; + + mutex_lock(&priv->mutex); + + ipw_sw_reset(priv, 0); + +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) + priv->net_dev->type = ARPHRD_ETHER; + + if (wrqu->mode == IW_MODE_MONITOR) +#ifdef CONFIG_IPW2200_RADIOTAP + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; +#else + priv->net_dev->type = ARPHRD_IEEE80211; +#endif +#endif /* CONFIG_IPW2200_MONITOR */ + + /* Free the existing firmware and reset the fw_loaded + * flag so ipw_load() will bring in the new firmawre */ + free_firmware(); + + priv->ieee->iw_mode = wrqu->mode; + + queue_work(priv->workqueue, &priv->adapter_restart); + mutex_unlock(&priv->mutex); + return err; +} + +static int ipw_wx_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->mode = priv->ieee->iw_mode; + IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); + mutex_unlock(&priv->mutex); + return 0; +} + +/* Values are in microsecond */ +static const s32 timeout_duration[] = { + 350000, + 250000, + 75000, + 37000, + 25000, +}; + +static const s32 period_duration[] = { + 400000, + 700000, + 1000000, + 1000000, + 1000000 +}; + +static int ipw_wx_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_range *range = (struct iw_range *)extra; + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + int i = 0, j; + + wrqu->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + /* 54Mbs == ~27 Mb/s real (802.11g) */ + range->throughput = 27 * 1000 * 1000; + + range->max_qual.qual = 100; + /* TODO: Find real max RSSI and stick here */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = 7; /* Updated all three */ + + range->avg_qual.qual = 70; + /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ + range->avg_qual.level = 0; /* FIXME to real average level */ + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; /* Updated all three */ + mutex_lock(&priv->mutex); + range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); + + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) * + 500000; + + range->max_rts = DEFAULT_RTS_THRESHOLD; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = WEP_KEYS; + + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 18; + + i = 0; + if (priv->ieee->mode & (IEEE_B | IEEE_G)) { + for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) { + if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && + (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + continue; + + range->freq[i].i = geo->bg[j].channel; + range->freq[i].m = geo->bg[j].freq * 100000; + range->freq[i].e = 1; + i++; + } + } + + if (priv->ieee->mode & IEEE_A) { + for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) { + if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && + (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + continue; + + range->freq[i].i = geo->a[j].channel; + range->freq[i].m = geo->a[j].freq * 100000; + range->freq[i].e = 1; + i++; + } + } + + range->num_channels = i; + range->num_frequency = i; + + mutex_unlock(&priv->mutex); + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + + range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; + + IPW_DEBUG_WX("GET Range\n"); + return 0; +} + +static int ipw_wx_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + static const unsigned char any[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + static const unsigned char off[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + mutex_lock(&priv->mutex); + if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || + !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { + /* we disable mandatory BSSID association */ + IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); + priv->config &= ~CFG_STATIC_BSSID; + IPW_DEBUG_ASSOC("Attempting to associate with new " + "parameters.\n"); + ipw_associate(priv); + mutex_unlock(&priv->mutex); + return 0; + } + + priv->config |= CFG_STATIC_BSSID; + if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { + IPW_DEBUG_WX("BSSID set to current BSSID.\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n", + wrqu->ap_addr.sa_data); + + memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + /* If we are associated, trying to associate, or have a statically + * configured BSSID then return that; otherwise return ANY */ + mutex_lock(&priv->mutex); + if (priv->config & CFG_STATIC_BSSID || + priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); + } else + memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", + wrqu->ap_addr.sa_data); + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int length; + DECLARE_SSID_BUF(ssid); + + mutex_lock(&priv->mutex); + + if (!wrqu->essid.flags) + { + IPW_DEBUG_WX("Setting ESSID to ANY\n"); + ipw_disassociate(priv); + priv->config &= ~CFG_STATIC_ESSID; + ipw_associate(priv); + mutex_unlock(&priv->mutex); + return 0; + } + + length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE); + + priv->config |= CFG_STATIC_ESSID; + + if (priv->essid_len == length && !memcmp(priv->essid, extra, length) + && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { + IPW_DEBUG_WX("ESSID set to current ESSID.\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, extra, length), length); + + priv->essid_len = length; + memcpy(priv->essid, extra, priv->essid_len); + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_get_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); + + /* If we are associated, trying to associate, or have a statically + * configured ESSID then return that; otherwise return ANY */ + mutex_lock(&priv->mutex); + if (priv->config & CFG_STATIC_ESSID || + priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { + IPW_DEBUG_WX("Getting essid: '%s'\n", + print_ssid(ssid, priv->essid, priv->essid_len)); + memcpy(extra, priv->essid, priv->essid_len); + wrqu->essid.length = priv->essid_len; + wrqu->essid.flags = 1; /* active */ + } else { + IPW_DEBUG_WX("Getting essid: ANY\n"); + wrqu->essid.length = 0; + wrqu->essid.flags = 0; /* active */ + } + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + IPW_DEBUG_WX("Setting nick to '%s'\n", extra); + if (wrqu->data.length > IW_ESSID_MAX_SIZE) + return -E2BIG; + mutex_lock(&priv->mutex); + wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); + memset(priv->nick, 0, sizeof(priv->nick)); + memcpy(priv->nick, extra, wrqu->data.length); + IPW_DEBUG_TRACE("<<\n"); + mutex_unlock(&priv->mutex); + return 0; + +} + +static int ipw_wx_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + IPW_DEBUG_WX("Getting nick\n"); + mutex_lock(&priv->mutex); + wrqu->data.length = strlen(priv->nick); + memcpy(extra, priv->nick, wrqu->data.length); + wrqu->data.flags = 1; /* active */ + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int err = 0; + + IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value); + IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value); + mutex_lock(&priv->mutex); + + if (wrqu->sens.fixed == 0) + { + priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; + priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; + goto out; + } + if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) || + (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) { + err = -EINVAL; + goto out; + } + + priv->roaming_threshold = wrqu->sens.value; + priv->disassociate_threshold = 3*wrqu->sens.value; + out: + mutex_unlock(&priv->mutex); + return err; +} + +static int ipw_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->sens.fixed = 1; + wrqu->sens.value = priv->roaming_threshold; + mutex_unlock(&priv->mutex); + + IPW_DEBUG_WX("GET roaming threshold -> %s %d \n", + wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); + + return 0; +} + +static int ipw_wx_set_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* TODO: We should use semaphores or locks for access to priv */ + struct ipw_priv *priv = ieee80211_priv(dev); + u32 target_rate = wrqu->bitrate.value; + u32 fixed, mask; + + /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */ + /* value = X, fixed = 1 means only rate X */ + /* value = X, fixed = 0 means all rates lower equal X */ + + if (target_rate == -1) { + fixed = 0; + mask = IEEE80211_DEFAULT_RATES_MASK; + /* Now we should reassociate */ + goto apply; + } + + mask = 0; + fixed = wrqu->bitrate.fixed; + + if (target_rate == 1000000 || !fixed) + mask |= IEEE80211_CCK_RATE_1MB_MASK; + if (target_rate == 1000000) + goto apply; + + if (target_rate == 2000000 || !fixed) + mask |= IEEE80211_CCK_RATE_2MB_MASK; + if (target_rate == 2000000) + goto apply; + + if (target_rate == 5500000 || !fixed) + mask |= IEEE80211_CCK_RATE_5MB_MASK; + if (target_rate == 5500000) + goto apply; + + if (target_rate == 6000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_6MB_MASK; + if (target_rate == 6000000) + goto apply; + + if (target_rate == 9000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_9MB_MASK; + if (target_rate == 9000000) + goto apply; + + if (target_rate == 11000000 || !fixed) + mask |= IEEE80211_CCK_RATE_11MB_MASK; + if (target_rate == 11000000) + goto apply; + + if (target_rate == 12000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_12MB_MASK; + if (target_rate == 12000000) + goto apply; + + if (target_rate == 18000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_18MB_MASK; + if (target_rate == 18000000) + goto apply; + + if (target_rate == 24000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_24MB_MASK; + if (target_rate == 24000000) + goto apply; + + if (target_rate == 36000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_36MB_MASK; + if (target_rate == 36000000) + goto apply; + + if (target_rate == 48000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_48MB_MASK; + if (target_rate == 48000000) + goto apply; + + if (target_rate == 54000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_54MB_MASK; + if (target_rate == 54000000) + goto apply; + + IPW_DEBUG_WX("invalid rate specified, returning error\n"); + return -EINVAL; + + apply: + IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", + mask, fixed ? "fixed" : "sub-rates"); + mutex_lock(&priv->mutex); + if (mask == IEEE80211_DEFAULT_RATES_MASK) { + priv->config &= ~CFG_FIXED_RATE; + ipw_set_fixed_rate(priv, priv->ieee->mode); + } else + priv->config |= CFG_FIXED_RATE; + + if (priv->rates_mask == mask) { + IPW_DEBUG_WX("Mask set to current mask.\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + priv->rates_mask = mask; + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->bitrate.value = priv->last_rate; + wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0; + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); + return 0; +} + +static int ipw_wx_set_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + if (wrqu->rts.disabled || !wrqu->rts.fixed) + priv->rts_threshold = DEFAULT_RTS_THRESHOLD; + else { + if (wrqu->rts.value < MIN_RTS_THRESHOLD || + wrqu->rts.value > MAX_RTS_THRESHOLD) { + mutex_unlock(&priv->mutex); + return -EINVAL; + } + priv->rts_threshold = wrqu->rts.value; + } + + ipw_send_rts_threshold(priv, priv->rts_threshold); + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); + return 0; +} + +static int ipw_wx_get_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->rts.value = priv->rts_threshold; + wrqu->rts.fixed = 0; /* no auto select */ + wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); + return 0; +} + +static int ipw_wx_set_txpow(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int err = 0; + + mutex_lock(&priv->mutex); + if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { + err = -EINPROGRESS; + goto out; + } + + if (!wrqu->power.fixed) + wrqu->power.value = IPW_TX_POWER_DEFAULT; + + if (wrqu->power.flags != IW_TXPOW_DBM) { + err = -EINVAL; + goto out; + } + + if ((wrqu->power.value > IPW_TX_POWER_MAX) || + (wrqu->power.value < IPW_TX_POWER_MIN)) { + err = -EINVAL; + goto out; + } + + priv->tx_power = wrqu->power.value; + err = ipw_set_tx_power(priv); + out: + mutex_unlock(&priv->mutex); + return err; +} + +static int ipw_wx_get_txpow(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->power.value = priv->tx_power; + wrqu->power.fixed = 1; + wrqu->power.flags = IW_TXPOW_DBM; + wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; + mutex_unlock(&priv->mutex); + + IPW_DEBUG_WX("GET TX Power -> %s %d \n", + wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); + + return 0; +} + +static int ipw_wx_set_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + if (wrqu->frag.disabled || !wrqu->frag.fixed) + priv->ieee->fts = DEFAULT_FTS; + else { + if (wrqu->frag.value < MIN_FRAG_THRESHOLD || + wrqu->frag.value > MAX_FRAG_THRESHOLD) { + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + priv->ieee->fts = wrqu->frag.value & ~0x1; + } + + ipw_send_frag_threshold(priv, wrqu->frag.value); + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); + return 0; +} + +static int ipw_wx_get_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->frag.value = priv->ieee->fts; + wrqu->frag.fixed = 0; /* no auto select */ + wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); + + return 0; +} + +static int ipw_wx_set_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) + return -EINVAL; + + if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) + return 0; + + if (wrqu->retry.value < 0 || wrqu->retry.value >= 255) + return -EINVAL; + + mutex_lock(&priv->mutex); + if (wrqu->retry.flags & IW_RETRY_SHORT) + priv->short_retry_limit = (u8) wrqu->retry.value; + else if (wrqu->retry.flags & IW_RETRY_LONG) + priv->long_retry_limit = (u8) wrqu->retry.value; + else { + priv->short_retry_limit = (u8) wrqu->retry.value; + priv->long_retry_limit = (u8) wrqu->retry.value; + } + + ipw_send_retry_limit(priv, priv->short_retry_limit, + priv->long_retry_limit); + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n", + priv->short_retry_limit, priv->long_retry_limit); + return 0; +} + +static int ipw_wx_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + mutex_lock(&priv->mutex); + wrqu->retry.disabled = 0; + + if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + if (wrqu->retry.flags & IW_RETRY_LONG) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + wrqu->retry.value = priv->long_retry_limit; + } else if (wrqu->retry.flags & IW_RETRY_SHORT) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; + wrqu->retry.value = priv->short_retry_limit; + } else { + wrqu->retry.flags = IW_RETRY_LIMIT; + wrqu->retry.value = priv->short_retry_limit; + } + mutex_unlock(&priv->mutex); + + IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value); + + return 0; +} + +static int ipw_wx_set_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_scan_req *req = (struct iw_scan_req *)extra; + struct delayed_work *work = NULL; + + mutex_lock(&priv->mutex); + + priv->user_requested_scan = 1; + + if (wrqu->data.length == sizeof(struct iw_scan_req)) { + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + int len = min((int)req->essid_len, + (int)sizeof(priv->direct_scan_ssid)); + memcpy(priv->direct_scan_ssid, req->essid, len); + priv->direct_scan_ssid_len = len; + work = &priv->request_direct_scan; + } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { + work = &priv->request_passive_scan; + } + } else { + /* Normal active broadcast scan */ + work = &priv->request_scan; + } + + mutex_unlock(&priv->mutex); + + IPW_DEBUG_WX("Start scan\n"); + + queue_delayed_work(priv->workqueue, work, 0); + + return 0; +} + +static int ipw_wx_get_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); +} + +static int ipw_wx_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int ret; + u32 cap = priv->capability; + + mutex_lock(&priv->mutex); + ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + + /* In IBSS mode, we need to notify the firmware to update + * the beacon info after we changed the capability. */ + if (cap != priv->capability && + priv->ieee->iw_mode == IW_MODE_ADHOC && + priv->status & STATUS_ASSOCIATED) + ipw_disassociate(priv); + + mutex_unlock(&priv->mutex); + return ret; +} + +static int ipw_wx_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); +} + +static int ipw_wx_set_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int err; + mutex_lock(&priv->mutex); + if (wrqu->power.disabled) { + priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); + err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); + if (err) { + IPW_DEBUG_WX("failed setting power mode.\n"); + mutex_unlock(&priv->mutex); + return err; + } + IPW_DEBUG_WX("SET Power Management Mode -> off\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + switch (wrqu->power.flags & IW_POWER_MODE) { + case IW_POWER_ON: /* If not specified */ + case IW_POWER_MODE: /* If set all mask */ + case IW_POWER_ALL_R: /* If explicitly state all */ + break; + default: /* Otherwise we don't support it */ + IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", + wrqu->power.flags); + mutex_unlock(&priv->mutex); + return -EOPNOTSUPP; + } + + /* If the user hasn't specified a power management mode yet, default + * to BATTERY */ + if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC) + priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY; + else + priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; + + err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); + if (err) { + IPW_DEBUG_WX("failed setting power mode.\n"); + mutex_unlock(&priv->mutex); + return err; + } + + IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + if (!(priv->power_mode & IPW_POWER_ENABLED)) + wrqu->power.disabled = 1; + else + wrqu->power.disabled = 0; + + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); + + return 0; +} + +static int ipw_wx_set_powermode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int mode = *(int *)extra; + int err; + + mutex_lock(&priv->mutex); + if ((mode < 1) || (mode > IPW_POWER_LIMIT)) + mode = IPW_POWER_AC; + + if (IPW_POWER_LEVEL(priv->power_mode) != mode) { + err = ipw_send_power_mode(priv, mode); + if (err) { + IPW_DEBUG_WX("failed setting power mode.\n"); + mutex_unlock(&priv->mutex); + return err; + } + priv->power_mode = IPW_POWER_ENABLED | mode; + } + mutex_unlock(&priv->mutex); + return 0; +} + +#define MAX_WX_STRING 80 +static int ipw_wx_get_powermode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int level = IPW_POWER_LEVEL(priv->power_mode); + char *p = extra; + + p += snprintf(p, MAX_WX_STRING, "Power save level: %d ", level); + + switch (level) { + case IPW_POWER_AC: + p += snprintf(p, MAX_WX_STRING - (p - extra), "(AC)"); + break; + case IPW_POWER_BATTERY: + p += snprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)"); + break; + default: + p += snprintf(p, MAX_WX_STRING - (p - extra), + "(Timeout %dms, Period %dms)", + timeout_duration[level - 1] / 1000, + period_duration[level - 1] / 1000); + } + + if (!(priv->power_mode & IPW_POWER_ENABLED)) + p += snprintf(p, MAX_WX_STRING - (p - extra), " OFF"); + + wrqu->data.length = p - extra + 1; + + return 0; +} + +static int ipw_wx_set_wireless_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int mode = *(int *)extra; + u8 band = 0, modulation = 0; + + if (mode == 0 || mode & ~IEEE_MODE_MASK) { + IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); + return -EINVAL; + } + mutex_lock(&priv->mutex); + if (priv->adapter == IPW_2915ABG) { + priv->ieee->abg_true = 1; + if (mode & IEEE_A) { + band |= IEEE80211_52GHZ_BAND; + modulation |= IEEE80211_OFDM_MODULATION; + } else + priv->ieee->abg_true = 0; + } else { + if (mode & IEEE_A) { + IPW_WARNING("Attempt to set 2200BG into " + "802.11a mode\n"); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + priv->ieee->abg_true = 0; + } + + if (mode & IEEE_B) { + band |= IEEE80211_24GHZ_BAND; + modulation |= IEEE80211_CCK_MODULATION; + } else + priv->ieee->abg_true = 0; + + if (mode & IEEE_G) { + band |= IEEE80211_24GHZ_BAND; + modulation |= IEEE80211_OFDM_MODULATION; + } else + priv->ieee->abg_true = 0; + + priv->ieee->mode = mode; + priv->ieee->freq_band = band; + priv->ieee->modulation = modulation; + init_supported_rates(priv, &priv->rates); + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n"); + if (!ipw_disassociate(priv)) { + ipw_send_supported_rates(priv, &priv->rates); + ipw_associate(priv); + } + + /* Update the band LEDs */ + ipw_led_band_on(priv); + + IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", + mode & IEEE_A ? 'a' : '.', + mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_get_wireless_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + switch (priv->ieee->mode) { + case IEEE_A: + strncpy(extra, "802.11a (1)", MAX_WX_STRING); + break; + case IEEE_B: + strncpy(extra, "802.11b (2)", MAX_WX_STRING); + break; + case IEEE_A | IEEE_B: + strncpy(extra, "802.11ab (3)", MAX_WX_STRING); + break; + case IEEE_G: + strncpy(extra, "802.11g (4)", MAX_WX_STRING); + break; + case IEEE_A | IEEE_G: + strncpy(extra, "802.11ag (5)", MAX_WX_STRING); + break; + case IEEE_B | IEEE_G: + strncpy(extra, "802.11bg (6)", MAX_WX_STRING); + break; + case IEEE_A | IEEE_B | IEEE_G: + strncpy(extra, "802.11abg (7)", MAX_WX_STRING); + break; + default: + strncpy(extra, "unknown", MAX_WX_STRING); + break; + } + + IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); + + wrqu->data.length = strlen(extra) + 1; + mutex_unlock(&priv->mutex); + + return 0; +} + +static int ipw_wx_set_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int mode = *(int *)extra; + mutex_lock(&priv->mutex); + /* Switching from SHORT -> LONG requires a disassociation */ + if (mode == 1) { + if (!(priv->config & CFG_PREAMBLE_LONG)) { + priv->config |= CFG_PREAMBLE_LONG; + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC + ("[re]association triggered due to preamble change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + } + goto done; + } + + if (mode == 0) { + priv->config &= ~CFG_PREAMBLE_LONG; + goto done; + } + mutex_unlock(&priv->mutex); + return -EINVAL; + + done: + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_get_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + if (priv->config & CFG_PREAMBLE_LONG) + snprintf(wrqu->name, IFNAMSIZ, "long (1)"); + else + snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); + mutex_unlock(&priv->mutex); + return 0; +} + +#ifdef CONFIG_IPW2200_MONITOR +static int ipw_wx_set_monitor(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int *parms = (int *)extra; + int enable = (parms[0] > 0); + mutex_lock(&priv->mutex); + IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); + if (enable) { + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { +#ifdef CONFIG_IPW2200_RADIOTAP + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; +#else + priv->net_dev->type = ARPHRD_IEEE80211; +#endif + queue_work(priv->workqueue, &priv->adapter_restart); + } + + ipw_set_channel(priv, parms[1]); + } else { + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + mutex_unlock(&priv->mutex); + return 0; + } + priv->net_dev->type = ARPHRD_ETHER; + queue_work(priv->workqueue, &priv->adapter_restart); + } + mutex_unlock(&priv->mutex); + return 0; +} + +#endif /* CONFIG_IPW2200_MONITOR */ + +static int ipw_wx_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + IPW_DEBUG_WX("RESET\n"); + queue_work(priv->workqueue, &priv->adapter_restart); + return 0; +} + +static int ipw_wx_sw_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + union iwreq_data wrqu_sec = { + .encoding = { + .flags = IW_ENCODE_DISABLED, + }, + }; + int ret; + + IPW_DEBUG_WX("SW_RESET\n"); + + mutex_lock(&priv->mutex); + + ret = ipw_sw_reset(priv, 2); + if (!ret) { + free_firmware(); + ipw_adapter_restart(priv); + } + + /* The SW reset bit might have been toggled on by the 'disable' + * module parameter, so take appropriate action */ + ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); + + mutex_unlock(&priv->mutex); + ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); + mutex_lock(&priv->mutex); + + if (!(priv->status & STATUS_RF_KILL_MASK)) { + /* Configuration likely changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to sw " + "reset.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + } + + mutex_unlock(&priv->mutex); + + return 0; +} + +/* Rebase the WE IOCTLs to zero for the handler array */ +#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] +static iw_handler ipw_wx_handlers[] = { + IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, + IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, + IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, + IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, + IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, + IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens, + IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens, + IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, + IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, + IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, + IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, + IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, + IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, + IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, + IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, + IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, + IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, + IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, + IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, + IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, + IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, + IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, + IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, + IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, + IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, + IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, + IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, + IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, + IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, + IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, + IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy, + IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, + IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, + IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, + IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie, + IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie, + IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme, + IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth, + IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth, + IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext, + IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext, +}; + +enum { + IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV, + IPW_PRIV_GET_POWER, + IPW_PRIV_SET_MODE, + IPW_PRIV_GET_MODE, + IPW_PRIV_SET_PREAMBLE, + IPW_PRIV_GET_PREAMBLE, + IPW_PRIV_RESET, + IPW_PRIV_SW_RESET, +#ifdef CONFIG_IPW2200_MONITOR + IPW_PRIV_SET_MONITOR, +#endif +}; + +static struct iw_priv_args ipw_priv_args[] = { + { + .cmd = IPW_PRIV_SET_POWER, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_power"}, + { + .cmd = IPW_PRIV_GET_POWER, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_power"}, + { + .cmd = IPW_PRIV_SET_MODE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_mode"}, + { + .cmd = IPW_PRIV_GET_MODE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_mode"}, + { + .cmd = IPW_PRIV_SET_PREAMBLE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_preamble"}, + { + .cmd = IPW_PRIV_GET_PREAMBLE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, + .name = "get_preamble"}, + { + IPW_PRIV_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, + { + IPW_PRIV_SW_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"}, +#ifdef CONFIG_IPW2200_MONITOR + { + IPW_PRIV_SET_MONITOR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, +#endif /* CONFIG_IPW2200_MONITOR */ +}; + +static iw_handler ipw_priv_handler[] = { + ipw_wx_set_powermode, + ipw_wx_get_powermode, + ipw_wx_set_wireless_mode, + ipw_wx_get_wireless_mode, + ipw_wx_set_preamble, + ipw_wx_get_preamble, + ipw_wx_reset, + ipw_wx_sw_reset, +#ifdef CONFIG_IPW2200_MONITOR + ipw_wx_set_monitor, +#endif +}; + +static struct iw_handler_def ipw_wx_handler_def = { + .standard = ipw_wx_handlers, + .num_standard = ARRAY_SIZE(ipw_wx_handlers), + .num_private = ARRAY_SIZE(ipw_priv_handler), + .num_private_args = ARRAY_SIZE(ipw_priv_args), + .private = ipw_priv_handler, + .private_args = ipw_priv_args, + .get_wireless_stats = ipw_get_wireless_stats, +}; + +/* + * Get wireless statistics. + * Called by /proc/net/wireless + * Also called by SIOCGIWSTATS + */ +static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_statistics *wstats; + + wstats = &priv->wstats; + + /* if hw is disabled, then ipw_get_ordinal() can't be called. + * netdev->get_wireless_stats seems to be called before fw is + * initialized. STATUS_ASSOCIATED will only be set if the hw is up + * and associated; if not associcated, the values are all meaningless + * anyway, so set them all to NULL and INVALID */ + if (!(priv->status & STATUS_ASSOCIATED)) { + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = 7; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + return wstats; + } + + wstats->qual.qual = priv->quality; + wstats->qual.level = priv->exp_avg_rssi; + wstats->qual.noise = priv->exp_avg_noise; + wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; + + wstats->miss.beacon = average_value(&priv->average_missed_beacons); + wstats->discard.retries = priv->last_tx_failures; + wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable; + +/* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len)) + goto fail_get_ordinal; + wstats->discard.retries += tx_retry; */ + + return wstats; +} + +/* net device stuff */ + +static void init_sys_config(struct ipw_sys_config *sys_config) +{ + memset(sys_config, 0, sizeof(struct ipw_sys_config)); + sys_config->bt_coexistence = 0; + sys_config->answer_broadcast_ssid_probe = 0; + sys_config->accept_all_data_frames = 0; + sys_config->accept_non_directed_frames = 1; + sys_config->exclude_unicast_unencrypted = 0; + sys_config->disable_unicast_decryption = 1; + sys_config->exclude_multicast_unencrypted = 0; + sys_config->disable_multicast_decryption = 1; + if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B) + antenna = CFG_SYS_ANTENNA_BOTH; + sys_config->antenna_diversity = antenna; + sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */ + sys_config->dot11g_auto_detection = 0; + sys_config->enable_cts_to_self = 0; + sys_config->bt_coexist_collision_thr = 0; + sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */ + sys_config->silence_threshold = 0x1e; +} + +static int ipw_net_open(struct net_device *dev) +{ + IPW_DEBUG_INFO("dev->open\n"); + netif_start_queue(dev); + return 0; +} + +static int ipw_net_stop(struct net_device *dev) +{ + IPW_DEBUG_INFO("dev->close\n"); + netif_stop_queue(dev); + return 0; +} + +/* +todo: + +modify to send one tfd per fragment instead of using chunking. otherwise +we need to heavily modify the ieee80211_skb_to_txb. +*/ + +static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, + int pri) +{ + struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *) + txb->fragments[0]->data; + int i = 0; + struct tfd_frame *tfd; +#ifdef CONFIG_IPW2200_QOS + int tx_id = ipw_get_tx_queue_number(priv, pri); + struct clx2_tx_queue *txq = &priv->txq[tx_id]; +#else + struct clx2_tx_queue *txq = &priv->txq[0]; +#endif + struct clx2_queue *q = &txq->q; + u8 id, hdr_len, unicast; + u16 remaining_bytes; + int fc; + + hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + unicast = !is_multicast_ether_addr(hdr->addr1); + id = ipw_find_station(priv, hdr->addr1); + if (id == IPW_INVALID_STATION) { + id = ipw_add_station(priv, hdr->addr1); + if (id == IPW_INVALID_STATION) { + IPW_WARNING("Attempt to send data to " + "invalid cell: %pM\n", + hdr->addr1); + goto drop; + } + } + break; + + case IW_MODE_INFRA: + default: + unicast = !is_multicast_ether_addr(hdr->addr3); + id = 0; + break; + } + + tfd = &txq->bd[q->first_empty]; + txq->txb[q->first_empty] = txb; + memset(tfd, 0, sizeof(*tfd)); + tfd->u.data.station_number = id; + + tfd->control_flags.message_type = TX_FRAME_TYPE; + tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; + + tfd->u.data.cmd_id = DINO_CMD_TX; + tfd->u.data.len = cpu_to_le16(txb->payload_size); + remaining_bytes = txb->payload_size; + + if (priv->assoc_request.ieee_mode == IPW_B_MODE) + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK; + else + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM; + + if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) + tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; + + fc = le16_to_cpu(hdr->frame_ctl); + hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS); + + memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); + + if (likely(unicast)) + tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD; + + if (txb->encrypted && !priv->ieee->host_encrypt) { + switch (priv->ieee->sec.level) { + case SEC_LEVEL_3: + tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= + cpu_to_le16(IEEE80211_FCTL_PROTECTED); + /* XXX: ACK flag must be set for CCMP even if it + * is a multicast/broadcast packet, because CCMP + * group communication encrypted by GTK is + * actually done by the AP. */ + if (!unicast) + tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD; + + tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM; + tfd->u.data.key_index = 0; + tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE; + break; + case SEC_LEVEL_2: + tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= + cpu_to_le16(IEEE80211_FCTL_PROTECTED); + tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP; + tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE; + break; + case SEC_LEVEL_1: + tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= + cpu_to_le16(IEEE80211_FCTL_PROTECTED); + tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx; + if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <= + 40) + tfd->u.data.key_index |= DCT_WEP_KEY_64Bit; + else + tfd->u.data.key_index |= DCT_WEP_KEY_128Bit; + break; + case SEC_LEVEL_0: + break; + default: + printk(KERN_ERR "Unknow security level %d\n", + priv->ieee->sec.level); + break; + } + } else + /* No hardware encryption */ + tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP; + +#ifdef CONFIG_IPW2200_QOS + if (fc & IEEE80211_STYPE_QOS_DATA) + ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data)); +#endif /* CONFIG_IPW2200_QOS */ + + /* payload */ + tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2), + txb->nr_frags)); + IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n", + txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks)); + for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) { + IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n", + i, le32_to_cpu(tfd->u.data.num_chunks), + txb->fragments[i]->len - hdr_len); + IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n", + i, tfd->u.data.num_chunks, + txb->fragments[i]->len - hdr_len); + printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len, + txb->fragments[i]->len - hdr_len); + + tfd->u.data.chunk_ptr[i] = + cpu_to_le32(pci_map_single + (priv->pci_dev, + txb->fragments[i]->data + hdr_len, + txb->fragments[i]->len - hdr_len, + PCI_DMA_TODEVICE)); + tfd->u.data.chunk_len[i] = + cpu_to_le16(txb->fragments[i]->len - hdr_len); + } + + if (i != txb->nr_frags) { + struct sk_buff *skb; + u16 remaining_bytes = 0; + int j; + + for (j = i; j < txb->nr_frags; j++) + remaining_bytes += txb->fragments[j]->len - hdr_len; + + printk(KERN_INFO "Trying to reallocate for %d bytes\n", + remaining_bytes); + skb = alloc_skb(remaining_bytes, GFP_ATOMIC); + if (skb != NULL) { + tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); + for (j = i; j < txb->nr_frags; j++) { + int size = txb->fragments[j]->len - hdr_len; + + printk(KERN_INFO "Adding frag %d %d...\n", + j, size); + memcpy(skb_put(skb, size), + txb->fragments[j]->data + hdr_len, size); + } + dev_kfree_skb_any(txb->fragments[i]); + txb->fragments[i] = skb; + tfd->u.data.chunk_ptr[i] = + cpu_to_le32(pci_map_single + (priv->pci_dev, skb->data, + remaining_bytes, + PCI_DMA_TODEVICE)); + + le32_add_cpu(&tfd->u.data.num_chunks, 1); + } + } + + /* kick DMA */ + q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); + ipw_write32(priv, q->reg_w, q->first_empty); + + if (ipw_tx_queue_space(q) < q->high_mark) + netif_stop_queue(priv->net_dev); + + return NETDEV_TX_OK; + + drop: + IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); + ieee80211_txb_free(txb); + return NETDEV_TX_OK; +} + +static int ipw_net_is_queue_full(struct net_device *dev, int pri) +{ + struct ipw_priv *priv = ieee80211_priv(dev); +#ifdef CONFIG_IPW2200_QOS + int tx_id = ipw_get_tx_queue_number(priv, pri); + struct clx2_tx_queue *txq = &priv->txq[tx_id]; +#else + struct clx2_tx_queue *txq = &priv->txq[0]; +#endif /* CONFIG_IPW2200_QOS */ + + if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark) + return 1; + + return 0; +} + +#ifdef CONFIG_IPW2200_PROMISCUOUS +static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, + struct ieee80211_txb *txb) +{ + struct ieee80211_rx_stats dummystats; + struct ieee80211_hdr *hdr; + u8 n; + u16 filter = priv->prom_priv->filter; + int hdr_only = 0; + + if (filter & IPW_PROM_NO_TX) + return; + + memset(&dummystats, 0, sizeof(dummystats)); + + /* Filtering of fragment chains is done agains the first fragment */ + hdr = (void *)txb->fragments[0]->data; + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { + if (filter & IPW_PROM_NO_MGMT) + return; + if (filter & IPW_PROM_MGMT_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { + if (filter & IPW_PROM_NO_CTL) + return; + if (filter & IPW_PROM_CTL_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { + if (filter & IPW_PROM_NO_DATA) + return; + if (filter & IPW_PROM_DATA_HEADER_ONLY) + hdr_only = 1; + } + + for(n=0; nnr_frags; ++n) { + struct sk_buff *src = txb->fragments[n]; + struct sk_buff *dst; + struct ieee80211_radiotap_header *rt_hdr; + int len; + + if (hdr_only) { + hdr = (void *)src->data; + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + } else + len = src->len; + + dst = alloc_skb( + len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); + if (!dst) continue; + + rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); + + rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; + rt_hdr->it_pad = 0; + rt_hdr->it_present = 0; /* after all, it's just an idea */ + rt_hdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL); + + *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16( + ieee80211chan2mhz(priv->channel)); + if (priv->channel > 14) /* 802.11a */ + *(__le16*)skb_put(dst, sizeof(u16)) = + cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else if (priv->ieee->mode == IEEE_B) /* 802.11b */ + *(__le16*)skb_put(dst, sizeof(u16)) = + cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ); + else /* 802.11g */ + *(__le16*)skb_put(dst, sizeof(u16)) = + cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_2GHZ); + + rt_hdr->it_len = cpu_to_le16(dst->len); + + skb_copy_from_linear_data(src, skb_put(dst, len), len); + + if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) + dev_kfree_skb_any(dst); + } +} +#endif + +static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, + struct net_device *dev, int pri) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + unsigned long flags; + int ret; + + IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); + spin_lock_irqsave(&priv->lock, flags); + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (rtap_iface && netif_running(priv->prom_net_dev)) + ipw_handle_promiscuous_tx(priv, txb); +#endif + + ret = ipw_tx_skb(priv, txb, pri); + if (ret == NETDEV_TX_OK) + __ipw_led_activity_on(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +static struct net_device_stats *ipw_net_get_stats(struct net_device *dev) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + priv->ieee->stats.tx_packets = priv->tx_packets; + priv->ieee->stats.rx_packets = priv->rx_packets; + return &priv->ieee->stats; +} + +static void ipw_net_set_multicast_list(struct net_device *dev) +{ + +} + +static int ipw_net_set_mac_address(struct net_device *dev, void *p) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + mutex_lock(&priv->mutex); + priv->config |= CFG_CUSTOM_MAC; + memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); + printk(KERN_INFO "%s: Setting MAC to %pM\n", + priv->net_dev->name, priv->mac_addr); + queue_work(priv->workqueue, &priv->adapter_restart); + mutex_unlock(&priv->mutex); + return 0; +} + +static void ipw_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct ipw_priv *p = ieee80211_priv(dev); + char vers[64]; + char date[32]; + u32 len; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + + len = sizeof(vers); + ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len); + len = sizeof(date); + ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len); + + snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)", + vers, date); + strcpy(info->bus_info, pci_name(p->pci_dev)); + info->eedump_len = IPW_EEPROM_IMAGE_SIZE; +} + +static u32 ipw_ethtool_get_link(struct net_device *dev) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + return (priv->status & STATUS_ASSOCIATED) != 0; +} + +static int ipw_ethtool_get_eeprom_len(struct net_device *dev) +{ + return IPW_EEPROM_IMAGE_SIZE; +} + +static int ipw_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 * bytes) +{ + struct ipw_priv *p = ieee80211_priv(dev); + + if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) + return -EINVAL; + mutex_lock(&p->mutex); + memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len); + mutex_unlock(&p->mutex); + return 0; +} + +static int ipw_ethtool_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 * bytes) +{ + struct ipw_priv *p = ieee80211_priv(dev); + int i; + + if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) + return -EINVAL; + mutex_lock(&p->mutex); + memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); + for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) + ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]); + mutex_unlock(&p->mutex); + return 0; +} + +static const struct ethtool_ops ipw_ethtool_ops = { + .get_link = ipw_ethtool_get_link, + .get_drvinfo = ipw_ethtool_get_drvinfo, + .get_eeprom_len = ipw_ethtool_get_eeprom_len, + .get_eeprom = ipw_ethtool_get_eeprom, + .set_eeprom = ipw_ethtool_set_eeprom, +}; + +static irqreturn_t ipw_isr(int irq, void *data) +{ + struct ipw_priv *priv = data; + u32 inta, inta_mask; + + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->irq_lock); + + if (!(priv->status & STATUS_INT_ENABLED)) { + /* IRQ is disabled */ + goto none; + } + + inta = ipw_read32(priv, IPW_INTA_RW); + inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); + + if (inta == 0xFFFFFFFF) { + /* Hardware disappeared */ + IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n"); + goto none; + } + + if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) { + /* Shared interrupt */ + goto none; + } + + /* tell the device to stop sending interrupts */ + __ipw_disable_interrupts(priv); + + /* ack current interrupts */ + inta &= (IPW_INTA_MASK_ALL & inta_mask); + ipw_write32(priv, IPW_INTA_RW, inta); + + /* Cache INTA value for our tasklet */ + priv->isr_inta = inta; + + tasklet_schedule(&priv->irq_tasklet); + + spin_unlock(&priv->irq_lock); + + return IRQ_HANDLED; + none: + spin_unlock(&priv->irq_lock); + return IRQ_NONE; +} + +static void ipw_rf_kill(void *adapter) +{ + struct ipw_priv *priv = adapter; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + if (rf_kill_active(priv)) { + IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n"); + if (priv->workqueue) + queue_delayed_work(priv->workqueue, + &priv->rf_kill, 2 * HZ); + goto exit_unlock; + } + + /* RF Kill is now disabled, so bring the device back up */ + + if (!(priv->status & STATUS_RF_KILL_MASK)) { + IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting " + "device\n"); + + /* we can not do an adapter restart while inside an irq lock */ + queue_work(priv->workqueue, &priv->adapter_restart); + } else + IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " + "enabled\n"); + + exit_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipw_bg_rf_kill(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rf_kill.work); + mutex_lock(&priv->mutex); + ipw_rf_kill(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_link_up(struct ipw_priv *priv) +{ + priv->last_seq_num = -1; + priv->last_frag_num = -1; + priv->last_packet_time = 0; + + netif_carrier_on(priv->net_dev); + + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); + cancel_delayed_work(&priv->scan_event); + ipw_reset_stats(priv); + /* Ensure the rate is updated immediately */ + priv->last_rate = ipw_get_current_rate(priv); + ipw_gather_stats(priv); + ipw_led_link_up(priv); + notify_wx_assoc_event(priv); + + if (priv->config & CFG_BACKGROUND_SCAN) + queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); +} + +static void ipw_bg_link_up(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_up); + mutex_lock(&priv->mutex); + ipw_link_up(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_link_down(struct ipw_priv *priv) +{ + ipw_led_link_down(priv); + netif_carrier_off(priv->net_dev); + notify_wx_assoc_event(priv); + + /* Cancel any queued work ... */ + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); + cancel_delayed_work(&priv->adhoc_check); + cancel_delayed_work(&priv->gather_stats); + + ipw_reset_stats(priv); + + if (!(priv->status & STATUS_EXIT_PENDING)) { + /* Queue up another scan... */ + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); + } else + cancel_delayed_work(&priv->scan_event); +} + +static void ipw_bg_link_down(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_down); + mutex_lock(&priv->mutex); + ipw_link_down(priv); + mutex_unlock(&priv->mutex); +} + +static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) +{ + int ret = 0; + + priv->workqueue = create_workqueue(DRV_NAME); + init_waitqueue_head(&priv->wait_command_queue); + init_waitqueue_head(&priv->wait_state); + + INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check); + INIT_WORK(&priv->associate, ipw_bg_associate); + INIT_WORK(&priv->disassociate, ipw_bg_disassociate); + INIT_WORK(&priv->system_config, ipw_system_config); + INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish); + INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart); + INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill); + INIT_WORK(&priv->up, ipw_bg_up); + INIT_WORK(&priv->down, ipw_bg_down); + INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan); + INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan); + INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event); + INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); + INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); + INIT_WORK(&priv->roam, ipw_bg_roam); + INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check); + INIT_WORK(&priv->link_up, ipw_bg_link_up); + INIT_WORK(&priv->link_down, ipw_bg_link_down); + INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on); + INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off); + INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off); + INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network); + +#ifdef CONFIG_IPW2200_QOS + INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate); +#endif /* CONFIG_IPW2200_QOS */ + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + ipw_irq_tasklet, (unsigned long)priv); + + return ret; +} + +static void shim__set_security(struct net_device *dev, + struct ieee80211_security *sec) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int i; + for (i = 0; i < 4; i++) { + if (sec->flags & (1 << i)) { + priv->ieee->sec.encode_alg[i] = sec->encode_alg[i]; + priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; + if (sec->key_sizes[i] == 0) + priv->ieee->sec.flags &= ~(1 << i); + else { + memcpy(priv->ieee->sec.keys[i], sec->keys[i], + sec->key_sizes[i]); + priv->ieee->sec.flags |= (1 << i); + } + priv->status |= STATUS_SECURITY_UPDATED; + } else if (sec->level != SEC_LEVEL_1) + priv->ieee->sec.flags &= ~(1 << i); + } + + if (sec->flags & SEC_ACTIVE_KEY) { + if (sec->active_key <= 3) { + priv->ieee->sec.active_key = sec->active_key; + priv->ieee->sec.flags |= SEC_ACTIVE_KEY; + } else + priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; + priv->status |= STATUS_SECURITY_UPDATED; + } else + priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; + + if ((sec->flags & SEC_AUTH_MODE) && + (priv->ieee->sec.auth_mode != sec->auth_mode)) { + priv->ieee->sec.auth_mode = sec->auth_mode; + priv->ieee->sec.flags |= SEC_AUTH_MODE; + if (sec->auth_mode == WLAN_AUTH_SHARED_KEY) + priv->capability |= CAP_SHARED_KEY; + else + priv->capability &= ~CAP_SHARED_KEY; + priv->status |= STATUS_SECURITY_UPDATED; + } + + if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) { + priv->ieee->sec.flags |= SEC_ENABLED; + priv->ieee->sec.enabled = sec->enabled; + priv->status |= STATUS_SECURITY_UPDATED; + if (sec->enabled) + priv->capability |= CAP_PRIVACY_ON; + else + priv->capability &= ~CAP_PRIVACY_ON; + } + + if (sec->flags & SEC_ENCRYPT) + priv->ieee->sec.encrypt = sec->encrypt; + + if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { + priv->ieee->sec.level = sec->level; + priv->ieee->sec.flags |= SEC_LEVEL; + priv->status |= STATUS_SECURITY_UPDATED; + } + + if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) + ipw_set_hwcrypto_keys(priv); + + /* To match current functionality of ipw2100 (which works well w/ + * various supplicants, we don't force a disassociate if the + * privacy capability changes ... */ +#if 0 + if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) && + (((priv->assoc_request.capability & + cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) || + (!(priv->assoc_request.capability & + cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) { + IPW_DEBUG_ASSOC("Disassociating due to capability " + "change.\n"); + ipw_disassociate(priv); + } +#endif +} + +static int init_supported_rates(struct ipw_priv *priv, + struct ipw_supported_rates *rates) +{ + /* TODO: Mask out rates based on priv->rates_mask */ + + memset(rates, 0, sizeof(*rates)); + /* configure supported rates */ + switch (priv->ieee->freq_band) { + case IEEE80211_52GHZ_BAND: + rates->ieee_mode = IPW_A_MODE; + rates->purpose = IPW_RATE_CAPABILITIES; + ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, + IEEE80211_OFDM_DEFAULT_RATES_MASK); + break; + + default: /* Mixed or 2.4Ghz */ + rates->ieee_mode = IPW_G_MODE; + rates->purpose = IPW_RATE_CAPABILITIES; + ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION, + IEEE80211_CCK_DEFAULT_RATES_MASK); + if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) { + ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, + IEEE80211_OFDM_DEFAULT_RATES_MASK); + } + break; + } + + return 0; +} + +static int ipw_config(struct ipw_priv *priv) +{ + /* This is only called from ipw_up, which resets/reloads the firmware + so, we don't need to first disable the card before we configure + it */ + if (ipw_set_tx_power(priv)) + goto error; + + /* initialize adapter address */ + if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr)) + goto error; + + /* set basic system config settings */ + init_sys_config(&priv->sys_config); + + /* Support Bluetooth if we have BT h/w on board, and user wants to. + * Does not support BT priority yet (don't abort or defer our Tx) */ + if (bt_coexist) { + unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY]; + + if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG) + priv->sys_config.bt_coexistence + |= CFG_BT_COEXISTENCE_SIGNAL_CHNL; + if (bt_caps & EEPROM_SKU_CAP_BT_OOB) + priv->sys_config.bt_coexistence + |= CFG_BT_COEXISTENCE_OOB; + } + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { + priv->sys_config.accept_all_data_frames = 1; + priv->sys_config.accept_non_directed_frames = 1; + priv->sys_config.accept_all_mgmt_bcpr = 1; + priv->sys_config.accept_all_mgmt_frames = 1; + } +#endif + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + priv->sys_config.answer_broadcast_ssid_probe = 1; + else + priv->sys_config.answer_broadcast_ssid_probe = 0; + + if (ipw_send_system_config(priv)) + goto error; + + init_supported_rates(priv, &priv->rates); + if (ipw_send_supported_rates(priv, &priv->rates)) + goto error; + + /* Set request-to-send threshold */ + if (priv->rts_threshold) { + if (ipw_send_rts_threshold(priv, priv->rts_threshold)) + goto error; + } +#ifdef CONFIG_IPW2200_QOS + IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n"); + ipw_qos_activate(priv, NULL); +#endif /* CONFIG_IPW2200_QOS */ + + if (ipw_set_random_seed(priv)) + goto error; + + /* final state transition to the RUN state */ + if (ipw_send_host_complete(priv)) + goto error; + + priv->status |= STATUS_INIT; + + ipw_led_init(priv); + ipw_led_radio_on(priv); + priv->notif_missed_beacons = 0; + + /* Set hardware WEP key if it is configured. */ + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.level == SEC_LEVEL_1) && + !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) + ipw_set_hwcrypto_keys(priv); + + return 0; + + error: + return -EIO; +} + +/* + * NOTE: + * + * These tables have been tested in conjunction with the + * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters. + * + * Altering this values, using it on other hardware, or in geographies + * not intended for resale of the above mentioned Intel adapters has + * not been tested. + * + * Remember to update the table in README.ipw2200 when changing this + * table. + * + */ +static const struct ieee80211_geo ipw_geos[] = { + { /* Restricted */ + "---", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + }, + + { /* Custom US/Canada */ + "ZZF", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 8, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Rest of World */ + "ZZD", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}}, + }, + + { /* Custom USA & Europe & High */ + "ZZA", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 13, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149}, + {5765, 153}, + {5785, 157}, + {5805, 161}, + {5825, 165}}, + }, + + { /* Custom NA & Europe */ + "ZZB", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 13, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, + {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, + {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, + {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, + {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Custom Japan */ + "ZZC", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 4, + .a = {{5170, 34}, {5190, 38}, + {5210, 42}, {5230, 46}}, + }, + + { /* Custom */ + "ZZM", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + }, + + { /* Europe */ + "ZZE", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}}, + .a_channels = 19, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, + {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, + {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, + {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, + {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, + {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, + {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, + {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, + {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, + {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, + {5700, 140, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Custom Japan */ + "ZZJ", + .bg_channels = 14, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}}, + .a_channels = 4, + .a = {{5170, 34}, {5190, 38}, + {5210, 42}, {5230, 46}}, + }, + + { /* Rest of World */ + "ZZR", + .bg_channels = 14, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY | + IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* High Band */ + "ZZH", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, + {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, + {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + .a_channels = 4, + .a = {{5745, 149}, {5765, 153}, + {5785, 157}, {5805, 161}}, + }, + + { /* Custom Europe */ + "ZZG", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, + {2467, 12}, {2472, 13}}, + .a_channels = 4, + .a = {{5180, 36}, {5200, 40}, + {5220, 44}, {5240, 48}}, + }, + + { /* Europe */ + "ZZK", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, + {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, + {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + .a_channels = 24, + .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, + {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, + {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, + {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, + {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, + {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, + {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, + {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, + {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, + {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, + {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, + {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, + {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, + {5700, 140, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, + {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, + {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, + {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, + {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Europe */ + "ZZL", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 13, + .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, + {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, + {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, + {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, + {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, + {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, + {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, + {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + } +}; + +#define MAX_HW_RESTARTS 5 +static int ipw_up(struct ipw_priv *priv) +{ + int rc, i, j; + + if (priv->status & STATUS_EXIT_PENDING) + return -EIO; + + if (cmdlog && !priv->cmdlog) { + priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog), + GFP_KERNEL); + if (priv->cmdlog == NULL) { + IPW_ERROR("Error allocating %d command log entries.\n", + cmdlog); + return -ENOMEM; + } else { + priv->cmdlog_len = cmdlog; + } + } + + for (i = 0; i < MAX_HW_RESTARTS; i++) { + /* Load the microcode, firmware, and eeprom. + * Also start the clocks. */ + rc = ipw_load(priv); + if (rc) { + IPW_ERROR("Unable to load firmware: %d\n", rc); + return rc; + } + + ipw_init_ordinals(priv); + if (!(priv->config & CFG_CUSTOM_MAC)) + eeprom_parse_mac(priv, priv->mac_addr); + memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); + + for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { + if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], + ipw_geos[j].name, 3)) + break; + } + if (j == ARRAY_SIZE(ipw_geos)) { + IPW_WARNING("SKU [%c%c%c] not recognized.\n", + priv->eeprom[EEPROM_COUNTRY_CODE + 0], + priv->eeprom[EEPROM_COUNTRY_CODE + 1], + priv->eeprom[EEPROM_COUNTRY_CODE + 2]); + j = 0; + } + if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { + IPW_WARNING("Could not set geography."); + return 0; + } + + if (priv->status & STATUS_RF_KILL_SW) { + IPW_WARNING("Radio disabled by module parameter.\n"); + return 0; + } else if (rf_kill_active(priv)) { + IPW_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + 2 * HZ); + return 0; + } + + rc = ipw_config(priv); + if (!rc) { + IPW_DEBUG_INFO("Configured device on count %i\n", i); + + /* If configure to try and auto-associate, kick + * off a scan. */ + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); + + return 0; + } + + IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc); + IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n", + i, MAX_HW_RESTARTS); + + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + ipw_down(priv); + } + + /* tried to restart and config the device for as long as our + * patience could withstand */ + IPW_ERROR("Unable to initialize device after %d attempts.\n", i); + + return -EIO; +} + +static void ipw_bg_up(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, up); + mutex_lock(&priv->mutex); + ipw_up(priv); + mutex_unlock(&priv->mutex); +} + +static void ipw_deinit(struct ipw_priv *priv) +{ + int i; + + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_INFO("Aborting scan during shutdown.\n"); + ipw_abort_scan(priv); + } + + if (priv->status & STATUS_ASSOCIATED) { + IPW_DEBUG_INFO("Disassociating during shutdown.\n"); + ipw_disassociate(priv); + } + + ipw_led_shutdown(priv); + + /* Wait up to 1s for status to change to not scanning and not + * associated (disassociation can take a while for a ful 802.11 + * exchange */ + for (i = 1000; i && (priv->status & + (STATUS_DISASSOCIATING | + STATUS_ASSOCIATED | STATUS_SCANNING)); i--) + udelay(10); + + if (priv->status & (STATUS_DISASSOCIATING | + STATUS_ASSOCIATED | STATUS_SCANNING)) + IPW_DEBUG_INFO("Still associated or scanning...\n"); + else + IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i); + + /* Attempt to disable the card */ + ipw_send_card_disable(priv, 0); + + priv->status &= ~STATUS_INIT; +} + +static void ipw_down(struct ipw_priv *priv) +{ + int exit_pending = priv->status & STATUS_EXIT_PENDING; + + priv->status |= STATUS_EXIT_PENDING; + + if (ipw_is_init(priv)) + ipw_deinit(priv); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + priv->status &= ~STATUS_EXIT_PENDING; + + /* tell the device to stop sending interrupts */ + ipw_disable_interrupts(priv); + + /* Clear all bits but the RF Kill */ + priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING; + netif_carrier_off(priv->net_dev); + + ipw_stop_nic(priv); + + ipw_led_radio_off(priv); +} + +static void ipw_bg_down(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, down); + mutex_lock(&priv->mutex); + ipw_down(priv); + mutex_unlock(&priv->mutex); +} + +/* Called by register_netdev() */ +static int ipw_net_init(struct net_device *dev) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + + if (ipw_up(priv)) { + mutex_unlock(&priv->mutex); + return -EIO; + } + + mutex_unlock(&priv->mutex); + return 0; +} + +/* PCI driver stuff */ +static struct pci_device_id card_ids[] = { + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ + {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ + {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ + {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ + + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, card_ids); + +static struct attribute *ipw_sysfs_entries[] = { + &dev_attr_rf_kill.attr, + &dev_attr_direct_dword.attr, + &dev_attr_indirect_byte.attr, + &dev_attr_indirect_dword.attr, + &dev_attr_mem_gpio_reg.attr, + &dev_attr_command_event_reg.attr, + &dev_attr_nic_type.attr, + &dev_attr_status.attr, + &dev_attr_cfg.attr, + &dev_attr_error.attr, + &dev_attr_event_log.attr, + &dev_attr_cmd_log.attr, + &dev_attr_eeprom_delay.attr, + &dev_attr_ucode_version.attr, + &dev_attr_rtc.attr, + &dev_attr_scan_age.attr, + &dev_attr_led.attr, + &dev_attr_speed_scan.attr, + &dev_attr_net_stats.attr, + &dev_attr_channels.attr, +#ifdef CONFIG_IPW2200_PROMISCUOUS + &dev_attr_rtap_iface.attr, + &dev_attr_rtap_filter.attr, +#endif + NULL +}; + +static struct attribute_group ipw_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = ipw_sysfs_entries, +}; + +#ifdef CONFIG_IPW2200_PROMISCUOUS +static int ipw_prom_open(struct net_device *dev) +{ + struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_priv *priv = prom_priv->priv; + + IPW_DEBUG_INFO("prom dev->open\n"); + netif_carrier_off(dev); + + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + priv->sys_config.accept_all_data_frames = 1; + priv->sys_config.accept_non_directed_frames = 1; + priv->sys_config.accept_all_mgmt_bcpr = 1; + priv->sys_config.accept_all_mgmt_frames = 1; + + ipw_send_system_config(priv); + } + + return 0; +} + +static int ipw_prom_stop(struct net_device *dev) +{ + struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_priv *priv = prom_priv->priv; + + IPW_DEBUG_INFO("prom dev->stop\n"); + + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + priv->sys_config.accept_all_data_frames = 0; + priv->sys_config.accept_non_directed_frames = 0; + priv->sys_config.accept_all_mgmt_bcpr = 0; + priv->sys_config.accept_all_mgmt_frames = 0; + + ipw_send_system_config(priv); + } + + return 0; +} + +static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + IPW_DEBUG_INFO("prom dev->xmit\n"); + return -EOPNOTSUPP; +} + +static struct net_device_stats *ipw_prom_get_stats(struct net_device *dev) +{ + struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + return &prom_priv->ieee->stats; +} + +static int ipw_prom_alloc(struct ipw_priv *priv) +{ + int rc = 0; + + if (priv->prom_net_dev) + return -EPERM; + + priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); + if (priv->prom_net_dev == NULL) + return -ENOMEM; + + priv->prom_priv = ieee80211_priv(priv->prom_net_dev); + priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev); + priv->prom_priv->priv = priv; + + strcpy(priv->prom_net_dev->name, "rtap%d"); + memcpy(priv->prom_net_dev->dev_addr, priv->mac_addr, ETH_ALEN); + + priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; + priv->prom_net_dev->open = ipw_prom_open; + priv->prom_net_dev->stop = ipw_prom_stop; + priv->prom_net_dev->get_stats = ipw_prom_get_stats; + priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit; + + priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR; + SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev); + + rc = register_netdev(priv->prom_net_dev); + if (rc) { + free_ieee80211(priv->prom_net_dev); + priv->prom_net_dev = NULL; + return rc; + } + + return 0; +} + +static void ipw_prom_free(struct ipw_priv *priv) +{ + if (!priv->prom_net_dev) + return; + + unregister_netdev(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev); + + priv->prom_net_dev = NULL; +} + +#endif + + +static int __devinit ipw_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err = 0; + struct net_device *net_dev; + void __iomem *base; + u32 length, val; + struct ipw_priv *priv; + int i; + + net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); + if (net_dev == NULL) { + err = -ENOMEM; + goto out; + } + + priv = ieee80211_priv(net_dev); + priv->ieee = netdev_priv(net_dev); + + priv->net_dev = net_dev; + priv->pci_dev = pdev; + ipw_debug_level = debug; + spin_lock_init(&priv->irq_lock); + spin_lock_init(&priv->lock); + for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + mutex_init(&priv->mutex); + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_free_ieee80211; + } + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); + goto out_pci_disable_device; + } + + pci_set_drvdata(pdev, priv); + + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto out_pci_disable_device; + + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + length = pci_resource_len(pdev, 0); + priv->hw_len = length; + + base = pci_ioremap_bar(pdev, 0); + if (!base) { + err = -ENODEV; + goto out_pci_release_regions; + } + + priv->hw_base = base; + IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length); + IPW_DEBUG_INFO("pci_resource_base = %p\n", base); + + err = ipw_setup_deferred_work(priv); + if (err) { + IPW_ERROR("Unable to setup deferred work\n"); + goto out_iounmap; + } + + ipw_sw_reset(priv, 1); + + err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv); + if (err) { + IPW_ERROR("Error allocating IRQ %d\n", pdev->irq); + goto out_destroy_workqueue; + } + + SET_NETDEV_DEV(net_dev, &pdev->dev); + + mutex_lock(&priv->mutex); + + priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; + priv->ieee->set_security = shim__set_security; + priv->ieee->is_queue_full = ipw_net_is_queue_full; + +#ifdef CONFIG_IPW2200_QOS + priv->ieee->is_qos_active = ipw_is_qos_active; + priv->ieee->handle_probe_response = ipw_handle_beacon; + priv->ieee->handle_beacon = ipw_handle_probe_response; + priv->ieee->handle_assoc_response = ipw_handle_assoc_response; +#endif /* CONFIG_IPW2200_QOS */ + + priv->ieee->perfect_rssi = -20; + priv->ieee->worst_rssi = -85; + + net_dev->open = ipw_net_open; + net_dev->stop = ipw_net_stop; + net_dev->init = ipw_net_init; + net_dev->get_stats = ipw_net_get_stats; + net_dev->set_multicast_list = ipw_net_set_multicast_list; + net_dev->set_mac_address = ipw_net_set_mac_address; + priv->wireless_data.spy_data = &priv->ieee->spy_data; + net_dev->wireless_data = &priv->wireless_data; + net_dev->wireless_handlers = &ipw_wx_handler_def; + net_dev->ethtool_ops = &ipw_ethtool_ops; + net_dev->irq = pdev->irq; + net_dev->base_addr = (unsigned long)priv->hw_base; + net_dev->mem_start = pci_resource_start(pdev, 0); + net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1; + + err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); + if (err) { + IPW_ERROR("failed to create sysfs device attributes\n"); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + + mutex_unlock(&priv->mutex); + err = register_netdev(net_dev); + if (err) { + IPW_ERROR("failed to register network device\n"); + goto out_remove_sysfs; + } + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (rtap_iface) { + err = ipw_prom_alloc(priv); + if (err) { + IPW_ERROR("Failed to register promiscuous network " + "device (error %d).\n", err); + unregister_netdev(priv->net_dev); + goto out_remove_sysfs; + } + } +#endif + + printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg " + "channels, %d 802.11a channels)\n", + priv->ieee->geo.name, priv->ieee->geo.bg_channels, + priv->ieee->geo.a_channels); + + return 0; + + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); + out_release_irq: + free_irq(pdev->irq, priv); + out_destroy_workqueue: + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + out_iounmap: + iounmap(priv->hw_base); + out_pci_release_regions: + pci_release_regions(pdev); + out_pci_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + out_free_ieee80211: + free_ieee80211(priv->net_dev); + out: + return err; +} + +static void __devexit ipw_pci_remove(struct pci_dev *pdev) +{ + struct ipw_priv *priv = pci_get_drvdata(pdev); + struct list_head *p, *q; + int i; + + if (!priv) + return; + + mutex_lock(&priv->mutex); + + priv->status |= STATUS_EXIT_PENDING; + ipw_down(priv); + sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); + + mutex_unlock(&priv->mutex); + + unregister_netdev(priv->net_dev); + + if (priv->rxq) { + ipw_rx_queue_free(priv, priv->rxq); + priv->rxq = NULL; + } + ipw_tx_queue_free(priv); + + if (priv->cmdlog) { + kfree(priv->cmdlog); + priv->cmdlog = NULL; + } + /* ipw_down will ensure that there is no more pending work + * in the workqueue's, so we can safely remove them now. */ + cancel_delayed_work(&priv->adhoc_check); + cancel_delayed_work(&priv->gather_stats); + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); + cancel_delayed_work(&priv->scan_event); + cancel_delayed_work(&priv->rf_kill); + cancel_delayed_work(&priv->scan_check); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + + /* Free MAC hash list for ADHOC */ + for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { + list_del(p); + kfree(list_entry(p, struct ipw_ibss_seq, list)); + } + } + + kfree(priv->error); + priv->error = NULL; + +#ifdef CONFIG_IPW2200_PROMISCUOUS + ipw_prom_free(priv); +#endif + + free_irq(pdev->irq, priv); + iounmap(priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + free_ieee80211(priv->net_dev); + free_firmware(); +} + +#ifdef CONFIG_PM +static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ipw_priv *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->net_dev; + + printk(KERN_INFO "%s: Going into suspend...\n", dev->name); + + /* Take down the device; powers it off, etc. */ + ipw_down(priv); + + /* Remove the PRESENT state of the device */ + netif_device_detach(dev); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int ipw_pci_resume(struct pci_dev *pdev) +{ + struct ipw_priv *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->net_dev; + int err; + u32 val; + + printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); + + pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s: pci_enable_device failed on resume\n", + dev->name); + return err; + } + pci_restore_state(pdev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + /* Set the device back into the PRESENT state; this will also wake + * the queue of needed */ + netif_device_attach(dev); + + /* Bring the device back up */ + queue_work(priv->workqueue, &priv->up); + + return 0; +} +#endif + +static void ipw_pci_shutdown(struct pci_dev *pdev) +{ + struct ipw_priv *priv = pci_get_drvdata(pdev); + + /* Take down the device; powers it off, etc. */ + ipw_down(priv); + + pci_disable_device(pdev); +} + +/* driver initialization stuff */ +static struct pci_driver ipw_driver = { + .name = DRV_NAME, + .id_table = card_ids, + .probe = ipw_pci_probe, + .remove = __devexit_p(ipw_pci_remove), +#ifdef CONFIG_PM + .suspend = ipw_pci_suspend, + .resume = ipw_pci_resume, +#endif + .shutdown = ipw_pci_shutdown, +}; + +static int __init ipw_init(void) +{ + int ret; + + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + ret = pci_register_driver(&ipw_driver); + if (ret) { + IPW_ERROR("Unable to initialize PCI module\n"); + return ret; + } + + ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level); + if (ret) { + IPW_ERROR("Unable to create driver sysfs file\n"); + pci_unregister_driver(&ipw_driver); + return ret; + } + + return ret; +} + +static void __exit ipw_exit(void) +{ + driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level); + pci_unregister_driver(&ipw_driver); +} + +module_param(disable, int, 0444); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); + +module_param(associate, int, 0444); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); + +module_param(auto_create, int, 0444); +MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); + +module_param(led, int, 0444); +MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)"); + +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); + +module_param(channel, int, 0444); +MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); + +#ifdef CONFIG_IPW2200_PROMISCUOUS +module_param(rtap_iface, int, 0444); +MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)"); +#endif + +#ifdef CONFIG_IPW2200_QOS +module_param(qos_enable, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); + +module_param(qos_burst_enable, int, 0444); +MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode"); + +module_param(qos_no_ack_mask, int, 0444); +MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack"); + +module_param(burst_duration_CCK, int, 0444); +MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value"); + +module_param(burst_duration_OFDM, int, 0444); +MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); +#endif /* CONFIG_IPW2200_QOS */ + +#ifdef CONFIG_IPW2200_MONITOR +module_param(mode, int, 0444); +MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); +#else +module_param(mode, int, 0444); +MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); +#endif + +module_param(bt_coexist, int, 0444); +MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)"); + +module_param(hwcrypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)"); + +module_param(cmdlog, int, 0444); +MODULE_PARM_DESC(cmdlog, + "allocate a ring buffer for logging firmware commands"); + +module_param(roaming, int, 0444); +MODULE_PARM_DESC(roaming, "enable roaming support (default on)"); + +module_param(antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)"); + +module_exit(ipw_exit); +module_init(ipw_init); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h new file mode 100644 index 0000000..0a84d52 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -0,0 +1,2011 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ + +#ifndef __ipw2200_h__ +#define __ipw2200_h__ + +#define WEXT_USECHANNELS 1 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define DRV_NAME "ipw2200" + +#include + +/* Authentication and Association States */ +enum connection_manager_assoc_states { + CMAS_INIT = 0, + CMAS_TX_AUTH_SEQ_1, + CMAS_RX_AUTH_SEQ_2, + CMAS_AUTH_SEQ_1_PASS, + CMAS_AUTH_SEQ_1_FAIL, + CMAS_TX_AUTH_SEQ_3, + CMAS_RX_AUTH_SEQ_4, + CMAS_AUTH_SEQ_2_PASS, + CMAS_AUTH_SEQ_2_FAIL, + CMAS_AUTHENTICATED, + CMAS_TX_ASSOC, + CMAS_RX_ASSOC_RESP, + CMAS_ASSOCIATED, + CMAS_LAST +}; + +#define IPW_WAIT (1<<0) +#define IPW_QUIET (1<<1) +#define IPW_ROAMING (1<<2) + +#define IPW_POWER_MODE_CAM 0x00 //(always on) +#define IPW_POWER_INDEX_1 0x01 +#define IPW_POWER_INDEX_2 0x02 +#define IPW_POWER_INDEX_3 0x03 +#define IPW_POWER_INDEX_4 0x04 +#define IPW_POWER_INDEX_5 0x05 +#define IPW_POWER_AC 0x06 +#define IPW_POWER_BATTERY 0x07 +#define IPW_POWER_LIMIT 0x07 +#define IPW_POWER_MASK 0x0F +#define IPW_POWER_ENABLED 0x10 +#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK) + +#define IPW_CMD_HOST_COMPLETE 2 +#define IPW_CMD_POWER_DOWN 4 +#define IPW_CMD_SYSTEM_CONFIG 6 +#define IPW_CMD_MULTICAST_ADDRESS 7 +#define IPW_CMD_SSID 8 +#define IPW_CMD_ADAPTER_ADDRESS 11 +#define IPW_CMD_PORT_TYPE 12 +#define IPW_CMD_RTS_THRESHOLD 15 +#define IPW_CMD_FRAG_THRESHOLD 16 +#define IPW_CMD_POWER_MODE 17 +#define IPW_CMD_WEP_KEY 18 +#define IPW_CMD_TGI_TX_KEY 19 +#define IPW_CMD_SCAN_REQUEST 20 +#define IPW_CMD_ASSOCIATE 21 +#define IPW_CMD_SUPPORTED_RATES 22 +#define IPW_CMD_SCAN_ABORT 23 +#define IPW_CMD_TX_FLUSH 24 +#define IPW_CMD_QOS_PARAMETERS 25 +#define IPW_CMD_SCAN_REQUEST_EXT 26 +#define IPW_CMD_DINO_CONFIG 30 +#define IPW_CMD_RSN_CAPABILITIES 31 +#define IPW_CMD_RX_KEY 32 +#define IPW_CMD_CARD_DISABLE 33 +#define IPW_CMD_SEED_NUMBER 34 +#define IPW_CMD_TX_POWER 35 +#define IPW_CMD_COUNTRY_INFO 36 +#define IPW_CMD_AIRONET_INFO 37 +#define IPW_CMD_AP_TX_POWER 38 +#define IPW_CMD_CCKM_INFO 39 +#define IPW_CMD_CCX_VER_INFO 40 +#define IPW_CMD_SET_CALIBRATION 41 +#define IPW_CMD_SENSITIVITY_CALIB 42 +#define IPW_CMD_RETRY_LIMIT 51 +#define IPW_CMD_IPW_PRE_POWER_DOWN 58 +#define IPW_CMD_VAP_BEACON_TEMPLATE 60 +#define IPW_CMD_VAP_DTIM_PERIOD 61 +#define IPW_CMD_EXT_SUPPORTED_RATES 62 +#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63 +#define IPW_CMD_VAP_QUIET_INTERVALS 64 +#define IPW_CMD_VAP_CHANNEL_SWITCH 65 +#define IPW_CMD_VAP_MANDATORY_CHANNELS 66 +#define IPW_CMD_VAP_CELL_PWR_LIMIT 67 +#define IPW_CMD_VAP_CF_PARAM_SET 68 +#define IPW_CMD_VAP_SET_BEACONING_STATE 69 +#define IPW_CMD_MEASUREMENT 80 +#define IPW_CMD_POWER_CAPABILITY 81 +#define IPW_CMD_SUPPORTED_CHANNELS 82 +#define IPW_CMD_TPC_REPORT 83 +#define IPW_CMD_WME_INFO 84 +#define IPW_CMD_PRODUCTION_COMMAND 85 +#define IPW_CMD_LINKSYS_EOU_INFO 90 + +#define RFD_SIZE 4 +#define NUM_TFD_CHUNKS 6 + +#define TX_QUEUE_SIZE 32 +#define RX_QUEUE_SIZE 32 + +#define DINO_CMD_WEP_KEY 0x08 +#define DINO_CMD_TX 0x0B +#define DCT_ANTENNA_A 0x01 +#define DCT_ANTENNA_B 0x02 + +#define IPW_A_MODE 0 +#define IPW_B_MODE 1 +#define IPW_G_MODE 2 + +/* + * TX Queue Flag Definitions + */ + +/* tx wep key definition */ +#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00 +#define DCT_WEP_KEY_64Bit 0x40 +#define DCT_WEP_KEY_128Bit 0x80 +#define DCT_WEP_KEY_128bitIV 0xC0 +#define DCT_WEP_KEY_SIZE_MASK 0xC0 + +#define DCT_WEP_KEY_INDEX_MASK 0x0F +#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20 + +/* abort attempt if mgmt frame is rx'd */ +#define DCT_FLAG_ABORT_MGMT 0x01 + +/* require CTS */ +#define DCT_FLAG_CTS_REQUIRED 0x02 + +/* use short preamble */ +#define DCT_FLAG_LONG_PREAMBLE 0x00 +#define DCT_FLAG_SHORT_PREAMBLE 0x04 + +/* RTS/CTS first */ +#define DCT_FLAG_RTS_REQD 0x08 + +/* dont calculate duration field */ +#define DCT_FLAG_DUR_SET 0x10 + +/* even if MAC WEP set (allows pre-encrypt) */ +#define DCT_FLAG_NO_WEP 0x20 + +/* overwrite TSF field */ +#define DCT_FLAG_TSF_REQD 0x40 + +/* ACK rx is expected to follow */ +#define DCT_FLAG_ACK_REQD 0x80 + +/* TX flags extension */ +#define DCT_FLAG_EXT_MODE_CCK 0x01 +#define DCT_FLAG_EXT_MODE_OFDM 0x00 + +#define DCT_FLAG_EXT_SECURITY_WEP 0x00 +#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP +#define DCT_FLAG_EXT_SECURITY_CKIP 0x04 +#define DCT_FLAG_EXT_SECURITY_CCM 0x08 +#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C +#define DCT_FLAG_EXT_SECURITY_MASK 0x0C + +#define DCT_FLAG_EXT_QOS_ENABLED 0x10 + +#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00 +#define DCT_FLAG_EXT_HC_SIFS 0x20 +#define DCT_FLAG_EXT_HC_PIFS 0x40 + +#define TX_RX_TYPE_MASK 0xFF +#define TX_FRAME_TYPE 0x00 +#define TX_HOST_COMMAND_TYPE 0x01 +#define RX_FRAME_TYPE 0x09 +#define RX_HOST_NOTIFICATION_TYPE 0x03 +#define RX_HOST_CMD_RESPONSE_TYPE 0x04 +#define RX_TX_FRAME_RESPONSE_TYPE 0x05 +#define TFD_NEED_IRQ_MASK 0x04 + +#define HOST_CMD_DINO_CONFIG 30 + +#define HOST_NOTIFICATION_STATUS_ASSOCIATED 10 +#define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11 +#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12 +#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13 +#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14 +#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15 +#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16 +#define HOST_NOTIFICATION_STATUS_BEACON_STATE 17 +#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18 +#define HOST_NOTIFICATION_TX_STATUS 19 +#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20 +#define HOST_NOTIFICATION_MEASUREMENT_STARTED 21 +#define HOST_NOTIFICATION_MEASUREMENT_ENDED 22 +#define HOST_NOTIFICATION_CHANNEL_SWITCHED 23 +#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24 +#define HOST_NOTIFICATION_NOISE_STATS 25 +#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30 +#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 + +#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 +#define IPW_MB_ROAMING_THRESHOLD_MIN 1 +#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 +#define IPW_MB_ROAMING_THRESHOLD_MAX 30 +#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 3*IPW_MB_ROAMING_THRESHOLD_DEFAULT +#define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300 + +#define MACADRR_BYTE_LEN 6 + +#define DCR_TYPE_AP 0x01 +#define DCR_TYPE_WLAP 0x02 +#define DCR_TYPE_MU_ESS 0x03 +#define DCR_TYPE_MU_IBSS 0x04 +#define DCR_TYPE_MU_PIBSS 0x05 +#define DCR_TYPE_SNIFFER 0x06 +#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS + +/* QoS definitions */ + +#define CW_MIN_OFDM 15 +#define CW_MAX_OFDM 1023 +#define CW_MIN_CCK 31 +#define CW_MAX_CCK 1023 + +#define QOS_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define QOS_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define QOS_TX2_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1) +#define QOS_TX3_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1) + +#define QOS_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define QOS_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define QOS_TX2_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1) +#define QOS_TX3_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/4 - 1) + +#define QOS_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define QOS_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define QOS_TX2_CW_MAX_OFDM cpu_to_le16(CW_MIN_OFDM) +#define QOS_TX3_CW_MAX_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1) + +#define QOS_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define QOS_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define QOS_TX2_CW_MAX_CCK cpu_to_le16(CW_MIN_CCK) +#define QOS_TX3_CW_MAX_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1) + +#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE) +#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE) +#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE) +#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE) + +#define QOS_TX0_ACM 0 +#define QOS_TX1_ACM 0 +#define QOS_TX2_ACM 0 +#define QOS_TX3_ACM 0 + +#define QOS_TX0_TXOP_LIMIT_CCK 0 +#define QOS_TX1_TXOP_LIMIT_CCK 0 +#define QOS_TX2_TXOP_LIMIT_CCK cpu_to_le16(6016) +#define QOS_TX3_TXOP_LIMIT_CCK cpu_to_le16(3264) + +#define QOS_TX0_TXOP_LIMIT_OFDM 0 +#define QOS_TX1_TXOP_LIMIT_OFDM 0 +#define QOS_TX2_TXOP_LIMIT_OFDM cpu_to_le16(3008) +#define QOS_TX3_TXOP_LIMIT_OFDM cpu_to_le16(1504) + +#define DEF_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define DEF_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define DEF_TX2_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define DEF_TX3_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) + +#define DEF_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define DEF_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define DEF_TX2_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define DEF_TX3_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) + +#define DEF_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define DEF_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define DEF_TX2_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define DEF_TX3_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) + +#define DEF_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define DEF_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define DEF_TX2_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define DEF_TX3_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) + +#define DEF_TX0_AIFS 0 +#define DEF_TX1_AIFS 0 +#define DEF_TX2_AIFS 0 +#define DEF_TX3_AIFS 0 + +#define DEF_TX0_ACM 0 +#define DEF_TX1_ACM 0 +#define DEF_TX2_ACM 0 +#define DEF_TX3_ACM 0 + +#define DEF_TX0_TXOP_LIMIT_CCK 0 +#define DEF_TX1_TXOP_LIMIT_CCK 0 +#define DEF_TX2_TXOP_LIMIT_CCK 0 +#define DEF_TX3_TXOP_LIMIT_CCK 0 + +#define DEF_TX0_TXOP_LIMIT_OFDM 0 +#define DEF_TX1_TXOP_LIMIT_OFDM 0 +#define DEF_TX2_TXOP_LIMIT_OFDM 0 +#define DEF_TX3_TXOP_LIMIT_OFDM 0 + +#define QOS_QOS_SETS 3 +#define QOS_PARAM_SET_ACTIVE 0 +#define QOS_PARAM_SET_DEF_CCK 1 +#define QOS_PARAM_SET_DEF_OFDM 2 + +#define CTRL_QOS_NO_ACK (0x0020) + +#define IPW_TX_QUEUE_1 1 +#define IPW_TX_QUEUE_2 2 +#define IPW_TX_QUEUE_3 3 +#define IPW_TX_QUEUE_4 4 + +/* QoS sturctures */ +struct ipw_qos_info { + int qos_enable; + struct ieee80211_qos_parameters *def_qos_parm_OFDM; + struct ieee80211_qos_parameters *def_qos_parm_CCK; + u32 burst_duration_CCK; + u32 burst_duration_OFDM; + u16 qos_no_ack_mask; + int burst_enable; +}; + +/**************************************************************/ +/** + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +struct clx2_queue { + int n_bd; /**< number of BDs in this queue */ + int first_empty; /**< 1-st empty entry (index) */ + int last_used; /**< last used entry (index) */ + u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */ + u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */ + dma_addr_t dma_addr; /**< physical addr for BD's */ + int low_mark; /**< low watermark, resume queue if free space more than this */ + int high_mark; /**< high watermark, stop queue if free space less than this */ +} __attribute__ ((packed)); /* XXX */ + +struct machdr32 { + __le16 frame_ctl; + __le16 duration; // watch out for endians! + u8 addr1[MACADRR_BYTE_LEN]; + u8 addr2[MACADRR_BYTE_LEN]; + u8 addr3[MACADRR_BYTE_LEN]; + __le16 seq_ctrl; // more endians! + u8 addr4[MACADRR_BYTE_LEN]; + __le16 qos_ctrl; +} __attribute__ ((packed)); + +struct machdr30 { + __le16 frame_ctl; + __le16 duration; // watch out for endians! + u8 addr1[MACADRR_BYTE_LEN]; + u8 addr2[MACADRR_BYTE_LEN]; + u8 addr3[MACADRR_BYTE_LEN]; + __le16 seq_ctrl; // more endians! + u8 addr4[MACADRR_BYTE_LEN]; +} __attribute__ ((packed)); + +struct machdr26 { + __le16 frame_ctl; + __le16 duration; // watch out for endians! + u8 addr1[MACADRR_BYTE_LEN]; + u8 addr2[MACADRR_BYTE_LEN]; + u8 addr3[MACADRR_BYTE_LEN]; + __le16 seq_ctrl; // more endians! + __le16 qos_ctrl; +} __attribute__ ((packed)); + +struct machdr24 { + __le16 frame_ctl; + __le16 duration; // watch out for endians! + u8 addr1[MACADRR_BYTE_LEN]; + u8 addr2[MACADRR_BYTE_LEN]; + u8 addr3[MACADRR_BYTE_LEN]; + __le16 seq_ctrl; // more endians! +} __attribute__ ((packed)); + +// TX TFD with 32 byte MAC Header +struct tx_tfd_32 { + struct machdr32 mchdr; // 32 + __le32 uivplaceholder[2]; // 8 +} __attribute__ ((packed)); + +// TX TFD with 30 byte MAC Header +struct tx_tfd_30 { + struct machdr30 mchdr; // 30 + u8 reserved[2]; // 2 + __le32 uivplaceholder[2]; // 8 +} __attribute__ ((packed)); + +// tx tfd with 26 byte mac header +struct tx_tfd_26 { + struct machdr26 mchdr; // 26 + u8 reserved1[2]; // 2 + __le32 uivplaceholder[2]; // 8 + u8 reserved2[4]; // 4 +} __attribute__ ((packed)); + +// tx tfd with 24 byte mac header +struct tx_tfd_24 { + struct machdr24 mchdr; // 24 + __le32 uivplaceholder[2]; // 8 + u8 reserved[8]; // 8 +} __attribute__ ((packed)); + +#define DCT_WEP_KEY_FIELD_LENGTH 16 + +struct tfd_command { + u8 index; + u8 length; + __le16 reserved; + u8 payload[0]; +} __attribute__ ((packed)); + +struct tfd_data { + /* Header */ + __le32 work_area_ptr; + u8 station_number; /* 0 for BSS */ + u8 reserved1; + __le16 reserved2; + + /* Tx Parameters */ + u8 cmd_id; + u8 seq_num; + __le16 len; + u8 priority; + u8 tx_flags; + u8 tx_flags_ext; + u8 key_index; + u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH]; + u8 rate; + u8 antenna; + __le16 next_packet_duration; + __le16 next_frag_len; + __le16 back_off_counter; //////txop; + u8 retrylimit; + __le16 cwcurrent; + u8 reserved3; + + /* 802.11 MAC Header */ + union { + struct tx_tfd_24 tfd_24; + struct tx_tfd_26 tfd_26; + struct tx_tfd_30 tfd_30; + struct tx_tfd_32 tfd_32; + } tfd; + + /* Payload DMA info */ + __le32 num_chunks; + __le32 chunk_ptr[NUM_TFD_CHUNKS]; + __le16 chunk_len[NUM_TFD_CHUNKS]; +} __attribute__ ((packed)); + +struct txrx_control_flags { + u8 message_type; + u8 rx_seq_num; + u8 control_bits; + u8 reserved; +} __attribute__ ((packed)); + +#define TFD_SIZE 128 +#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags)) + +struct tfd_frame { + struct txrx_control_flags control_flags; + union { + struct tfd_data data; + struct tfd_command cmd; + u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH]; + } u; +} __attribute__ ((packed)); + +typedef void destructor_func(const void *); + +/** + * Tx Queue for DMA. Queue consists of circular buffer of + * BD's and required locking structures. + */ +struct clx2_tx_queue { + struct clx2_queue q; + struct tfd_frame *bd; + struct ieee80211_txb **txb; +}; + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 32 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +// Used for passing to driver number of successes and failures per rate +struct rate_histogram { + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } success; + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } failed; +} __attribute__ ((packed)); + +/* statistics command response */ +struct ipw_cmd_stats { + u8 cmd_id; + u8 seq_num; + __le16 good_sfd; + __le16 bad_plcp; + __le16 wrong_bssid; + __le16 valid_mpdu; + __le16 bad_mac_header; + __le16 reserved_frame_types; + __le16 rx_ina; + __le16 bad_crc32; + __le16 invalid_cts; + __le16 invalid_acks; + __le16 long_distance_ina_fina; + __le16 dsp_silence_unreachable; + __le16 accumulated_rssi; + __le16 rx_ovfl_frame_tossed; + __le16 rssi_silence_threshold; + __le16 rx_ovfl_frame_supplied; + __le16 last_rx_frame_signal; + __le16 last_rx_frame_noise; + __le16 rx_autodetec_no_ofdm; + __le16 rx_autodetec_no_barker; + __le16 reserved; +} __attribute__ ((packed)); + +struct notif_channel_result { + u8 channel_num; + struct ipw_cmd_stats stats; + u8 uReserved; +} __attribute__ ((packed)); + +#define SCAN_COMPLETED_STATUS_COMPLETE 1 +#define SCAN_COMPLETED_STATUS_ABORTED 2 + +struct notif_scan_complete { + u8 scan_type; + u8 num_channels; + u8 status; + u8 reserved; +} __attribute__ ((packed)); + +struct notif_frag_length { + __le16 frag_length; + __le16 reserved; +} __attribute__ ((packed)); + +struct notif_beacon_state { + __le32 state; + __le32 number; +} __attribute__ ((packed)); + +struct notif_tgi_tx_key { + u8 key_state; + u8 security_type; + u8 station_index; + u8 reserved; +} __attribute__ ((packed)); + +#define SILENCE_OVER_THRESH (1) +#define SILENCE_UNDER_THRESH (2) + +struct notif_link_deterioration { + struct ipw_cmd_stats stats; + u8 rate; + u8 modulation; + struct rate_histogram histogram; + u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */ + __le16 silence_count; +} __attribute__ ((packed)); + +struct notif_association { + u8 state; +} __attribute__ ((packed)); + +struct notif_authenticate { + u8 state; + struct machdr24 addr; + __le16 status; +} __attribute__ ((packed)); + +struct notif_calibration { + u8 data[104]; +} __attribute__ ((packed)); + +struct notif_noise { + __le32 value; +} __attribute__ ((packed)); + +struct ipw_rx_notification { + u8 reserved[8]; + u8 subtype; + u8 flags; + __le16 size; + union { + struct notif_association assoc; + struct notif_authenticate auth; + struct notif_channel_result channel_result; + struct notif_scan_complete scan_complete; + struct notif_frag_length frag_len; + struct notif_beacon_state beacon_state; + struct notif_tgi_tx_key tgi_tx_key; + struct notif_link_deterioration link_deterioration; + struct notif_calibration calibration; + struct notif_noise noise; + u8 raw[0]; + } u; +} __attribute__ ((packed)); + +struct ipw_rx_frame { + __le32 reserved1; + u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER + u8 received_channel; // The channel that this frame was received on. + // Note that for .11b this does not have to be + // the same as the channel that it was sent. + // Filled by LMAC + u8 frameStatus; + u8 rate; + u8 rssi; + u8 agc; + u8 rssi_dbm; + __le16 signal; + __le16 noise; + u8 antennaAndPhy; + u8 control; // control bit should be on in bg + u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate + // is identical) + u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen + __le16 length; + u8 data[0]; +} __attribute__ ((packed)); + +struct ipw_rx_header { + u8 message_type; + u8 rx_seq_num; + u8 control_bits; + u8 reserved; +} __attribute__ ((packed)); + +struct ipw_rx_packet { + struct ipw_rx_header header; + union { + struct ipw_rx_frame frame; + struct ipw_rx_notification notification; + } u; +} __attribute__ ((packed)); + +#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12 +#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \ + sizeof(struct ipw_rx_frame)) + +struct ipw_rx_mem_buffer { + dma_addr_t dma_addr; + struct sk_buff *skb; + struct list_head list; +}; /* Not transferred over network, so not __attribute__ ((packed)) */ + +struct ipw_rx_queue { + struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 processed; /* Internal index to last handled Rx packet */ + u32 read; /* Shared index to newest available Rx buffer */ + u32 write; /* Shared index to oldest written Rx packet */ + u32 free_count; /* Number of pre-allocated buffers in rx_free */ + /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */ + struct list_head rx_free; /* Own an SKBs */ + struct list_head rx_used; /* No SKB allocated */ + spinlock_t lock; +}; /* Not transferred over network, so not __attribute__ ((packed)) */ + +struct alive_command_responce { + u8 alive_command; + u8 sequence_number; + __le16 software_revision; + u8 device_identifier; + u8 reserved1[5]; + __le16 reserved2; + __le16 reserved3; + __le16 clock_settle_time; + __le16 powerup_settle_time; + __le16 reserved4; + u8 time_stamp[5]; /* month, day, year, hours, minutes */ + u8 ucode_valid; +} __attribute__ ((packed)); + +#define IPW_MAX_RATES 12 + +struct ipw_rates { + u8 num_rates; + u8 rates[IPW_MAX_RATES]; +} __attribute__ ((packed)); + +struct command_block { + unsigned int control; + u32 source_addr; + u32 dest_addr; + unsigned int status; +} __attribute__ ((packed)); + +#define CB_NUMBER_OF_ELEMENTS_SMALL 64 +struct fw_image_desc { + unsigned long last_cb_index; + unsigned long current_cb_index; + struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL]; + void *v_addr; + unsigned long p_addr; + unsigned long len; +}; + +struct ipw_sys_config { + u8 bt_coexistence; + u8 reserved1; + u8 answer_broadcast_ssid_probe; + u8 accept_all_data_frames; + u8 accept_non_directed_frames; + u8 exclude_unicast_unencrypted; + u8 disable_unicast_decryption; + u8 exclude_multicast_unencrypted; + u8 disable_multicast_decryption; + u8 antenna_diversity; + u8 pass_crc_to_host; + u8 dot11g_auto_detection; + u8 enable_cts_to_self; + u8 enable_multicast_filtering; + u8 bt_coexist_collision_thr; + u8 silence_threshold; + u8 accept_all_mgmt_bcpr; + u8 accept_all_mgmt_frames; + u8 pass_noise_stats_to_host; + u8 reserved3; +} __attribute__ ((packed)); + +struct ipw_multicast_addr { + u8 num_of_multicast_addresses; + u8 reserved[3]; + u8 mac1[6]; + u8 mac2[6]; + u8 mac3[6]; + u8 mac4[6]; +} __attribute__ ((packed)); + +#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */ +#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */ + +#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00 +#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20 +#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30 + +#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */ +#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */ +#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */ +#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */ +//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */ + +struct ipw_wep_key { + u8 cmd_id; + u8 seq_num; + u8 key_index; + u8 key_size; + u8 key[16]; +} __attribute__ ((packed)); + +struct ipw_tgi_tx_key { + u8 key_id; + u8 security_type; + u8 station_index; + u8 flags; + u8 key[16]; + __le32 tx_counter[2]; +} __attribute__ ((packed)); + +#define IPW_SCAN_CHANNELS 54 + +struct ipw_scan_request { + u8 scan_type; + __le16 dwell_time; + u8 channels_list[IPW_SCAN_CHANNELS]; + u8 channels_reserved[3]; +} __attribute__ ((packed)); + +enum { + IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0, + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN, + IPW_SCAN_ACTIVE_DIRECT_SCAN, + IPW_SCAN_ACTIVE_BROADCAST_SCAN, + IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN, + IPW_SCAN_TYPES +}; + +struct ipw_scan_request_ext { + __le32 full_scan_index; + u8 channels_list[IPW_SCAN_CHANNELS]; + u8 scan_type[IPW_SCAN_CHANNELS / 2]; + u8 reserved; + __le16 dwell_time[IPW_SCAN_TYPES]; +} __attribute__ ((packed)); + +static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) +{ + if (index % 2) + return scan->scan_type[index / 2] & 0x0F; + else + return (scan->scan_type[index / 2] & 0xF0) >> 4; +} + +static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan, + u8 index, u8 scan_type) +{ + if (index % 2) + scan->scan_type[index / 2] = + (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F); + else + scan->scan_type[index / 2] = + (scan->scan_type[index / 2] & 0x0F) | + ((scan_type & 0x0F) << 4); +} + +struct ipw_associate { + u8 channel; +#ifdef __LITTLE_ENDIAN_BITFIELD + u8 auth_type:4, auth_key:4; +#else + u8 auth_key:4, auth_type:4; +#endif + u8 assoc_type; + u8 reserved; + __le16 policy_support; + u8 preamble_length; + u8 ieee_mode; + u8 bssid[ETH_ALEN]; + __le32 assoc_tsf_msw; + __le32 assoc_tsf_lsw; + __le16 capability; + __le16 listen_interval; + __le16 beacon_interval; + u8 dest[ETH_ALEN]; + __le16 atim_window; + u8 smr; + u8 reserved1; + __le16 reserved2; +} __attribute__ ((packed)); + +struct ipw_supported_rates { + u8 ieee_mode; + u8 num_rates; + u8 purpose; + u8 reserved; + u8 supported_rates[IPW_MAX_RATES]; +} __attribute__ ((packed)); + +struct ipw_rts_threshold { + __le16 rts_threshold; + __le16 reserved; +} __attribute__ ((packed)); + +struct ipw_frag_threshold { + __le16 frag_threshold; + __le16 reserved; +} __attribute__ ((packed)); + +struct ipw_retry_limit { + u8 short_retry_limit; + u8 long_retry_limit; + __le16 reserved; +} __attribute__ ((packed)); + +struct ipw_dino_config { + __le32 dino_config_addr; + __le16 dino_config_size; + u8 dino_response; + u8 reserved; +} __attribute__ ((packed)); + +struct ipw_aironet_info { + u8 id; + u8 length; + __le16 reserved; +} __attribute__ ((packed)); + +struct ipw_rx_key { + u8 station_index; + u8 key_type; + u8 key_id; + u8 key_flag; + u8 key[16]; + u8 station_address[6]; + u8 key_index; + u8 reserved; +} __attribute__ ((packed)); + +struct ipw_country_channel_info { + u8 first_channel; + u8 no_channels; + s8 max_tx_power; +} __attribute__ ((packed)); + +struct ipw_country_info { + u8 id; + u8 length; + u8 country_str[3]; + struct ipw_country_channel_info groups[7]; +} __attribute__ ((packed)); + +struct ipw_channel_tx_power { + u8 channel_number; + s8 tx_power; +} __attribute__ ((packed)); + +#define SCAN_ASSOCIATED_INTERVAL (HZ) +#define SCAN_INTERVAL (HZ / 10) +#define MAX_A_CHANNELS 37 +#define MAX_B_CHANNELS 14 + +struct ipw_tx_power { + u8 num_channels; + u8 ieee_mode; + struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS]; +} __attribute__ ((packed)); + +struct ipw_rsn_capabilities { + u8 id; + u8 length; + __le16 version; +} __attribute__ ((packed)); + +struct ipw_sensitivity_calib { + __le16 beacon_rssi_raw; + __le16 reserved; +} __attribute__ ((packed)); + +/** + * Host command structure. + * + * On input, the following fields should be filled: + * - cmd + * - len + * - status_len + * - param (if needed) + * + * On output, + * - \a status contains status; + * - \a param filled with status parameters. + */ +struct ipw_cmd { /* XXX */ + u32 cmd; /**< Host command */ + u32 status;/**< Status */ + u32 status_len; + /**< How many 32 bit parameters in the status */ + u32 len; /**< incoming parameters length, bytes */ + /** + * command parameters. + * There should be enough space for incoming and + * outcoming parameters. + * Incoming parameters listed 1-st, followed by outcoming params. + * nParams=(len+3)/4+status_len + */ + u32 param[0]; +} __attribute__ ((packed)); + +#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */ + +#define STATUS_INT_ENABLED (1<<1) +#define STATUS_RF_KILL_HW (1<<2) +#define STATUS_RF_KILL_SW (1<<3) +#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW) + +#define STATUS_INIT (1<<5) +#define STATUS_AUTH (1<<6) +#define STATUS_ASSOCIATED (1<<7) +#define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED) + +#define STATUS_ASSOCIATING (1<<8) +#define STATUS_DISASSOCIATING (1<<9) +#define STATUS_ROAMING (1<<10) +#define STATUS_EXIT_PENDING (1<<11) +#define STATUS_DISASSOC_PENDING (1<<12) +#define STATUS_STATE_PENDING (1<<13) + +#define STATUS_DIRECT_SCAN_PENDING (1<<19) +#define STATUS_SCAN_PENDING (1<<20) +#define STATUS_SCANNING (1<<21) +#define STATUS_SCAN_ABORTING (1<<22) +#define STATUS_SCAN_FORCED (1<<23) + +#define STATUS_LED_LINK_ON (1<<24) +#define STATUS_LED_ACT_ON (1<<25) + +#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */ +#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */ +#define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */ + +#define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */ + +#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ +#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ +#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ +#define CFG_CUSTOM_MAC (1<<3) +#define CFG_PREAMBLE_LONG (1<<4) +#define CFG_ADHOC_PERSIST (1<<5) +#define CFG_ASSOCIATE (1<<6) +#define CFG_FIXED_RATE (1<<7) +#define CFG_ADHOC_CREATE (1<<8) +#define CFG_NO_LED (1<<9) +#define CFG_BACKGROUND_SCAN (1<<10) +#define CFG_SPEED_SCAN (1<<11) +#define CFG_NET_STATS (1<<12) + +#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ +#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ + +#define MAX_STATIONS 32 +#define IPW_INVALID_STATION (0xff) + +struct ipw_station_entry { + u8 mac_addr[ETH_ALEN]; + u8 reserved; + u8 support_mode; +}; + +#define AVG_ENTRIES 8 +struct average { + s16 entries[AVG_ENTRIES]; + u8 pos; + u8 init; + s32 sum; +}; + +#define MAX_SPEED_SCAN 100 +#define IPW_IBSS_MAC_HASH_SIZE 31 + +struct ipw_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +struct ipw_error_elem { /* XXX */ + u32 desc; + u32 time; + u32 blink1; + u32 blink2; + u32 link1; + u32 link2; + u32 data; +}; + +struct ipw_event { /* XXX */ + u32 event; + u32 time; + u32 data; +} __attribute__ ((packed)); + +struct ipw_fw_error { /* XXX */ + unsigned long jiffies; + u32 status; + u32 config; + u32 elem_len; + u32 log_len; + struct ipw_error_elem *elem; + struct ipw_event *log; + u8 payload[0]; +} __attribute__ ((packed)); + +#ifdef CONFIG_IPW2200_PROMISCUOUS + +enum ipw_prom_filter { + IPW_PROM_CTL_HEADER_ONLY = (1 << 0), + IPW_PROM_MGMT_HEADER_ONLY = (1 << 1), + IPW_PROM_DATA_HEADER_ONLY = (1 << 2), + IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */ + IPW_PROM_NO_TX = (1 << 4), + IPW_PROM_NO_RX = (1 << 5), + IPW_PROM_NO_CTL = (1 << 6), + IPW_PROM_NO_MGMT = (1 << 7), + IPW_PROM_NO_DATA = (1 << 8), +}; + +struct ipw_priv; +struct ipw_prom_priv { + struct ipw_priv *priv; + struct ieee80211_device *ieee; + enum ipw_prom_filter filter; + int tx_packets; + int rx_packets; +}; +#endif + +#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS) +/* Magic struct that slots into the radiotap header -- no reason + * to build this manually element by element, we can write it much + * more efficiently than we can parse it. ORDER MATTERS HERE + * + * When sent to us via the simulated Rx interface in sysfs, the entire + * structure is provided regardless of any bits unset. + */ +struct ipw_rt_hdr { + struct ieee80211_radiotap_header rt_hdr; + u64 rt_tsf; /* TSF */ /* XXX */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channel; /* channel in mhz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + u8 payload[0]; /* payload... */ +} __attribute__ ((packed)); +#endif + +struct ipw_priv { + /* ieee device used by generic ieee processing code */ + struct ieee80211_device *ieee; + + spinlock_t lock; + spinlock_t irq_lock; + struct mutex mutex; + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + struct net_device *net_dev; + +#ifdef CONFIG_IPW2200_PROMISCUOUS + /* Promiscuous mode */ + struct ipw_prom_priv *prom_priv; + struct net_device *prom_net_dev; +#endif + + /* pci hardware address support */ + void __iomem *hw_base; + unsigned long hw_len; + + struct fw_image_desc sram_desc; + + /* result of ucode download */ + struct alive_command_responce dino_alive; + + wait_queue_head_t wait_command_queue; + wait_queue_head_t wait_state; + + /* Rx and Tx DMA processing queues */ + struct ipw_rx_queue *rxq; + struct clx2_tx_queue txq_cmd; + struct clx2_tx_queue txq[4]; + u32 status; + u32 config; + u32 capability; + + struct average average_missed_beacons; + s16 exp_avg_rssi; + s16 exp_avg_noise; + u32 port_type; + int rx_bufs_min; /**< minimum number of bufs in Rx queue */ + int rx_pend_max; /**< maximum pending buffers for one IRQ */ + u32 hcmd_seq; /**< sequence number for hcmd */ + u32 disassociate_threshold; + u32 roaming_threshold; + + struct ipw_associate assoc_request; + struct ieee80211_network *assoc_network; + + unsigned long ts_scan_abort; + struct ipw_supported_rates rates; + struct ipw_rates phy[3]; /**< PHY restrictions, per band */ + struct ipw_rates supp; /**< software defined */ + struct ipw_rates extended; /**< use for corresp. IE, AP only */ + + struct notif_link_deterioration last_link_deterioration; /** for statistics */ + struct ipw_cmd *hcmd; /**< host command currently executed */ + + wait_queue_head_t hcmd_wq; /**< host command waits for execution */ + u32 tsf_bcn[2]; /**< TSF from latest beacon */ + + struct notif_calibration calib; /**< last calibration */ + + /* ordinal interface with firmware */ + u32 table0_addr; + u32 table0_len; + u32 table1_addr; + u32 table1_len; + u32 table2_addr; + u32 table2_len; + + /* context information */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u8 nick[IW_ESSID_MAX_SIZE]; + u16 rates_mask; + u8 channel; + struct ipw_sys_config sys_config; + u32 power_mode; + u8 bssid[ETH_ALEN]; + u16 rts_threshold; + u8 mac_addr[ETH_ALEN]; + u8 num_stations; + u8 stations[MAX_STATIONS][ETH_ALEN]; + u8 short_retry_limit; + u8 long_retry_limit; + + u32 notif_missed_beacons; + + /* Statistics and counters normalized with each association */ + u32 last_missed_beacons; + u32 last_tx_packets; + u32 last_rx_packets; + u32 last_tx_failures; + u32 last_rx_err; + u32 last_rate; + + u32 missed_adhoc_beacons; + u32 missed_beacons; + u32 rx_packets; + u32 tx_packets; + u32 quality; + + u8 speed_scan[MAX_SPEED_SCAN]; + u8 speed_scan_pos; + + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE]; + + /* eeprom */ + u8 eeprom[0x100]; /* 256 bytes of eeprom */ + u8 country[4]; + int eeprom_delay; + + struct iw_statistics wstats; + + struct iw_public_data wireless_data; + + int user_requested_scan; + u8 direct_scan_ssid[IW_ESSID_MAX_SIZE]; + u8 direct_scan_ssid_len; + + struct workqueue_struct *workqueue; + + struct delayed_work adhoc_check; + struct work_struct associate; + struct work_struct disassociate; + struct work_struct system_config; + struct work_struct rx_replenish; + struct delayed_work request_scan; + struct delayed_work request_direct_scan; + struct delayed_work request_passive_scan; + struct delayed_work scan_event; + struct work_struct adapter_restart; + struct delayed_work rf_kill; + struct work_struct up; + struct work_struct down; + struct delayed_work gather_stats; + struct work_struct abort_scan; + struct work_struct roam; + struct delayed_work scan_check; + struct work_struct link_up; + struct work_struct link_down; + + struct tasklet_struct irq_tasklet; + + /* LED related variables and work_struct */ + u8 nic_type; + u32 led_activity_on; + u32 led_activity_off; + u32 led_association_on; + u32 led_association_off; + u32 led_ofdm_on; + u32 led_ofdm_off; + + struct delayed_work led_link_on; + struct delayed_work led_link_off; + struct delayed_work led_act_off; + struct work_struct merge_networks; + + struct ipw_cmd_log *cmdlog; + int cmdlog_len; + int cmdlog_pos; + +#define IPW_2200BG 1 +#define IPW_2915ABG 2 + u8 adapter; + + s8 tx_power; + +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif + + struct ipw_fw_error *error; + + /* network state */ + + /* Used to pass the current INTA value from ISR to Tasklet */ + u32 isr_inta; + + /* QoS */ + struct ipw_qos_info qos_data; + struct work_struct qos_activate; + /*********************************/ + + /* debugging info */ + u32 indirect_dword; + u32 direct_dword; + u32 indirect_byte; +}; /*ipw_priv */ + +/* debug macros */ + +/* Debug and printf string expansion helpers for printing bitfields */ +#define BIT_FMT8 "%c%c%c%c-%c%c%c%c" +#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8 +#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16 + +#define BITC(x,y) (((x>>y)&1)?'1':'0') +#define BIT_ARG8(x) \ +BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\ +BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0) + +#define BIT_ARG16(x) \ +BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\ +BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\ +BIT_ARG8(x) + +#define BIT_ARG32(x) \ +BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\ +BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\ +BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\ +BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\ +BIT_ARG16(x) + + +#define IPW_DEBUG(level, fmt, args...) \ +do { if (ipw_debug_level & (level)) \ + printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) + +#ifdef CONFIG_IPW2200_DEBUG +#define IPW_LL_DEBUG(level, fmt, args...) \ +do { if (ipw_debug_level & (level)) \ + printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) +#else +#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0) +#endif /* CONFIG_IPW2200_DEBUG */ + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IPW_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IPW_xxxx_DEBUG() macro definition for your + * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw then you do not have + * CONFIG_IPW2200_DEBUG defined in your kernel configuration + * + */ + +#define IPW_DL_ERROR (1<<0) +#define IPW_DL_WARNING (1<<1) +#define IPW_DL_INFO (1<<2) +#define IPW_DL_WX (1<<3) +#define IPW_DL_HOST_COMMAND (1<<5) +#define IPW_DL_STATE (1<<6) + +#define IPW_DL_NOTIF (1<<10) +#define IPW_DL_SCAN (1<<11) +#define IPW_DL_ASSOC (1<<12) +#define IPW_DL_DROP (1<<13) +#define IPW_DL_IOCTL (1<<14) + +#define IPW_DL_MANAGE (1<<15) +#define IPW_DL_FW (1<<16) +#define IPW_DL_RF_KILL (1<<17) +#define IPW_DL_FW_ERRORS (1<<18) + +#define IPW_DL_LED (1<<19) + +#define IPW_DL_ORD (1<<20) + +#define IPW_DL_FRAG (1<<21) +#define IPW_DL_WEP (1<<22) +#define IPW_DL_TX (1<<23) +#define IPW_DL_RX (1<<24) +#define IPW_DL_ISR (1<<25) +#define IPW_DL_FW_INFO (1<<26) +#define IPW_DL_IO (1<<27) +#define IPW_DL_TRACE (1<<28) + +#define IPW_DL_STATS (1<<29) +#define IPW_DL_MERGE (1<<30) +#define IPW_DL_QOS (1<<31) + +#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) +#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) +#define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a) + +#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a) +#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a) +#define IPW_DEBUG_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a) +#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a) +#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a) +#define IPW_DEBUG_ISR(f, a...) IPW_LL_DEBUG(IPW_DL_ISR, f, ## a) +#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a) +#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a) +#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a) +#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a) +#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a) +#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a) +#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a) +#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a) +#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a) +#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a) +#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a) +#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a) +#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) +#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) +#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a) +#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a) +#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a) + +#include + +/* +* Register bit definitions +*/ + +#define IPW_INTA_RW 0x00000008 +#define IPW_INTA_MASK_R 0x0000000C +#define IPW_INDIRECT_ADDR 0x00000010 +#define IPW_INDIRECT_DATA 0x00000014 +#define IPW_AUTOINC_ADDR 0x00000018 +#define IPW_AUTOINC_DATA 0x0000001C +#define IPW_RESET_REG 0x00000020 +#define IPW_GP_CNTRL_RW 0x00000024 + +#define IPW_READ_INT_REGISTER 0xFF4 + +#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004 + +#define IPW_REGISTER_DOMAIN1_END 0x00001000 +#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4 + +#define IPW_SHARED_LOWER_BOUND 0x00000200 +#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80 + +#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000 +#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000 + +#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29) +#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001 +#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002 + +/* + * RESET Register Bit Indexes + */ +#define CBD_RESET_REG_PRINCETON_RESET (1<<0) +#define IPW_START_STANDBY (1<<2) +#define IPW_ACTIVITY_LED (1<<4) +#define IPW_ASSOCIATED_LED (1<<5) +#define IPW_OFDM_LED (1<<6) +#define IPW_RESET_REG_SW_RESET (1<<7) +#define IPW_RESET_REG_MASTER_DISABLED (1<<8) +#define IPW_RESET_REG_STOP_MASTER (1<<9) +#define IPW_GATE_ODMA (1<<25) +#define IPW_GATE_IDMA (1<<26) +#define IPW_ARC_KESHET_CONFIG (1<<27) +#define IPW_GATE_ADMA (1<<29) + +#define IPW_CSR_CIS_UPPER_BOUND 0x00000200 +#define IPW_DOMAIN_0_END 0x1000 +#define CLX_MEM_BAR_SIZE 0x1000 + +/* Dino/baseband control registers bits */ + +#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */ +#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */ +#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */ +#define IPW_BASEBAND_CONTROL_STATUS 0X00200000 +#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004 +#define IPW_BASEBAND_RX_FIFO_READ 0X00200004 +#define IPW_BASEBAND_CONTROL_STORE 0X00200010 + +#define IPW_INTERNAL_CMD_EVENT 0X00300004 +#define IPW_BASEBAND_POWER_DOWN 0x00000001 + +#define IPW_MEM_HALT_AND_RESET 0x003000e0 + +/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */ +#define IPW_BIT_HALT_RESET_ON 0x80000000 +#define IPW_BIT_HALT_RESET_OFF 0x00000000 + +#define CB_LAST_VALID 0x20000000 +#define CB_INT_ENABLED 0x40000000 +#define CB_VALID 0x80000000 +#define CB_SRC_LE 0x08000000 +#define CB_DEST_LE 0x04000000 +#define CB_SRC_AUTOINC 0x00800000 +#define CB_SRC_IO_GATED 0x00400000 +#define CB_DEST_AUTOINC 0x00080000 +#define CB_SRC_SIZE_LONG 0x00200000 +#define CB_DEST_SIZE_LONG 0x00020000 + +/* DMA DEFINES */ + +#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000 +#define DMA_CB_STOP_AND_ABORT 0x00000C00 +#define DMA_CB_START 0x00000100 + +#define IPW_SHARED_SRAM_SIZE 0x00030000 +#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000 +#define CB_MAX_LENGTH 0x1FFF + +#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18 +#define IPW_EEPROM_IMAGE_SIZE 0x100 + +/* DMA defs */ +#define IPW_DMA_I_CURRENT_CB 0x003000D0 +#define IPW_DMA_O_CURRENT_CB 0x003000D4 +#define IPW_DMA_I_DMA_CONTROL 0x003000A4 +#define IPW_DMA_I_CB_BASE 0x003000A0 + +#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200 +#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204 +#define IPW_TX_QUEUE_0_BD_BASE 0x00000208 +#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C) +#define IPW_TX_QUEUE_1_BD_BASE 0x00000210 +#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214 +#define IPW_TX_QUEUE_2_BD_BASE 0x00000218 +#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C) +#define IPW_TX_QUEUE_3_BD_BASE 0x00000220 +#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224 +#define IPW_RX_BD_BASE 0x00000240 +#define IPW_RX_BD_SIZE 0x00000244 +#define IPW_RFDS_TABLE_LOWER 0x00000500 + +#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280 +#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284 +#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288 +#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C) +#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290 +#define IPW_RX_READ_INDEX (0x000002A0) + +#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) +#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84) +#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88) +#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C) +#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90) +#define IPW_RX_WRITE_INDEX (0x00000FA0) + +/* + * EEPROM Related Definitions + */ + +#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814) +#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818) +#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C) +#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820) +#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0) + +#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C) +#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C) +#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C) +#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10) +#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14) +#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18) + +#define MSB 1 +#define LSB 0 +#define WORD_TO_BYTE(_word) ((_word) * sizeof(u16)) + +#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \ + ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) ) + +/* EEPROM access by BYTE */ +#define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */ +#define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */ +#define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */ +#define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */ +#define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */ +#define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */ +#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */ +#define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */ +#define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */ +#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ + +/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */ +#define EEPROM_NIC_TYPE_0 0 +#define EEPROM_NIC_TYPE_1 1 +#define EEPROM_NIC_TYPE_2 2 +#define EEPROM_NIC_TYPE_3 3 +#define EEPROM_NIC_TYPE_4 4 + +/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */ +#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */ +#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */ +#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */ + +#define FW_MEM_REG_LOWER_BOUND 0x00300000 +#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) +#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) +#define EEPROM_BIT_SK (1<<0) +#define EEPROM_BIT_CS (1<<1) +#define EEPROM_BIT_DI (1<<2) +#define EEPROM_BIT_DO (1<<4) + +#define EEPROM_CMD_READ 0x2 + +/* Interrupts masks */ +#define IPW_INTA_NONE 0x00000000 + +#define IPW_INTA_BIT_RX_TRANSFER 0x00000002 +#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010 +#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020 + +//Inta Bits for CF +#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800 +#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000 +#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000 +#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000 +#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000 + +#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000 + +#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000 +#define IPW_INTA_BIT_POWER_DOWN 0x00200000 + +#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000 +#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000 +#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000 +#define IPW_INTA_BIT_FATAL_ERROR 0x40000000 +#define IPW_INTA_BIT_PARITY_ERROR 0x80000000 + +/* Interrupts enabled at init time. */ +#define IPW_INTA_MASK_ALL \ + (IPW_INTA_BIT_TX_QUEUE_1 | \ + IPW_INTA_BIT_TX_QUEUE_2 | \ + IPW_INTA_BIT_TX_QUEUE_3 | \ + IPW_INTA_BIT_TX_QUEUE_4 | \ + IPW_INTA_BIT_TX_CMD_QUEUE | \ + IPW_INTA_BIT_RX_TRANSFER | \ + IPW_INTA_BIT_FATAL_ERROR | \ + IPW_INTA_BIT_PARITY_ERROR | \ + IPW_INTA_BIT_STATUS_CHANGE | \ + IPW_INTA_BIT_FW_INITIALIZATION_DONE | \ + IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \ + IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \ + IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \ + IPW_INTA_BIT_POWER_DOWN | \ + IPW_INTA_BIT_RF_KILL_DONE ) + +/* FW event log definitions */ +#define EVENT_ELEM_SIZE (3 * sizeof(u32)) +#define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16)) + +/* FW error log definitions */ +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) +#define ERROR_START_OFFSET (1 * sizeof(u32)) + +/* TX power level (dbm) */ +#define IPW_TX_POWER_MIN -12 +#define IPW_TX_POWER_MAX 20 +#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX + +enum { + IPW_FW_ERROR_OK = 0, + IPW_FW_ERROR_FAIL, + IPW_FW_ERROR_MEMORY_UNDERFLOW, + IPW_FW_ERROR_MEMORY_OVERFLOW, + IPW_FW_ERROR_BAD_PARAM, + IPW_FW_ERROR_BAD_CHECKSUM, + IPW_FW_ERROR_NMI_INTERRUPT, + IPW_FW_ERROR_BAD_DATABASE, + IPW_FW_ERROR_ALLOC_FAIL, + IPW_FW_ERROR_DMA_UNDERRUN, + IPW_FW_ERROR_DMA_STATUS, + IPW_FW_ERROR_DINO_ERROR, + IPW_FW_ERROR_EEPROM_ERROR, + IPW_FW_ERROR_SYSASSERT, + IPW_FW_ERROR_FATAL_ERROR +}; + +#define AUTH_OPEN 0 +#define AUTH_SHARED_KEY 1 +#define AUTH_LEAP 2 +#define AUTH_IGNORE 3 + +#define HC_ASSOCIATE 0 +#define HC_REASSOCIATE 1 +#define HC_DISASSOCIATE 2 +#define HC_IBSS_START 3 +#define HC_IBSS_RECONF 4 +#define HC_DISASSOC_QUIET 5 + +#define HC_QOS_SUPPORT_ASSOC cpu_to_le16(0x01) + +#define IPW_RATE_CAPABILITIES 1 +#define IPW_RATE_CONNECT 0 + +/* + * Rate values and masks + */ +#define IPW_TX_RATE_1MB 0x0A +#define IPW_TX_RATE_2MB 0x14 +#define IPW_TX_RATE_5MB 0x37 +#define IPW_TX_RATE_6MB 0x0D +#define IPW_TX_RATE_9MB 0x0F +#define IPW_TX_RATE_11MB 0x6E +#define IPW_TX_RATE_12MB 0x05 +#define IPW_TX_RATE_18MB 0x07 +#define IPW_TX_RATE_24MB 0x09 +#define IPW_TX_RATE_36MB 0x0B +#define IPW_TX_RATE_48MB 0x01 +#define IPW_TX_RATE_54MB 0x03 + +#define IPW_ORD_TABLE_ID_MASK 0x0000FF00 +#define IPW_ORD_TABLE_VALUE_MASK 0x000000FF + +#define IPW_ORD_TABLE_0_MASK 0x0000F000 +#define IPW_ORD_TABLE_1_MASK 0x0000F100 +#define IPW_ORD_TABLE_2_MASK 0x0000F200 +#define IPW_ORD_TABLE_3_MASK 0x0000F300 +#define IPW_ORD_TABLE_4_MASK 0x0000F400 +#define IPW_ORD_TABLE_5_MASK 0x0000F500 +#define IPW_ORD_TABLE_6_MASK 0x0000F600 +#define IPW_ORD_TABLE_7_MASK 0x0000F700 + +/* + * Table 0 Entries (all entries are 32 bits) + */ +enum { + IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1, + IPW_ORD_STAT_FRAG_TRESHOLD, + IPW_ORD_STAT_RTS_THRESHOLD, + IPW_ORD_STAT_TX_HOST_REQUESTS, + IPW_ORD_STAT_TX_HOST_COMPLETE, + IPW_ORD_STAT_TX_DIR_DATA, + IPW_ORD_STAT_TX_DIR_DATA_B_1, + IPW_ORD_STAT_TX_DIR_DATA_B_2, + IPW_ORD_STAT_TX_DIR_DATA_B_5_5, + IPW_ORD_STAT_TX_DIR_DATA_B_11, + /* Hole */ + + IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19, + IPW_ORD_STAT_TX_DIR_DATA_G_2, + IPW_ORD_STAT_TX_DIR_DATA_G_5_5, + IPW_ORD_STAT_TX_DIR_DATA_G_6, + IPW_ORD_STAT_TX_DIR_DATA_G_9, + IPW_ORD_STAT_TX_DIR_DATA_G_11, + IPW_ORD_STAT_TX_DIR_DATA_G_12, + IPW_ORD_STAT_TX_DIR_DATA_G_18, + IPW_ORD_STAT_TX_DIR_DATA_G_24, + IPW_ORD_STAT_TX_DIR_DATA_G_36, + IPW_ORD_STAT_TX_DIR_DATA_G_48, + IPW_ORD_STAT_TX_DIR_DATA_G_54, + IPW_ORD_STAT_TX_NON_DIR_DATA, + IPW_ORD_STAT_TX_NON_DIR_DATA_B_1, + IPW_ORD_STAT_TX_NON_DIR_DATA_B_2, + IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5, + IPW_ORD_STAT_TX_NON_DIR_DATA_B_11, + /* Hole */ + + IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_2, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_6, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_9, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_11, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_12, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_18, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_24, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_36, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_48, + IPW_ORD_STAT_TX_NON_DIR_DATA_G_54, + IPW_ORD_STAT_TX_RETRY, + IPW_ORD_STAT_TX_FAILURE, + IPW_ORD_STAT_RX_ERR_CRC, + IPW_ORD_STAT_RX_ERR_ICV, + IPW_ORD_STAT_RX_NO_BUFFER, + IPW_ORD_STAT_FULL_SCANS, + IPW_ORD_STAT_PARTIAL_SCANS, + IPW_ORD_STAT_TGH_ABORTED_SCANS, + IPW_ORD_STAT_TX_TOTAL_BYTES, + IPW_ORD_STAT_CURR_RSSI_RAW, + IPW_ORD_STAT_RX_BEACON, + IPW_ORD_STAT_MISSED_BEACONS, + IPW_ORD_TABLE_0_LAST +}; + +#define IPW_RSSI_TO_DBM 112 + +/* Table 1 Entries + */ +enum { + IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1, +}; + +/* + * Table 2 Entries + * + * FW_VERSION: 16 byte string + * FW_DATE: 16 byte string (only 14 bytes used) + * UCODE_VERSION: 4 byte version code + * UCODE_DATE: 5 bytes code code + * ADDAPTER_MAC: 6 byte MAC address + * RTC: 4 byte clock + */ +enum { + IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1, + IPW_ORD_STAT_FW_DATE, + IPW_ORD_STAT_UCODE_VERSION, + IPW_ORD_STAT_UCODE_DATE, + IPW_ORD_STAT_ADAPTER_MAC, + IPW_ORD_STAT_RTC, + IPW_ORD_TABLE_2_LAST +}; + +/* Table 3 */ +enum { + IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0, + IPW_ORD_STAT_TX_PACKET_FAILURE, + IPW_ORD_STAT_TX_PACKET_SUCCESS, + IPW_ORD_STAT_TX_PACKET_ABORTED, + IPW_ORD_TABLE_3_LAST +}; + +/* Table 4 */ +enum { + IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK +}; + +/* Table 5 */ +enum { + IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK, + IPW_ORD_STAT_AP_ASSNS, + IPW_ORD_STAT_ROAM, + IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS, + IPW_ORD_STAT_ROAM_CAUSE_UNASSOC, + IPW_ORD_STAT_ROAM_CAUSE_RSSI, + IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY, + IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE, + IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX, + IPW_ORD_STAT_LINK_UP, + IPW_ORD_STAT_LINK_DOWN, + IPW_ORD_ANTENNA_DIVERSITY, + IPW_ORD_CURR_FREQ, + IPW_ORD_TABLE_5_LAST +}; + +/* Table 6 */ +enum { + IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK, + IPW_ORD_CURR_BSSID, + IPW_ORD_CURR_SSID, + IPW_ORD_TABLE_6_LAST +}; + +/* Table 7 */ +enum { + IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK, + IPW_ORD_STAT_PERCENT_TX_RETRIES, + IPW_ORD_STAT_PERCENT_LINK_QUALITY, + IPW_ORD_STAT_CURR_RSSI_DBM, + IPW_ORD_TABLE_7_LAST +}; + +#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410) +#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414) +#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500) +#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180) +#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184) +#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188) +#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C) + +struct ipw_fixed_rate { + __le16 tx_rates; + __le16 reserved; +} __attribute__ ((packed)); + +#define IPW_INDIRECT_ADDR_MASK (~0x3ul) + +struct host_cmd { + u8 cmd; + u8 len; + u16 reserved; + u32 *param; +} __attribute__ ((packed)); /* XXX */ + +struct cmdlog_host_cmd { + u8 cmd; + u8 len; + __le16 reserved; + char param[124]; +} __attribute__ ((packed)); + +struct ipw_cmd_log { + unsigned long jiffies; + int retcode; + struct cmdlog_host_cmd cmd; +}; + +/* SysConfig command parameters ... */ +/* bt_coexistence param */ +#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */ +#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */ +#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */ +#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */ +#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */ + +/* clear-to-send to self param */ +#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00 +#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x01 +#define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN + +/* Antenna diversity param (h/w can select best antenna, based on signal) */ +#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */ +#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */ +#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */ +#define CFG_SYS_ANTENNA_SLOW_DIV 0x02 /* consider background noise */ + +/* + * The definitions below were lifted off the ipw2100 driver, which only + * supports 'b' mode, so I'm sure these are not exactly correct. + * + * Somebody fix these!! + */ +#define REG_MIN_CHANNEL 0 +#define REG_MAX_CHANNEL 14 + +#define REG_CHANNEL_MASK 0x00003FFF +#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff + +#define IPW_MAX_CONFIG_RETRIES 10 + +#endif /* __ipw2200_h__ */ -- cgit v1.1 From beb2a7f331361bfe81e71acdb0739eae570475a2 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 11 Nov 2008 16:45:38 -0500 Subject: net/ieee80211 -> drivers/net/ipw2x00/libipw_* rename The old ieee80211 code only remains as a support library for the ipw2100 and ipw2200 drivers. So, move the code and rename it appropriately to reflects it's true purpose and status. Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/Kconfig | 45 +- drivers/net/wireless/ipw2x00/Makefile | 8 + drivers/net/wireless/ipw2x00/libipw_geo.c | 195 +++ drivers/net/wireless/ipw2x00/libipw_module.c | 293 +++++ drivers/net/wireless/ipw2x00/libipw_rx.c | 1799 ++++++++++++++++++++++++++ drivers/net/wireless/ipw2x00/libipw_tx.c | 546 ++++++++ drivers/net/wireless/ipw2x00/libipw_wx.c | 760 +++++++++++ 7 files changed, 3644 insertions(+), 2 deletions(-) create mode 100644 drivers/net/wireless/ipw2x00/libipw_geo.c create mode 100644 drivers/net/wireless/ipw2x00/libipw_module.c create mode 100644 drivers/net/wireless/ipw2x00/libipw_rx.c create mode 100644 drivers/net/wireless/ipw2x00/libipw_tx.c create mode 100644 drivers/net/wireless/ipw2x00/libipw_wx.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 67c57bf..3d5cc44 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -8,7 +8,7 @@ config IPW2100 select WIRELESS_EXT select FW_LOADER select LIB80211 - select IEEE80211 + select LIBIPW ---help--- A driver for the Intel PRO/Wireless 2100 Network Connection 802.11b wireless network adapter. @@ -67,7 +67,7 @@ config IPW2200 select WIRELESS_EXT select FW_LOADER select LIB80211 - select IEEE80211 + select LIBIPW ---help--- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network Connection adapters. @@ -148,3 +148,44 @@ config IPW2200_DEBUG If you are not sure, say N here. +config LIBIPW + tristate + select WIRELESS_EXT + select CRYPTO + select CRYPTO_ARC4 + select CRYPTO_ECB + select CRYPTO_AES + select CRYPTO_MICHAEL_MIC + select CRYPTO_ECB + select CRC32 + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_TKIP + select LIB80211_CRYPT_CCMP + ---help--- + This option enables the hardware independent IEEE 802.11 + networking stack. This component is deprecated in favor of the + mac80211 component. + +config LIBIPW_DEBUG + bool "Full debugging output for the LIBIPW component" + depends on LIBIPW + ---help--- + This option will enable debug tracing output for the + libipw component. + + This will result in the kernel module being ~70k larger. You + can control which debug output is sent to the kernel log by + setting the value in + + /proc/net/ieee80211/debug_level + + For example: + + % echo 0x00000FFO > /proc/net/ieee80211/debug_level + + For a list of values you can assign to debug_level, you + can look at the bit mask values in + + If you are not trying to debug or develop the libipw + component, you most likely want to say N here. diff --git a/drivers/net/wireless/ipw2x00/Makefile b/drivers/net/wireless/ipw2x00/Makefile index dbc0d81..aecd2cf 100644 --- a/drivers/net/wireless/ipw2x00/Makefile +++ b/drivers/net/wireless/ipw2x00/Makefile @@ -4,3 +4,11 @@ obj-$(CONFIG_IPW2100) += ipw2100.o obj-$(CONFIG_IPW2200) += ipw2200.o + +obj-$(CONFIG_LIBIPW) += libipw.o +libipw-objs := \ + libipw_module.o \ + libipw_tx.o \ + libipw_rx.o \ + libipw_wx.o \ + libipw_geo.o diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c new file mode 100644 index 0000000..960ad13 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -0,0 +1,195 @@ +/****************************************************************************** + + Copyright(c) 2005 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return 0; + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + /* NOTE: If G mode is currently supported but + * this is a B only channel, we don't see it + * as valid. */ + if ((ieee->geo.bg[i].channel == channel) && + !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) && + (!(ieee->mode & IEEE_G) || + !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) + return IEEE80211_24GHZ_BAND; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if ((ieee->geo.a[i].channel == channel) && + !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID)) + return IEEE80211_52GHZ_BAND; + + return 0; +} + +int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return -1; + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + if (ieee->geo.bg[i].channel == channel) + return i; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].channel == channel) + return i; + + return -1; +} + +u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel) +{ + const struct ieee80211_channel * ch; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return 0; + + ch = ieee80211_get_channel(ieee, channel); + if (!ch->channel) + return 0; + return ch->freq; +} + +u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return 0; + + freq /= 100000; + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + if (ieee->geo.bg[i].freq == freq) + return ieee->geo.bg[i].channel; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].freq == freq) + return ieee->geo.a[i].channel; + + return 0; +} + +int ieee80211_set_geo(struct ieee80211_device *ieee, + const struct ieee80211_geo *geo) +{ + memcpy(ieee->geo.name, geo->name, 3); + ieee->geo.name[3] = '\0'; + ieee->geo.bg_channels = geo->bg_channels; + ieee->geo.a_channels = geo->a_channels; + memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * + sizeof(struct ieee80211_channel)); + memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * + sizeof(struct ieee80211_channel)); + return 0; +} + +const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee) +{ + return &ieee->geo; +} + +u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel) +{ + int index = ieee80211_channel_to_index(ieee, channel); + + if (index == -1) + return IEEE80211_CH_INVALID; + + if (channel <= IEEE80211_24GHZ_CHANNELS) + return ieee->geo.bg[index].flags; + + return ieee->geo.a[index].flags; +} + +static const struct ieee80211_channel bad_channel = { + .channel = 0, + .flags = IEEE80211_CH_INVALID, + .max_power = 0, +}; + +const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device + *ieee, u8 channel) +{ + int index = ieee80211_channel_to_index(ieee, channel); + + if (index == -1) + return &bad_channel; + + if (channel <= IEEE80211_24GHZ_CHANNELS) + return &ieee->geo.bg[index]; + + return &ieee->geo.a[index]; +} + +EXPORT_SYMBOL(ieee80211_get_channel); +EXPORT_SYMBOL(ieee80211_get_channel_flags); +EXPORT_SYMBOL(ieee80211_is_valid_channel); +EXPORT_SYMBOL(ieee80211_freq_to_channel); +EXPORT_SYMBOL(ieee80211_channel_to_freq); +EXPORT_SYMBOL(ieee80211_channel_to_index); +EXPORT_SYMBOL(ieee80211_set_geo); +EXPORT_SYMBOL(ieee80211_get_geo); diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c new file mode 100644 index 0000000..a2f5616 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -0,0 +1,293 @@ +/******************************************************************************* + + Copyright(c) 2004-2005 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRV_DESCRIPTION "802.11 data/management/control stack" +#define DRV_NAME "ieee80211" +#define DRV_VERSION IEEE80211_VERSION +#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation " + +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +static int ieee80211_networks_allocate(struct ieee80211_device *ieee) +{ + if (ieee->networks) + return 0; + + ieee->networks = + kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), + GFP_KERNEL); + if (!ieee->networks) { + printk(KERN_WARNING "%s: Out of memory allocating beacons\n", + ieee->dev->name); + return -ENOMEM; + } + + return 0; +} + +void ieee80211_network_reset(struct ieee80211_network *network) +{ + if (!network) + return; + + if (network->ibss_dfs) { + kfree(network->ibss_dfs); + network->ibss_dfs = NULL; + } +} + +static inline void ieee80211_networks_free(struct ieee80211_device *ieee) +{ + int i; + + if (!ieee->networks) + return; + + for (i = 0; i < MAX_NETWORK_COUNT; i++) + if (ieee->networks[i].ibss_dfs) + kfree(ieee->networks[i].ibss_dfs); + + kfree(ieee->networks); + ieee->networks = NULL; +} + +static void ieee80211_networks_initialize(struct ieee80211_device *ieee) +{ + int i; + + INIT_LIST_HEAD(&ieee->network_free_list); + INIT_LIST_HEAD(&ieee->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) + list_add_tail(&ieee->networks[i].list, + &ieee->network_free_list); +} + +static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static struct net_device_stats *ieee80211_generic_get_stats( + struct net_device *dev) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + return &ieee->stats; +} + +struct net_device *alloc_ieee80211(int sizeof_priv) +{ + struct ieee80211_device *ieee; + struct net_device *dev; + int err; + + IEEE80211_DEBUG_INFO("Initializing...\n"); + + dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); + if (!dev) { + IEEE80211_ERROR("Unable to allocate network device.\n"); + goto failed; + } + ieee = netdev_priv(dev); + dev->hard_start_xmit = ieee80211_xmit; + dev->change_mtu = ieee80211_change_mtu; + + /* Drivers are free to override this if the generic implementation + * does not meet their needs. */ + dev->get_stats = ieee80211_generic_get_stats; + + ieee->dev = dev; + + err = ieee80211_networks_allocate(ieee); + if (err) { + IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err); + goto failed_free_netdev; + } + ieee80211_networks_initialize(ieee); + + /* Default fragmentation threshold is maximum payload size */ + ieee->fts = DEFAULT_FTS; + ieee->rts = DEFAULT_FTS; + ieee->scan_age = DEFAULT_MAX_SCAN_AGE; + ieee->open_wep = 1; + + /* Default to enabling full open WEP with host based encrypt/decrypt */ + ieee->host_encrypt = 1; + ieee->host_decrypt = 1; + ieee->host_mc_decrypt = 1; + + /* Host fragementation in Open mode. Default is enabled. + * Note: host fragmentation is always enabled if host encryption + * is enabled. For cards can do hardware encryption, they must do + * hardware fragmentation as well. So we don't need a variable + * like host_enc_frag. */ + ieee->host_open_frag = 1; + ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ + + spin_lock_init(&ieee->lock); + + lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); + + ieee->wpa_enabled = 0; + ieee->drop_unencrypted = 0; + ieee->privacy_invoked = 0; + + return dev; + +failed_free_netdev: + free_netdev(dev); +failed: + return NULL; +} + +void free_ieee80211(struct net_device *dev) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + + lib80211_crypt_info_free(&ieee->crypt_info); + + ieee80211_networks_free(ieee); + free_netdev(dev); +} + +#ifdef CONFIG_IEEE80211_DEBUG + +static int debug = 0; +u32 ieee80211_debug_level = 0; +EXPORT_SYMBOL_GPL(ieee80211_debug_level); +static struct proc_dir_entry *ieee80211_proc = NULL; + +static int show_debug_level(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); +} + +static int store_debug_level(struct file *file, const char __user * buffer, + unsigned long count, void *data) +{ + char buf[] = "0x00000000\n"; + unsigned long len = min((unsigned long)sizeof(buf) - 1, count); + unsigned long val; + + if (copy_from_user(buf, buffer, len)) + return count; + buf[len] = 0; + if (sscanf(buf, "%li", &val) != 1) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + ieee80211_debug_level = val; + + return strnlen(buf, len); +} +#endif /* CONFIG_IEEE80211_DEBUG */ + +static int __init ieee80211_init(void) +{ +#ifdef CONFIG_IEEE80211_DEBUG + struct proc_dir_entry *e; + + ieee80211_debug_level = debug; + ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net); + if (ieee80211_proc == NULL) { + IEEE80211_ERROR("Unable to create " DRV_NAME + " proc directory\n"); + return -EIO; + } + e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, + ieee80211_proc); + if (!e) { + remove_proc_entry(DRV_NAME, init_net.proc_net); + ieee80211_proc = NULL; + return -EIO; + } + e->read_proc = show_debug_level; + e->write_proc = store_debug_level; + e->data = NULL; +#endif /* CONFIG_IEEE80211_DEBUG */ + + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + return 0; +} + +static void __exit ieee80211_exit(void) +{ +#ifdef CONFIG_IEEE80211_DEBUG + if (ieee80211_proc) { + remove_proc_entry("debug_level", ieee80211_proc); + remove_proc_entry(DRV_NAME, init_net.proc_net); + ieee80211_proc = NULL; + } +#endif /* CONFIG_IEEE80211_DEBUG */ +} + +#ifdef CONFIG_IEEE80211_DEBUG +#include +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); +#endif /* CONFIG_IEEE80211_DEBUG */ + +module_exit(ieee80211_exit); +module_init(ieee80211_init); + +EXPORT_SYMBOL(alloc_ieee80211); +EXPORT_SYMBOL(free_ieee80211); diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c new file mode 100644 index 0000000..9c67dfa --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -0,0 +1,1799 @@ +/* + * Original code based Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3 - hostap.o module, common routines + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * Copyright (c) 2004-2005, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void ieee80211_monitor_rx(struct ieee80211_device *ieee, + struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_control); + + skb->dev = ieee->dev; + skb_reset_mac_header(skb); + skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + +/* Called only as a tasklet (software IRQ) */ +static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct + ieee80211_device + *ieee, + unsigned int seq, + unsigned int frag, + u8 * src, + u8 * dst) +{ + struct ieee80211_frag_entry *entry; + int i; + + for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { + entry = &ieee->frag_cache[i]; + if (entry->skb != NULL && + time_after(jiffies, entry->first_frag_time + 2 * HZ)) { + IEEE80211_DEBUG_FRAG("expiring fragment cache entry " + "seq=%u last_frag=%u\n", + entry->seq, entry->last_frag); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; + } + + if (entry->skb != NULL && entry->seq == seq && + (entry->last_frag + 1 == frag || frag == -1) && + !compare_ether_addr(entry->src_addr, src) && + !compare_ether_addr(entry->dst_addr, dst)) + return entry; + } + + return NULL; +} + +/* Called only as a tasklet (software IRQ) */ +static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *hdr) +{ + struct sk_buff *skb = NULL; + u16 sc; + unsigned int frag, seq; + struct ieee80211_frag_entry *entry; + + sc = le16_to_cpu(hdr->seq_ctl); + frag = WLAN_GET_SEQ_FRAG(sc); + seq = WLAN_GET_SEQ_SEQ(sc); + + if (frag == 0) { + /* Reserve enough space to fit maximum frame length */ + skb = dev_alloc_skb(ieee->dev->mtu + + sizeof(struct ieee80211_hdr_4addr) + + 8 /* LLC */ + + 2 /* alignment */ + + 8 /* WEP */ + ETH_ALEN /* WDS */ ); + if (skb == NULL) + return NULL; + + entry = &ieee->frag_cache[ieee->frag_next_idx]; + ieee->frag_next_idx++; + if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN) + ieee->frag_next_idx = 0; + + if (entry->skb != NULL) + dev_kfree_skb_any(entry->skb); + + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->last_frag = frag; + entry->skb = skb; + memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); + memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); + } else { + /* received a fragment of a frame for which the head fragment + * should have already been received */ + entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2, + hdr->addr1); + if (entry != NULL) { + entry->last_frag = frag; + skb = entry->skb; + } + } + + return skb; +} + +/* Called only as a tasklet (software IRQ) */ +static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *hdr) +{ + u16 sc; + unsigned int seq; + struct ieee80211_frag_entry *entry; + + sc = le16_to_cpu(hdr->seq_ctl); + seq = WLAN_GET_SEQ_SEQ(sc); + + entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2, + hdr->addr1); + + if (entry == NULL) { + IEEE80211_DEBUG_FRAG("could not invalidate fragment cache " + "entry (seq=%u)\n", seq); + return -1; + } + + entry->skb = NULL; + return 0; +} + +#ifdef NOT_YET +/* ieee80211_rx_frame_mgtmt + * + * Responsible for handling management control frames + * + * Called by ieee80211_rx */ +static int +ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype) +{ + if (ieee->iw_mode == IW_MODE_MASTER) { + printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", + ieee->dev->name); + return 0; +/* + hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *) + skb->data);*/ + } + + if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) { + if (stype == WLAN_FC_STYPE_BEACON && + ieee->iw_mode == IW_MODE_MASTER) { + struct sk_buff *skb2; + /* Process beacon frames also in kernel driver to + * update STA(AP) table statistics */ + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + hostap_rx(skb2->dev, skb2, rx_stats); + } + + /* send management frames to the user space daemon for + * processing */ + ieee->apdevstats.rx_packets++; + ieee->apdevstats.rx_bytes += skb->len; + prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); + return 0; + } + + if (ieee->iw_mode == IW_MODE_MASTER) { + if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { + printk(KERN_DEBUG "%s: unknown management frame " + "(type=0x%02x, stype=0x%02x) dropped\n", + skb->dev->name, type, stype); + return -1; + } + + hostap_rx(skb->dev, skb, rx_stats); + return 0; + } + + printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " + "received in non-Host AP mode\n", skb->dev->name); + return -1; +} +#endif + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ + +/* Called by ieee80211_rx_frame_decrypt */ +static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, + struct sk_buff *skb) +{ + struct net_device *dev = ieee->dev; + u16 fc, ethertype; + struct ieee80211_hdr_3addr *hdr; + u8 *pos; + + if (skb->len < 24) + return 0; + + hdr = (struct ieee80211_hdr_3addr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + + /* check that the frame is unicast frame to us */ + if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_TODS && + !compare_ether_addr(hdr->addr1, dev->dev_addr) && + !compare_ether_addr(hdr->addr3, dev->dev_addr)) { + /* ToDS frame with own addr BSSID and DA */ + } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_FROMDS && + !compare_ether_addr(hdr->addr1, dev->dev_addr)) { + /* FromDS frame with own addr as DA */ + } else + return 0; + + if (skb->len < 24 + 8) + return 0; + + /* check for port access entity Ethernet type */ + pos = skb->data + 24; + ethertype = (pos[6] << 8) | pos[7]; + if (ethertype == ETH_P_PAE) + return 1; + + return 0; +} + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static int +ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, + struct lib80211_crypt_data *crypt) +{ + struct ieee80211_hdr_3addr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) + return 0; + + hdr = (struct ieee80211_hdr_3addr *)skb->data; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", + hdr->addr2, res); + if (res == -2) + IEEE80211_DEBUG_DROP("Decryption failed ICV " + "mismatch (key %d)\n", + skb->data[hdrlen + 3] >> 6); + ieee->ieee_stats.rx_discards_undecryptable++; + return -1; + } + + return res; +} + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static int +ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, + struct sk_buff *skb, int keyidx, + struct lib80211_crypt_data *crypt) +{ + struct ieee80211_hdr_3addr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) + return 0; + + hdr = (struct ieee80211_hdr_3addr *)skb->data; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" + " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2, + keyidx); + return -1; + } + + return 0; +} + +/* All received frames are sent to this function. @skb contains the frame in + * IEEE 802.11 format, i.e., in the format it was sent over air. + * This function is called only as a tasklet (software IRQ). */ +int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) +{ + struct net_device *dev = ieee->dev; + struct ieee80211_hdr_4addr *hdr; + size_t hdrlen; + u16 fc, type, stype, sc; + struct net_device_stats *stats; + unsigned int frag; + u8 *payload; + u16 ethertype; +#ifdef NOT_YET + struct net_device *wds = NULL; + struct sk_buff *skb2 = NULL; + struct net_device *wds = NULL; + int frame_authorized = 0; + int from_assoc_ap = 0; + void *sta = NULL; +#endif + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + struct lib80211_crypt_data *crypt = NULL; + int keyidx = 0; + int can_be_decrypted = 0; + + hdr = (struct ieee80211_hdr_4addr *)skb->data; + stats = &ieee->stats; + + if (skb->len < 10) { + printk(KERN_INFO "%s: SKB length < 10\n", dev->name); + goto rx_dropped; + } + + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + sc = le16_to_cpu(hdr->seq_ctl); + frag = WLAN_GET_SEQ_FRAG(sc); + hdrlen = ieee80211_get_hdrlen(fc); + + if (skb->len < hdrlen) { + printk(KERN_INFO "%s: invalid SKB length %d\n", + dev->name, skb->len); + goto rx_dropped; + } + + /* Put this code here so that we avoid duplicating it in all + * Rx paths. - Jean II */ +#ifdef CONFIG_WIRELESS_EXT +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + /* If spy monitoring on */ + if (ieee->spy_data.spy_number > 0) { + struct iw_quality wstats; + + wstats.updated = 0; + if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { + wstats.level = rx_stats->signal; + wstats.updated |= IW_QUAL_LEVEL_UPDATED; + } else + wstats.updated |= IW_QUAL_LEVEL_INVALID; + + if (rx_stats->mask & IEEE80211_STATMASK_NOISE) { + wstats.noise = rx_stats->noise; + wstats.updated |= IW_QUAL_NOISE_UPDATED; + } else + wstats.updated |= IW_QUAL_NOISE_INVALID; + + if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) { + wstats.qual = rx_stats->signal; + wstats.updated |= IW_QUAL_QUAL_UPDATED; + } else + wstats.updated |= IW_QUAL_QUAL_INVALID; + + /* Update spy records */ + wireless_spy_update(ieee->dev, hdr->addr2, &wstats); + } +#endif /* IW_WIRELESS_SPY */ +#endif /* CONFIG_WIRELESS_EXT */ + +#ifdef NOT_YET + hostap_update_rx_stats(local->ap, hdr, rx_stats); +#endif + + if (ieee->iw_mode == IW_MODE_MONITOR) { + stats->rx_packets++; + stats->rx_bytes += skb->len; + ieee80211_monitor_rx(ieee, skb, rx_stats); + return 1; + } + + can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) || + is_broadcast_ether_addr(hdr->addr2)) ? + ieee->host_mc_decrypt : ieee->host_decrypt; + + if (can_be_decrypted) { + if (skb->len >= hdrlen + 3) { + /* Top two-bits of byte 3 are the key index */ + keyidx = skb->data[hdrlen + 3] >> 6; + } + + /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx + * is only allowed 2-bits of storage, no value of keyidx can + * be provided via above code that would result in keyidx + * being out of range */ + crypt = ieee->crypt_info.crypt[keyidx]; + +#ifdef NOT_YET + sta = NULL; + + /* Use station specific key to override default keys if the + * receiver address is a unicast address ("individual RA"). If + * bcrx_sta_key parameter is set, station specific key is used + * even with broad/multicast targets (this is against IEEE + * 802.11, but makes it easier to use different keys with + * stations that do not support WEP key mapping). */ + + if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) + (void)hostap_handle_sta_crypto(local, hdr, &crypt, + &sta); +#endif + + /* allow NULL decrypt to indicate an station specific override + * for default encryption */ + if (crypt && (crypt->ops == NULL || + crypt->ops->decrypt_mpdu == NULL)) + crypt = NULL; + + if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { + /* This seems to be triggered by some (multicast?) + * frames from other than current BSS, so just drop the + * frames silently instead of filling system log with + * these reports. */ + IEEE80211_DEBUG_DROP("Decryption failed (not set)" + " (SA=%pM)\n", hdr->addr2); + ieee->ieee_stats.rx_discards_undecryptable++; + goto rx_dropped; + } + } +#ifdef NOT_YET + if (type != WLAN_FC_TYPE_DATA) { + if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH && + fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt && + (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) { + printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " + "from %pM\n", dev->name, hdr->addr2); + /* TODO: could inform hostapd about this so that it + * could send auth failure report */ + goto rx_dropped; + } + + if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) + goto rx_dropped; + else + goto rx_exit; + } +#endif + /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */ + if (sc == ieee->prev_seq_ctl) + goto rx_dropped; + else + ieee->prev_seq_ctl = sc; + + /* Data frame - extract src/dst addresses */ + if (skb->len < IEEE80211_3ADDR_LEN) + goto rx_dropped; + + switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_FROMDS: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + break; + case IEEE80211_FCTL_TODS: + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + if (skb->len < IEEE80211_4ADDR_LEN) + goto rx_dropped; + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + break; + case 0: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + break; + } + +#ifdef NOT_YET + if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) + goto rx_dropped; + if (wds) { + skb->dev = dev = wds; + stats = hostap_get_stats(dev); + } + + if (ieee->iw_mode == IW_MODE_MASTER && !wds && + (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_FROMDS && ieee->stadev + && !compare_ether_addr(hdr->addr2, ieee->assoc_ap_addr)) { + /* Frame from BSSID of the AP for which we are a client */ + skb->dev = dev = ieee->stadev; + stats = hostap_get_stats(dev); + from_assoc_ap = 1; + } +#endif + +#ifdef NOT_YET + if ((ieee->iw_mode == IW_MODE_MASTER || + ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { + switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, + wds != NULL)) { + case AP_RX_CONTINUE_NOT_AUTHORIZED: + frame_authorized = 0; + break; + case AP_RX_CONTINUE: + frame_authorized = 1; + break; + case AP_RX_DROP: + goto rx_dropped; + case AP_RX_EXIT: + goto rx_exit; + } + } +#endif + + /* Nullfunc frames may have PS-bit set, so they must be passed to + * hostap_handle_sta_rx() before being dropped here. */ + + stype &= ~IEEE80211_STYPE_QOS_DATA; + + if (stype != IEEE80211_STYPE_DATA && + stype != IEEE80211_STYPE_DATA_CFACK && + stype != IEEE80211_STYPE_DATA_CFPOLL && + stype != IEEE80211_STYPE_DATA_CFACKPOLL) { + if (stype != IEEE80211_STYPE_NULLFUNC) + IEEE80211_DEBUG_DROP("RX: dropped data frame " + "with no data (type=0x%02x, " + "subtype=0x%02x, len=%d)\n", + type, stype, skb->len); + goto rx_dropped; + } + + /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ + + if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && + (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) + goto rx_dropped; + + hdr = (struct ieee80211_hdr_4addr *)skb->data; + + /* skb: hdr + (possibly fragmented) plaintext payload */ + // PR: FIXME: hostap has additional conditions in the "if" below: + // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && + if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) { + int flen; + struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); + IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); + + if (!frag_skb) { + IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, + "Rx cannot get skb from fragment " + "cache (morefrag=%d seq=%u frag=%u)\n", + (fc & IEEE80211_FCTL_MOREFRAGS) != 0, + WLAN_GET_SEQ_SEQ(sc), frag); + goto rx_dropped; + } + + flen = skb->len; + if (frag != 0) + flen -= hdrlen; + + if (frag_skb->tail + flen > frag_skb->end) { + printk(KERN_WARNING "%s: host decrypted and " + "reassembled frame did not fit skb\n", + dev->name); + ieee80211_frag_cache_invalidate(ieee, hdr); + goto rx_dropped; + } + + if (frag == 0) { + /* copy first fragment (including full headers) into + * beginning of the fragment cache skb */ + skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen); + } else { + /* append frame payload to the end of the fragment + * cache skb */ + skb_copy_from_linear_data_offset(skb, hdrlen, + skb_put(frag_skb, flen), flen); + } + dev_kfree_skb_any(skb); + skb = NULL; + + if (fc & IEEE80211_FCTL_MOREFRAGS) { + /* more fragments expected - leave the skb in fragment + * cache for now; it will be delivered to upper layers + * after all fragments have been received */ + goto rx_exit; + } + + /* this was the last fragment and the frame will be + * delivered, so remove skb from fragment cache */ + skb = frag_skb; + hdr = (struct ieee80211_hdr_4addr *)skb->data; + ieee80211_frag_cache_invalidate(ieee, hdr); + } + + /* skb: hdr + (possible reassembled) full MSDU payload; possibly still + * encrypted/authenticated */ + if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && + ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) + goto rx_dropped; + + hdr = (struct ieee80211_hdr_4addr *)skb->data; + if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { + if ( /*ieee->ieee802_1x && */ + ieee80211_is_eapol_frame(ieee, skb)) { + /* pass unencrypted EAPOL frames even if encryption is + * configured */ + } else { + IEEE80211_DEBUG_DROP("encryption configured, but RX " + "frame not encrypted (SA=%pM)\n", + hdr->addr2); + goto rx_dropped; + } + } + + if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && + !ieee80211_is_eapol_frame(ieee, skb)) { + IEEE80211_DEBUG_DROP("dropped unencrypted RX data " + "frame from %pM (drop_unencrypted=1)\n", + hdr->addr2); + goto rx_dropped; + } + + /* If the frame was decrypted in hardware, we may need to strip off + * any security data (IV, ICV, etc) that was left behind */ + if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) && + ieee->host_strip_iv_icv) { + int trimlen = 0; + + /* Top two-bits of byte 3 are the key index */ + if (skb->len >= hdrlen + 3) + keyidx = skb->data[hdrlen + 3] >> 6; + + /* To strip off any security data which appears before the + * payload, we simply increase hdrlen (as the header gets + * chopped off immediately below). For the security data which + * appears after the payload, we use skb_trim. */ + + switch (ieee->sec.encode_alg[keyidx]) { + case SEC_ALG_WEP: + /* 4 byte IV */ + hdrlen += 4; + /* 4 byte ICV */ + trimlen = 4; + break; + case SEC_ALG_TKIP: + /* 4 byte IV, 4 byte ExtIV */ + hdrlen += 8; + /* 8 byte MIC, 4 byte ICV */ + trimlen = 12; + break; + case SEC_ALG_CCMP: + /* 8 byte CCMP header */ + hdrlen += 8; + /* 8 byte MIC */ + trimlen = 8; + break; + } + + if (skb->len < trimlen) + goto rx_dropped; + + __skb_trim(skb, skb->len - trimlen); + + if (skb->len < hdrlen) + goto rx_dropped; + } + + /* skb: hdr + (possible reassembled) full plaintext payload */ + + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + +#ifdef NOT_YET + /* If IEEE 802.1X is used, check whether the port is authorized to send + * the received frame. */ + if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) { + if (ethertype == ETH_P_PAE) { + printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", + dev->name); + if (ieee->hostapd && ieee->apdev) { + /* Send IEEE 802.1X frames to the user + * space daemon for processing */ + prism2_rx_80211(ieee->apdev, skb, rx_stats, + PRISM2_RX_MGMT); + ieee->apdevstats.rx_packets++; + ieee->apdevstats.rx_bytes += skb->len; + goto rx_exit; + } + } else if (!frame_authorized) { + printk(KERN_DEBUG "%s: dropped frame from " + "unauthorized port (IEEE 802.1X): " + "ethertype=0x%04x\n", dev->name, ethertype); + goto rx_dropped; + } + } +#endif + + /* convert hdr + possible LLC headers into Ethernet header */ + if (skb->len - hdrlen >= 8 && + ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + SNAP_SIZE); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + __be16 len; + /* Leave Ethernet header part of hdr and full payload */ + skb_pull(skb, hdrlen); + len = htons(skb->len); + memcpy(skb_push(skb, 2), &len, 2); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } + +#ifdef NOT_YET + if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) { + /* Non-standard frame: get addr4 from its bogus location after + * the payload */ + skb_copy_to_linear_data_offset(skb, ETH_ALEN, + skb->data + skb->len - ETH_ALEN, + ETH_ALEN); + skb_trim(skb, skb->len - ETH_ALEN); + } +#endif + + stats->rx_packets++; + stats->rx_bytes += skb->len; + +#ifdef NOT_YET + if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) { + if (dst[0] & 0x01) { + /* copy multicast frame both to the higher layers and + * to the wireless media */ + ieee->ap->bridged_multicast++; + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2 == NULL) + printk(KERN_DEBUG "%s: skb_clone failed for " + "multicast frame\n", dev->name); + } else if (hostap_is_sta_assoc(ieee->ap, dst)) { + /* send frame directly to the associated STA using + * wireless media and not passing to higher layers */ + ieee->ap->bridged_unicast++; + skb2 = skb; + skb = NULL; + } + } + + if (skb2 != NULL) { + /* send to wireless media */ + skb2->dev = dev; + skb2->protocol = htons(ETH_P_802_3); + skb_reset_mac_header(skb2); + skb_reset_network_header(skb2); + /* skb2->network_header += ETH_HLEN; */ + dev_queue_xmit(skb2); + } +#endif + + if (skb) { + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ + if (netif_rx(skb) == NET_RX_DROP) { + /* netif_rx always succeeds, but it might drop + * the packet. If it drops the packet, we log that + * in our stats. */ + IEEE80211_DEBUG_DROP + ("RX: netif_rx dropped the packet\n"); + stats->rx_dropped++; + } + } + + rx_exit: +#ifdef NOT_YET + if (sta) + hostap_handle_sta_release(sta); +#endif + return 1; + + rx_dropped: + stats->rx_dropped++; + + /* Returning 0 indicates to caller that we have not handled the SKB-- + * so it is still allocated and can be used again by underlying + * hardware as a DMA target */ + return 0; +} + +/* Filter out unrelated packets, call ieee80211_rx[_mgt] + * This function takes over the skb, it should not be used again after calling + * this function. */ +void ieee80211_rx_any(struct ieee80211_device *ieee, + struct sk_buff *skb, struct ieee80211_rx_stats *stats) +{ + struct ieee80211_hdr_4addr *hdr; + int is_packet_for_us; + u16 fc; + + if (ieee->iw_mode == IW_MODE_MONITOR) { + if (!ieee80211_rx(ieee, skb, stats)) + dev_kfree_skb_irq(skb); + return; + } + + if (skb->len < sizeof(struct ieee80211_hdr)) + goto drop_free; + + hdr = (struct ieee80211_hdr_4addr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + + if ((fc & IEEE80211_FCTL_VERS) != 0) + goto drop_free; + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + if (skb->len < sizeof(struct ieee80211_hdr_3addr)) + goto drop_free; + ieee80211_rx_mgt(ieee, hdr, stats); + dev_kfree_skb_irq(skb); + return; + case IEEE80211_FTYPE_DATA: + break; + case IEEE80211_FTYPE_CTL: + return; + default: + return; + } + + is_packet_for_us = 0; + switch (ieee->iw_mode) { + case IW_MODE_ADHOC: + /* our BSS and not from/to DS */ + if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0) + if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) { + /* promisc: get all */ + if (ieee->dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + /* to us */ + else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0) + is_packet_for_us = 1; + /* mcast */ + else if (is_multicast_ether_addr(hdr->addr1)) + is_packet_for_us = 1; + } + break; + case IW_MODE_INFRA: + /* our BSS (== from our AP) and from DS */ + if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0) + if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) { + /* promisc: get all */ + if (ieee->dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + /* to us */ + else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0) + is_packet_for_us = 1; + /* mcast */ + else if (is_multicast_ether_addr(hdr->addr1)) { + /* not our own packet bcasted from AP */ + if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN)) + is_packet_for_us = 1; + } + } + break; + default: + /* ? */ + break; + } + + if (is_packet_for_us) + if (!ieee80211_rx(ieee, skb, stats)) + dev_kfree_skb_irq(skb); + return; + +drop_free: + dev_kfree_skb_irq(skb); + ieee->stats.rx_dropped++; + return; +} + +#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 + +static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; + +/* +* Make ther structure we read from the beacon packet has +* the right values +*/ +static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element + *info_element, int sub_type) +{ + + if (info_element->qui_subtype != sub_type) + return -1; + if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) + return -1; + if (info_element->qui_type != QOS_OUI_TYPE) + return -1; + if (info_element->version != QOS_VERSION_1) + return -1; + + return 0; +} + +/* + * Parse a QoS parameter element + */ +static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info + *element_param, struct ieee80211_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; + + if ((info_element == NULL) || (element_param == NULL)) + return -1; + + if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { + memcpy(element_param->info_element.qui, info_element->data, + info_element->len); + element_param->info_element.elementID = info_element->id; + element_param->info_element.length = info_element->len; + } else + ret = -1; + if (ret == 0) + ret = ieee80211_verify_qos_info(&element_param->info_element, + QOS_OUI_PARAM_SUB_TYPE); + return ret; +} + +/* + * Parse a QoS information element + */ +static int ieee80211_read_qos_info_element(struct + ieee80211_qos_information_element + *element_info, struct ieee80211_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct ieee80211_qos_information_element) - 2; + + if (element_info == NULL) + return -1; + if (info_element == NULL) + return -1; + + if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { + memcpy(element_info->qui, info_element->data, + info_element->len); + element_info->elementID = info_element->id; + element_info->length = info_element->len; + } else + ret = -1; + + if (ret == 0) + ret = ieee80211_verify_qos_info(element_info, + QOS_OUI_INFO_SUB_TYPE); + return ret; +} + +/* + * Write QoS parameters from the ac parameters. + */ +static int ieee80211_qos_convert_ac_to_parameters(struct + ieee80211_qos_parameter_info + *param_elm, struct + ieee80211_qos_parameters + *qos_param) +{ + int rc = 0; + int i; + struct ieee80211_qos_ac_parameter *ac_params; + u32 txop; + u8 cw_min; + u8 cw_max; + + for (i = 0; i < QOS_QUEUE_NUM; i++) { + ac_params = &(param_elm->ac_params_record[i]); + + qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F; + qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2; + + cw_min = ac_params->ecw_min_max & 0x0F; + qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1); + + cw_max = (ac_params->ecw_min_max & 0xF0) >> 4; + qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1); + + qos_param->flag[i] = + (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; + + txop = le16_to_cpu(ac_params->tx_op_limit) * 32; + qos_param->tx_op_limit[i] = cpu_to_le16(txop); + } + return rc; +} + +/* + * we have a generic data element which it may contain QoS information or + * parameters element. check the information element length to decide + * which type to read + */ +static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element + *info_element, + struct ieee80211_network *network) +{ + int rc = 0; + struct ieee80211_qos_parameters *qos_param = NULL; + struct ieee80211_qos_information_element qos_info_element; + + rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); + + if (rc == 0) { + network->qos_data.param_count = qos_info_element.ac_info & 0x0F; + network->flags |= NETWORK_HAS_QOS_INFORMATION; + } else { + struct ieee80211_qos_parameter_info param_element; + + rc = ieee80211_read_qos_param_element(¶m_element, + info_element); + if (rc == 0) { + qos_param = &(network->qos_data.parameters); + ieee80211_qos_convert_ac_to_parameters(¶m_element, + qos_param); + network->flags |= NETWORK_HAS_QOS_PARAMETERS; + network->qos_data.param_count = + param_element.info_element.ac_info & 0x0F; + } + } + + if (rc == 0) { + IEEE80211_DEBUG_QOS("QoS is supported\n"); + network->qos_data.supported = 1; + } + return rc; +} + +#ifdef CONFIG_IEEE80211_DEBUG +#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x + +static const char *get_info_element_string(u16 id) +{ + switch (id) { + MFIE_STRING(SSID); + MFIE_STRING(RATES); + MFIE_STRING(FH_SET); + MFIE_STRING(DS_SET); + MFIE_STRING(CF_SET); + MFIE_STRING(TIM); + MFIE_STRING(IBSS_SET); + MFIE_STRING(COUNTRY); + MFIE_STRING(HOP_PARAMS); + MFIE_STRING(HOP_TABLE); + MFIE_STRING(REQUEST); + MFIE_STRING(CHALLENGE); + MFIE_STRING(POWER_CONSTRAINT); + MFIE_STRING(POWER_CAPABILITY); + MFIE_STRING(TPC_REQUEST); + MFIE_STRING(TPC_REPORT); + MFIE_STRING(SUPP_CHANNELS); + MFIE_STRING(CSA); + MFIE_STRING(MEASURE_REQUEST); + MFIE_STRING(MEASURE_REPORT); + MFIE_STRING(QUIET); + MFIE_STRING(IBSS_DFS); + MFIE_STRING(ERP_INFO); + MFIE_STRING(RSN); + MFIE_STRING(RATES_EX); + MFIE_STRING(GENERIC); + MFIE_STRING(QOS_PARAMETER); + default: + return "UNKNOWN"; + } +} +#endif + +static int ieee80211_parse_info_param(struct ieee80211_info_element + *info_element, u16 length, + struct ieee80211_network *network) +{ + DECLARE_SSID_BUF(ssid); + u8 i; +#ifdef CONFIG_IEEE80211_DEBUG + char rates_str[64]; + char *p; +#endif + + while (length >= sizeof(*info_element)) { + if (sizeof(*info_element) + info_element->len > length) { + IEEE80211_DEBUG_MGMT("Info elem: parse failed: " + "info_element->len + 2 > left : " + "info_element->len+2=%zd left=%d, id=%d.\n", + info_element->len + + sizeof(*info_element), + length, info_element->id); + /* We stop processing but don't return an error here + * because some misbehaviour APs break this rule. ie. + * Orinoco AP1000. */ + break; + } + + switch (info_element->id) { + case MFIE_TYPE_SSID: + network->ssid_len = min(info_element->len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(network->ssid, info_element->data, + network->ssid_len); + if (network->ssid_len < IW_ESSID_MAX_SIZE) + memset(network->ssid + network->ssid_len, 0, + IW_ESSID_MAX_SIZE - network->ssid_len); + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->ssid_len); + break; + + case MFIE_TYPE_RATES: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_len = min(info_element->len, + MAX_RATES_LENGTH); + for (i = 0; i < network->rates_len; i++) { + network->rates[i] = info_element->data[i]; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n", + rates_str, network->rates_len); + break; + + case MFIE_TYPE_RATES_EX: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_ex_len = min(info_element->len, + MAX_RATES_EX_LENGTH); + for (i = 0; i < network->rates_ex_len; i++) { + network->rates_ex[i] = info_element->data[i]; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n", + rates_str, network->rates_ex_len); + break; + + case MFIE_TYPE_DS_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n", + info_element->data[0]); + network->channel = info_element->data[0]; + break; + + case MFIE_TYPE_FH_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n"); + break; + + case MFIE_TYPE_CF_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n"); + break; + + case MFIE_TYPE_TIM: + network->tim.tim_count = info_element->data[0]; + network->tim.tim_period = info_element->data[1]; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n"); + break; + + case MFIE_TYPE_ERP_INFO: + network->erp_value = info_element->data[0]; + network->flags |= NETWORK_HAS_ERP_VALUE; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", + network->erp_value); + break; + + case MFIE_TYPE_IBSS_SET: + network->atim_window = info_element->data[0]; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n", + network->atim_window); + break; + + case MFIE_TYPE_CHALLENGE: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n"); + break; + + case MFIE_TYPE_GENERIC: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n", + info_element->len); + if (!ieee80211_parse_qos_info_param_IE(info_element, + network)) + break; + + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x01) { + network->wpa_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->wpa_ie, info_element, + network->wpa_ie_len); + } + break; + + case MFIE_TYPE_RSN: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n", + info_element->len); + network->rsn_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->rsn_ie, info_element, + network->rsn_ie_len); + break; + + case MFIE_TYPE_QOS_PARAMETER: + printk(KERN_ERR + "QoS Error need to parse QOS_PARAMETER IE\n"); + break; + /* 802.11h */ + case MFIE_TYPE_POWER_CONSTRAINT: + network->power_constraint = info_element->data[0]; + network->flags |= NETWORK_HAS_POWER_CONSTRAINT; + break; + + case MFIE_TYPE_CSA: + network->power_constraint = info_element->data[0]; + network->flags |= NETWORK_HAS_CSA; + break; + + case MFIE_TYPE_QUIET: + network->quiet.count = info_element->data[0]; + network->quiet.period = info_element->data[1]; + network->quiet.duration = info_element->data[2]; + network->quiet.offset = info_element->data[3]; + network->flags |= NETWORK_HAS_QUIET; + break; + + case MFIE_TYPE_IBSS_DFS: + if (network->ibss_dfs) + break; + network->ibss_dfs = kmemdup(info_element->data, + info_element->len, + GFP_ATOMIC); + if (!network->ibss_dfs) + return 1; + network->flags |= NETWORK_HAS_IBSS_DFS; + break; + + case MFIE_TYPE_TPC_REPORT: + network->tpc_report.transmit_power = + info_element->data[0]; + network->tpc_report.link_margin = info_element->data[1]; + network->flags |= NETWORK_HAS_TPC_REPORT; + break; + + default: + IEEE80211_DEBUG_MGMT + ("Unsupported info element: %s (%d)\n", + get_info_element_string(info_element->id), + info_element->id); + break; + } + + length -= sizeof(*info_element) + info_element->len; + info_element = + (struct ieee80211_info_element *)&info_element-> + data[info_element->len]; + } + + return 0; +} + +static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response + *frame, struct ieee80211_rx_stats *stats) +{ + struct ieee80211_network network_resp = { + .ibss_dfs = NULL, + }; + struct ieee80211_network *network = &network_resp; + struct net_device *dev = ieee->dev; + + network->flags = 0; + network->qos_data.active = 0; + network->qos_data.supported = 0; + network->qos_data.param_count = 0; + network->qos_data.old_param_count = 0; + + //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF); + network->atim_window = le16_to_cpu(frame->aid); + network->listen_interval = le16_to_cpu(frame->status); + memcpy(network->bssid, frame->header.addr3, ETH_ALEN); + network->capability = le16_to_cpu(frame->capability); + network->last_scanned = jiffies; + network->rates_len = network->rates_ex_len = 0; + network->last_associate = 0; + network->ssid_len = 0; + network->erp_value = + (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; + + if (stats->freq == IEEE80211_52GHZ_BAND) { + /* for A band (No DS info) */ + network->channel = stats->received_channel; + } else + network->flags |= NETWORK_HAS_CCK; + + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; + + if (ieee80211_parse_info_param + (frame->info_element, stats->len - sizeof(*frame), network)) + return 1; + + network->mode = 0; + if (stats->freq == IEEE80211_52GHZ_BAND) + network->mode = IEEE_A; + else { + if (network->flags & NETWORK_HAS_OFDM) + network->mode |= IEEE_G; + if (network->flags & NETWORK_HAS_CCK) + network->mode |= IEEE_B; + } + + memcpy(&network->stats, stats, sizeof(network->stats)); + + if (ieee->handle_assoc_response != NULL) + ieee->handle_assoc_response(dev, frame, network); + + return 0; +} + +/***************************************************/ + +static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response + *beacon, + struct ieee80211_network *network, + struct ieee80211_rx_stats *stats) +{ + DECLARE_SSID_BUF(ssid); + + network->qos_data.active = 0; + network->qos_data.supported = 0; + network->qos_data.param_count = 0; + network->qos_data.old_param_count = 0; + + /* Pull out fixed field data */ + memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); + network->capability = le16_to_cpu(beacon->capability); + network->last_scanned = jiffies; + network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]); + network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]); + network->beacon_interval = le16_to_cpu(beacon->beacon_interval); + /* Where to pull this? beacon->listen_interval; */ + network->listen_interval = 0x0A; + network->rates_len = network->rates_ex_len = 0; + network->last_associate = 0; + network->ssid_len = 0; + network->flags = 0; + network->atim_window = 0; + network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? + 0x3 : 0x0; + + if (stats->freq == IEEE80211_52GHZ_BAND) { + /* for A band (No DS info) */ + network->channel = stats->received_channel; + } else + network->flags |= NETWORK_HAS_CCK; + + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; + + if (ieee80211_parse_info_param + (beacon->info_element, stats->len - sizeof(*beacon), network)) + return 1; + + network->mode = 0; + if (stats->freq == IEEE80211_52GHZ_BAND) + network->mode = IEEE_A; + else { + if (network->flags & NETWORK_HAS_OFDM) + network->mode |= IEEE_G; + if (network->flags & NETWORK_HAS_CCK) + network->mode |= IEEE_B; + } + + if (network->mode == 0) { + IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' " + "network.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); + return 1; + } + + memcpy(&network->stats, stats, sizeof(network->stats)); + + return 0; +} + +static inline int is_same_network(struct ieee80211_network *src, + struct ieee80211_network *dst) +{ + /* A network is only a duplicate if the channel, BSSID, and ESSID + * all match. We treat all with the same BSSID and channel + * as one network */ + return ((src->ssid_len == dst->ssid_len) && + (src->channel == dst->channel) && + !compare_ether_addr(src->bssid, dst->bssid) && + !memcmp(src->ssid, dst->ssid, src->ssid_len)); +} + +static void update_network(struct ieee80211_network *dst, + struct ieee80211_network *src) +{ + int qos_active; + u8 old_param; + + ieee80211_network_reset(dst); + dst->ibss_dfs = src->ibss_dfs; + + /* We only update the statistics if they were created by receiving + * the network information on the actual channel the network is on. + * + * This keeps beacons received on neighbor channels from bringing + * down the signal level of an AP. */ + if (dst->channel == src->stats.received_channel) + memcpy(&dst->stats, &src->stats, + sizeof(struct ieee80211_rx_stats)); + else + IEEE80211_DEBUG_SCAN("Network %pM info received " + "off channel (%d vs. %d)\n", src->bssid, + dst->channel, src->stats.received_channel); + + dst->capability = src->capability; + memcpy(dst->rates, src->rates, src->rates_len); + dst->rates_len = src->rates_len; + memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); + dst->rates_ex_len = src->rates_ex_len; + + dst->mode = src->mode; + dst->flags = src->flags; + dst->time_stamp[0] = src->time_stamp[0]; + dst->time_stamp[1] = src->time_stamp[1]; + + dst->beacon_interval = src->beacon_interval; + dst->listen_interval = src->listen_interval; + dst->atim_window = src->atim_window; + dst->erp_value = src->erp_value; + dst->tim = src->tim; + + memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); + dst->wpa_ie_len = src->wpa_ie_len; + memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); + dst->rsn_ie_len = src->rsn_ie_len; + + dst->last_scanned = jiffies; + qos_active = src->qos_data.active; + old_param = dst->qos_data.old_param_count; + if (dst->flags & NETWORK_HAS_QOS_MASK) + memcpy(&dst->qos_data, &src->qos_data, + sizeof(struct ieee80211_qos_data)); + else { + dst->qos_data.supported = src->qos_data.supported; + dst->qos_data.param_count = src->qos_data.param_count; + } + + if (dst->qos_data.supported == 1) { + if (dst->ssid_len) + IEEE80211_DEBUG_QOS + ("QoS the network %s is QoS supported\n", + dst->ssid); + else + IEEE80211_DEBUG_QOS + ("QoS the network is QoS supported\n"); + } + dst->qos_data.active = qos_active; + dst->qos_data.old_param_count = old_param; + + /* dst->last_associate is not overwritten */ +} + +static inline int is_beacon(__le16 fc) +{ + return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); +} + +static void ieee80211_process_probe_response(struct ieee80211_device + *ieee, struct + ieee80211_probe_response + *beacon, struct ieee80211_rx_stats + *stats) +{ + struct net_device *dev = ieee->dev; + struct ieee80211_network network = { + .ibss_dfs = NULL, + }; + struct ieee80211_network *target; + struct ieee80211_network *oldest = NULL; +#ifdef CONFIG_IEEE80211_DEBUG + struct ieee80211_info_element *info_element = beacon->info_element; +#endif + unsigned long flags; + DECLARE_SSID_BUF(ssid); + + IEEE80211_DEBUG_SCAN("'%s' (%pM" + "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", + print_ssid(ssid, info_element->data, info_element->len), + beacon->header.addr3, + (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0', + (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0'); + + if (ieee80211_network_init(ieee, beacon, &network, stats)) { + IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", + print_ssid(ssid, info_element->data, + info_element->len), + beacon->header.addr3, + is_beacon(beacon->header.frame_ctl) ? + "BEACON" : "PROBE RESPONSE"); + return; + } + + /* The network parsed correctly -- so now we scan our known networks + * to see if we can find it in our list. + * + * NOTE: This search is definitely not optimized. Once its doing + * the "right thing" we'll optimize it for efficiency if + * necessary */ + + /* Search for this entry in the list and update it if it is + * already there. */ + + spin_lock_irqsave(&ieee->lock, flags); + + list_for_each_entry(target, &ieee->network_list, list) { + if (is_same_network(target, &network)) + break; + + if ((oldest == NULL) || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information */ + if (&target->list == &ieee->network_list) { + if (list_empty(&ieee->network_free_list)) { + /* If there are no more slots, expire the oldest */ + list_del(&oldest->list); + target = oldest; + IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from " + "network list.\n", + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); + ieee80211_network_reset(target); + } else { + /* Otherwise just pull from the free list */ + target = list_entry(ieee->network_free_list.next, + struct ieee80211_network, list); + list_del(ieee->network_free_list.next); + } + +#ifdef CONFIG_IEEE80211_DEBUG + IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", + print_ssid(ssid, network.ssid, + network.ssid_len), + network.bssid, + is_beacon(beacon->header.frame_ctl) ? + "BEACON" : "PROBE RESPONSE"); +#endif + memcpy(target, &network, sizeof(*target)); + network.ibss_dfs = NULL; + list_add_tail(&target->list, &ieee->network_list); + } else { + IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid, + is_beacon(beacon->header.frame_ctl) ? + "BEACON" : "PROBE RESPONSE"); + update_network(target, &network); + network.ibss_dfs = NULL; + } + + spin_unlock_irqrestore(&ieee->lock, flags); + + if (is_beacon(beacon->header.frame_ctl)) { + if (ieee->handle_beacon != NULL) + ieee->handle_beacon(dev, beacon, target); + } else { + if (ieee->handle_probe_response != NULL) + ieee->handle_probe_response(dev, beacon, target); + } +} + +void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *header, + struct ieee80211_rx_stats *stats) +{ + switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { + case IEEE80211_STYPE_ASSOC_RESP: + IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + ieee80211_handle_assoc_resp(ieee, + (struct ieee80211_assoc_response *) + header, stats); + break; + + case IEEE80211_STYPE_REASSOC_RESP: + IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + break; + + case IEEE80211_STYPE_PROBE_REQ: + IEEE80211_DEBUG_MGMT("received auth (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + if (ieee->handle_probe_request != NULL) + ieee->handle_probe_request(ieee->dev, + (struct + ieee80211_probe_request *) + header, stats); + break; + + case IEEE80211_STYPE_PROBE_RESP: + IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + IEEE80211_DEBUG_SCAN("Probe response\n"); + ieee80211_process_probe_response(ieee, + (struct + ieee80211_probe_response *) + header, stats); + break; + + case IEEE80211_STYPE_BEACON: + IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + IEEE80211_DEBUG_SCAN("Beacon\n"); + ieee80211_process_probe_response(ieee, + (struct + ieee80211_probe_response *) + header, stats); + break; + case IEEE80211_STYPE_AUTH: + + IEEE80211_DEBUG_MGMT("received auth (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + if (ieee->handle_auth != NULL) + ieee->handle_auth(ieee->dev, + (struct ieee80211_auth *)header); + break; + + case IEEE80211_STYPE_DISASSOC: + if (ieee->handle_disassoc != NULL) + ieee->handle_disassoc(ieee->dev, + (struct ieee80211_disassoc *) + header); + break; + + case IEEE80211_STYPE_ACTION: + IEEE80211_DEBUG_MGMT("ACTION\n"); + if (ieee->handle_action) + ieee->handle_action(ieee->dev, + (struct ieee80211_action *) + header, stats); + break; + + case IEEE80211_STYPE_REASSOC_REQ: + IEEE80211_DEBUG_MGMT("received reassoc (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n", + ieee->dev->name); + if (ieee->handle_reassoc_request != NULL) + ieee->handle_reassoc_request(ieee->dev, + (struct ieee80211_reassoc_request *) + header); + break; + + case IEEE80211_STYPE_ASSOC_REQ: + IEEE80211_DEBUG_MGMT("received assoc (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n", + ieee->dev->name); + if (ieee->handle_assoc_request != NULL) + ieee->handle_assoc_request(ieee->dev); + break; + + case IEEE80211_STYPE_DEAUTH: + IEEE80211_DEBUG_MGMT("DEAUTH\n"); + if (ieee->handle_deauth != NULL) + ieee->handle_deauth(ieee->dev, + (struct ieee80211_deauth *) + header); + break; + default: + IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n", + ieee->dev->name, + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + break; + } +} + +EXPORT_SYMBOL_GPL(ieee80211_rx_any); +EXPORT_SYMBOL(ieee80211_rx_mgt); +EXPORT_SYMBOL(ieee80211_rx); diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c new file mode 100644 index 0000000..f78f57e --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -0,0 +1,546 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + +802.11 Data Frame + + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `--------------------------------------------------| |------' +Total: 28 non-data bytes `----.----' + | + .- 'Frame data' expands, if WEP enabled, to <----------' + | + V + ,-----------------------. +Bytes | 4 | 0-2296 | 4 | + |-----|-----------|-----| +Desc. | IV | Encrypted | ICV | + | | Packet | | + `-----| |-----' + `-----.-----' + | + .- 'Encrypted Packet' expands to + | + V + ,---------------------------------------------------. +Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | + |------|------|---------|----------|------|---------| +Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | + | DSAP | SSAP | | | | Packet | + | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | + `---------------------------------------------------- +Total: 8 non-data bytes + +802.3 Ethernet Data Frame + + ,-----------------------------------------. +Bytes | 6 | 6 | 2 | Variable | 4 | + |-------|-------|------|-----------|------| +Desc. | Dest. | Source| Type | IP Packet | fcs | + | MAC | MAC | | | | + `-----------------------------------------' +Total: 18 non-data bytes + +In the event that fragmentation is required, the incoming payload is split into +N parts of size ieee->fts. The first fragment contains the SNAP header and the +remaining packets are just data. + +If encryption is enabled, each fragment payload size is reduced by enough space +to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) +So if you have 1500 bytes of payload with ieee->fts set to 500 without +encryption it will take 3 frames. With WEP it will take 4 frames as the +payload of each frame is reduced to 492 bytes. + +* SKB visualization +* +* ,- skb->data +* | +* | ETHERNET HEADER ,-<-- PAYLOAD +* | | 14 bytes from skb->data +* | 2 bytes for Type --> ,T. | (sizeof ethhdr) +* | | | | +* |,-Dest.--. ,--Src.---. | | | +* | 6 bytes| | 6 bytes | | | | +* v | | | | | | +* 0 | v 1 | v | v 2 +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +* ^ | ^ | ^ | +* | | | | | | +* | | | | `T' <---- 2 bytes for Type +* | | | | +* | | '---SNAP--' <-------- 6 bytes for SNAP +* | | +* `-IV--' <-------------------- 4 bytes for IV (WEP) +* +* SNAP HEADER +* +*/ + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +static int ieee80211_copy_snap(u8 * data, __be16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + u8 *oui; + + snap = (struct ieee80211_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + + if (h_proto == htons(ETH_P_AARP) || h_proto == htons(ETH_P_IPX)) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + + memcpy(data + SNAP_SIZE, &h_proto, sizeof(u16)); + + return SNAP_SIZE + sizeof(u16); +} + +static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, + struct sk_buff *frag, int hdr_len) +{ + struct lib80211_crypt_data *crypt = + ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + int res; + + if (crypt == NULL) + return -1; + + /* To encrypt, frame format is: + * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ + atomic_inc(&crypt->refcnt); + res = 0; + if (crypt->ops && crypt->ops->encrypt_mpdu) + res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); + + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_INFO "%s: Encryption failed: len=%d.\n", + ieee->dev->name, frag->len); + ieee->ieee_stats.tx_discards++; + return -1; + } + + return 0; +} + +void ieee80211_txb_free(struct ieee80211_txb *txb) +{ + int i; + if (unlikely(!txb)) + return; + for (i = 0; i < txb->nr_frags; i++) + if (txb->fragments[i]) + dev_kfree_skb_any(txb->fragments[i]); + kfree(txb); +} + +static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, + int headroom, gfp_t gfp_mask) +{ + struct ieee80211_txb *txb; + int i; + txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags), + gfp_mask); + if (!txb) + return NULL; + + memset(txb, 0, sizeof(struct ieee80211_txb)); + txb->nr_frags = nr_frags; + txb->frag_size = txb_size; + + for (i = 0; i < nr_frags; i++) { + txb->fragments[i] = __dev_alloc_skb(txb_size + headroom, + gfp_mask); + if (unlikely(!txb->fragments[i])) { + i--; + break; + } + skb_reserve(txb->fragments[i], headroom); + } + if (unlikely(i != nr_frags)) { + while (i >= 0) + dev_kfree_skb_any(txb->fragments[i--]); + kfree(txb); + return NULL; + } + return txb; +} + +static int ieee80211_classify(struct sk_buff *skb) +{ + struct ethhdr *eth; + struct iphdr *ip; + + eth = (struct ethhdr *)skb->data; + if (eth->h_proto != htons(ETH_P_IP)) + return 0; + + ip = ip_hdr(skb); + switch (ip->tos & 0xfc) { + case 0x20: + return 2; + case 0x40: + return 1; + case 0x60: + return 3; + case 0x80: + return 4; + case 0xa0: + return 5; + case 0xc0: + return 6; + case 0xe0: + return 7; + default: + return 0; + } +} + +/* Incoming skb is converted to a txb which consists of + * a block of 802.11 fragment packets (stored as skbs) */ +int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + struct ieee80211_txb *txb = NULL; + struct ieee80211_hdr_3addrqos *frag_hdr; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, + rts_required; + unsigned long flags; + struct net_device_stats *stats = &ieee->stats; + int encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; + __be16 ether_type; + int bytes, fc, hdr_len; + struct sk_buff *skb_frag; + struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */ + .duration_id = 0, + .seq_ctl = 0, + .qos_ctl = 0 + }; + u8 dest[ETH_ALEN], src[ETH_ALEN]; + struct lib80211_crypt_data *crypt; + int priority = skb->priority; + int snapped = 0; + + if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority)) + return NETDEV_TX_BUSY; + + spin_lock_irqsave(&ieee->lock, flags); + + /* If there is no driver handler to take the TXB, dont' bother + * creating it... */ + if (!ieee->hard_start_xmit) { + printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); + goto success; + } + + if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { + printk(KERN_WARNING "%s: skb too small (%d).\n", + ieee->dev->name, skb->len); + goto success; + } + + ether_type = ((struct ethhdr *)skb->data)->h_proto; + + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + + encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) && + ieee->sec.encrypt; + + host_encrypt = ieee->host_encrypt && encrypt && crypt; + host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt; + host_build_iv = ieee->host_build_iv && encrypt && crypt; + + if (!encrypt && ieee->ieee802_1x && + ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) { + stats->tx_dropped++; + goto success; + } + + /* Save source and destination addresses */ + skb_copy_from_linear_data(skb, dest, ETH_ALEN); + skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN); + + if (host_encrypt || host_build_iv) + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | + IEEE80211_FCTL_PROTECTED; + else + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + + if (ieee->iw_mode == IW_MODE_INFRA) { + fc |= IEEE80211_FCTL_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ + memcpy(header.addr1, ieee->bssid, ETH_ALEN); + memcpy(header.addr2, src, ETH_ALEN); + memcpy(header.addr3, dest, ETH_ALEN); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ + memcpy(header.addr1, dest, ETH_ALEN); + memcpy(header.addr2, src, ETH_ALEN); + memcpy(header.addr3, ieee->bssid, ETH_ALEN); + } + hdr_len = IEEE80211_3ADDR_LEN; + + if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) { + fc |= IEEE80211_STYPE_QOS_DATA; + hdr_len += 2; + + skb->priority = ieee80211_classify(skb); + header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID); + } + header.frame_ctl = cpu_to_le16(fc); + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + + /* Encrypt msdu first on the whole data packet. */ + if ((host_encrypt || host_encrypt_msdu) && + crypt && crypt->ops && crypt->ops->encrypt_msdu) { + int res = 0; + int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; + struct sk_buff *skb_new = dev_alloc_skb(len); + + if (unlikely(!skb_new)) + goto failed; + + skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); + memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); + snapped = 1; + ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), + ether_type); + skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len); + res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv); + if (res < 0) { + IEEE80211_ERROR("msdu encryption failed\n"); + dev_kfree_skb_any(skb_new); + goto failed; + } + dev_kfree_skb_any(skb); + skb = skb_new; + bytes += crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; + skb_pull(skb, hdr_len); + } + + if (host_encrypt || ieee->host_open_frag) { + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) */ + if (is_multicast_ether_addr(dest) || + is_broadcast_ether_addr(dest)) + frag_size = MAX_FRAG_THRESHOLD; + else + frag_size = ieee->fts; + + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account + * for it when determining the amount of payload space. */ + bytes_per_frag = frag_size - hdr_len; + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + bytes_per_frag -= IEEE80211_FCS_LEN; + + /* Each fragment may need to have room for encryptiong + * pre/postfix */ + if (host_encrypt) + bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_mpdu_postfix_len; + + /* Number of fragments is the total + * bytes_per_frag / payload_per_fragment */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + } else { + nr_frags = 1; + bytes_per_frag = bytes_last_frag = bytes; + frag_size = bytes + hdr_len; + } + + rts_required = (frag_size > ieee->rts + && ieee->config & CFG_IEEE80211_RTS); + if (rts_required) + nr_frags++; + + /* When we allocate the TXB we allocate enough space for the reserve + * and full fragment bytes (bytes_per_frag doesn't include prefix, + * postfix, header, FCS, etc.) */ + txb = ieee80211_alloc_txb(nr_frags, frag_size, + ieee->tx_headroom, GFP_ATOMIC); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + goto failed; + } + txb->encrypted = encrypt; + if (host_encrypt) + txb->payload_size = frag_size * (nr_frags - 1) + + bytes_last_frag; + else + txb->payload_size = bytes; + + if (rts_required) { + skb_frag = txb->fragments[0]; + frag_hdr = + (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + + /* + * Set header frame_ctl to the RTS. + */ + header.frame_ctl = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); + memcpy(frag_hdr, &header, hdr_len); + + /* + * Restore header frame_ctl to the original data setting. + */ + header.frame_ctl = cpu_to_le16(fc); + + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + + txb->rts_included = 1; + i = 1; + } else + i = 0; + + for (; i < nr_frags; i++) { + skb_frag = txb->fragments[i]; + + if (host_encrypt || host_build_iv) + skb_reserve(skb_frag, + crypt->ops->extra_mpdu_prefix_len); + + frag_hdr = + (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + memcpy(frag_hdr, &header, hdr_len); + + /* If this is not the last fragment, then add the MOREFRAGS + * bit to the frame control */ + if (i != nr_frags - 1) { + frag_hdr->frame_ctl = + cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS); + bytes = bytes_per_frag; + } else { + /* The last fragment takes the remaining length */ + bytes = bytes_last_frag; + } + + if (i == 0 && !snapped) { + ieee80211_copy_snap(skb_put + (skb_frag, SNAP_SIZE + sizeof(u16)), + ether_type); + bytes -= SNAP_SIZE + sizeof(u16); + } + + skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes); + + /* Advance the SKB... */ + skb_pull(skb, bytes); + + /* Encryption routine will move the header forward in order + * to insert the IV between the header and the payload */ + if (host_encrypt) + ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + else if (host_build_iv) { + atomic_inc(&crypt->refcnt); + if (crypt->ops->build_iv) + crypt->ops->build_iv(skb_frag, hdr_len, + ieee->sec.keys[ieee->sec.active_key], + ieee->sec.key_sizes[ieee->sec.active_key], + crypt->priv); + atomic_dec(&crypt->refcnt); + } + + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + } + + success: + spin_unlock_irqrestore(&ieee->lock, flags); + + dev_kfree_skb_any(skb); + + if (txb) { + int ret = (*ieee->hard_start_xmit) (txb, dev, priority); + if (ret == 0) { + stats->tx_packets++; + stats->tx_bytes += txb->payload_size; + return 0; + } + + ieee80211_txb_free(txb); + } + + return 0; + + failed: + spin_unlock_irqrestore(&ieee->lock, flags); + netif_stop_queue(dev); + stats->tx_errors++; + return 1; +} + +EXPORT_SYMBOL(ieee80211_txb_free); diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c new file mode 100644 index 0000000..31ea3ab --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -0,0 +1,760 @@ +/****************************************************************************** + + Copyright(c) 2004-2005 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +static const char *ieee80211_modes[] = { + "?", "a", "b", "ab", "g", "ag", "bg", "abg" +}; + +#define MAX_CUSTOM_LEN 64 +static char *ieee80211_translate_scan(struct ieee80211_device *ieee, + char *start, char *stop, + struct ieee80211_network *network, + struct iw_request_info *info) +{ + char custom[MAX_CUSTOM_LEN]; + char *p; + struct iw_event iwe; + int i, j; + char *current_val; /* For rates */ + u8 rate; + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); + + /* Remaining entries will be displayed in the order we provide them */ + + /* Add the ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = min(network->ssid_len, (u8) 32); + start = iwe_stream_add_point(info, start, stop, + &iwe, network->ssid); + + /* Add the protocol name */ + iwe.cmd = SIOCGIWNAME; + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", + ieee80211_modes[network->mode]); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (network->capability & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + + start = iwe_stream_add_event(info, start, stop, + &iwe, IW_EV_UINT_LEN); + } + + /* Add channel and frequency */ + /* Note : userspace automatically computes channel using iwrange */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); + iwe.u.freq.e = 6; + iwe.u.freq.i = 0; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (network->capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + start = iwe_stream_add_point(info, start, stop, + &iwe, network->ssid); + + /* Add basic and extended rates */ + /* Rate : stuffing multiple values in a single event require a bit + * more of magic - Jean II */ + current_val = start + iwe_stream_lcp_len(info); + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + for (i = 0, j = 0; i < network->rates_len;) { + if (j < network->rates_ex_len && + ((network->rates_ex[j] & 0x7F) < + (network->rates[i] & 0x7F))) + rate = network->rates_ex[j++] & 0x7F; + else + rate = network->rates[i++] & 0x7F; + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = ((rate & 0x7f) * 500000); + /* Add new value to event */ + current_val = iwe_stream_add_value(info, start, current_val, + stop, &iwe, IW_EV_PARAM_LEN); + } + for (; j < network->rates_ex_len; j++) { + rate = network->rates_ex[j] & 0x7F; + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = ((rate & 0x7f) * 500000); + /* Add new value to event */ + current_val = iwe_stream_add_value(info, start, current_val, + stop, &iwe, IW_EV_PARAM_LEN); + } + /* Check if we added any rate */ + if ((current_val - start) > iwe_stream_lcp_len(info)) + start = current_val; + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_UPDATED; + + if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { + iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | + IW_QUAL_LEVEL_INVALID; + iwe.u.qual.qual = 0; + } else { + if (ieee->perfect_rssi == ieee->worst_rssi) + iwe.u.qual.qual = 100; + else + iwe.u.qual.qual = + (100 * + (ieee->perfect_rssi - ieee->worst_rssi) * + (ieee->perfect_rssi - ieee->worst_rssi) - + (ieee->perfect_rssi - network->stats.rssi) * + (15 * (ieee->perfect_rssi - ieee->worst_rssi) + + 62 * (ieee->perfect_rssi - + network->stats.rssi))) / + ((ieee->perfect_rssi - + ieee->worst_rssi) * (ieee->perfect_rssi - + ieee->worst_rssi)); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + else if (iwe.u.qual.qual < 1) + iwe.u.qual.qual = 0; + } + + if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { + iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; + iwe.u.qual.noise = 0; + } else { + iwe.u.qual.noise = network->stats.noise; + } + + if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) { + iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; + iwe.u.qual.level = 0; + } else { + iwe.u.qual.level = network->stats.signal; + } + + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); + + iwe.cmd = IWEVCUSTOM; + p = custom; + + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); + + memset(&iwe, 0, sizeof(iwe)); + if (network->wpa_ie_len) { + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->wpa_ie, network->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->wpa_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + + memset(&iwe, 0, sizeof(iwe)); + if (network->rsn_ie_len) { + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->rsn_ie, network->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->rsn_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - network->last_scanned)); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); + + /* Add spectrum management information */ + iwe.cmd = -1; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: "); + + if (ieee80211_get_channel_flags(ieee, network->channel) & + IEEE80211_CH_INVALID) { + iwe.cmd = IWEVCUSTOM; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID "); + } + + if (ieee80211_get_channel_flags(ieee, network->channel) & + IEEE80211_CH_RADAR_DETECT) { + iwe.cmd = IWEVCUSTOM; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS "); + } + + if (iwe.cmd == IWEVCUSTOM) { + iwe.u.data.length = p - custom; + start = iwe_stream_add_point(info, start, stop, &iwe, custom); + } + + return start; +} + +#define SCAN_ITEM_SIZE 128 + +int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ieee80211_network *network; + unsigned long flags; + int err = 0; + + char *ev = extra; + char *stop = ev + wrqu->data.length; + int i = 0; + DECLARE_SSID_BUF(ssid); + + IEEE80211_DEBUG_WX("Getting scan\n"); + + spin_lock_irqsave(&ieee->lock, flags); + + list_for_each_entry(network, &ieee->network_list, list) { + i++; + if (stop - ev < SCAN_ITEM_SIZE) { + err = -E2BIG; + break; + } + + if (ieee->scan_age == 0 || + time_after(network->last_scanned + ieee->scan_age, jiffies)) + ev = ieee80211_translate_scan(ieee, ev, stop, network, + info); + else + IEEE80211_DEBUG_SCAN("Not showing network '%s (" + "%pM)' due to age (%dms).\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + jiffies_to_msecs(jiffies - + network-> + last_scanned)); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + + wrqu->data.length = ev - extra; + wrqu->data.flags = 0; + + IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); + + return err; +} + +int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + struct net_device *dev = ieee->dev; + struct ieee80211_security sec = { + .flags = 0 + }; + int i, key, key_provided, len; + struct lib80211_crypt_data **crypt; + int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; + DECLARE_SSID_BUF(ssid); + + IEEE80211_DEBUG_WX("SET_ENCODE\n"); + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + key_provided = 1; + } else { + key_provided = 0; + key = ieee->crypt_info.tx_keyidx; + } + + IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? + "provided" : "default"); + + crypt = &ieee->crypt_info.crypt[key]; + + if (erq->flags & IW_ENCODE_DISABLED) { + if (key_provided && *crypt) { + IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", + key); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + } else + IEEE80211_DEBUG_WX("Disabling encryption.\n"); + + /* Check all the keys to see if any are still configured, + * and if no key index was provided, de-init them all */ + for (i = 0; i < WEP_KEYS; i++) { + if (ieee->crypt_info.crypt[i] != NULL) { + if (key_provided) + break; + lib80211_crypt_delayed_deinit(&ieee->crypt_info, + &ieee->crypt_info.crypt[i]); + } + } + + if (i == WEP_KEYS) { + sec.enabled = 0; + sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT; + } + + goto done; + } + + sec.enabled = 1; + sec.encrypt = 1; + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; + + if (*crypt != NULL && (*crypt)->ops != NULL && + strcmp((*crypt)->ops->name, "WEP") != 0) { + /* changing to use WEP; deinit previously used algorithm + * on this key */ + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + } + + if (*crypt == NULL && host_crypto) { + struct lib80211_crypt_data *new_crypt; + + /* take WEP into use */ + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), + GFP_KERNEL); + if (new_crypt == NULL) + return -ENOMEM; + new_crypt->ops = lib80211_get_crypto_ops("WEP"); + if (!new_crypt->ops) { + request_module("lib80211_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); + } + + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(key); + + if (!new_crypt->ops || !new_crypt->priv) { + kfree(new_crypt); + new_crypt = NULL; + + printk(KERN_WARNING "%s: could not initialize WEP: " + "load module lib80211_crypt_wep\n", dev->name); + return -EOPNOTSUPP; + } + *crypt = new_crypt; + } + + /* If a new key was provided, set it up */ + if (erq->length > 0) { +#ifdef CONFIG_IEEE80211_DEBUG + DECLARE_SSID_BUF(ssid); +#endif + + len = erq->length <= 5 ? 5 : 13; + memcpy(sec.keys[key], keybuf, erq->length); + if (len > erq->length) + memset(sec.keys[key] + erq->length, 0, + len - erq->length); + IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", + key, print_ssid(ssid, sec.keys[key], len), + erq->length, len); + sec.key_sizes[key] = len; + if (*crypt) + (*crypt)->ops->set_key(sec.keys[key], len, NULL, + (*crypt)->priv); + sec.flags |= (1 << key); + /* This ensures a key will be activated if no key is + * explicitly set */ + if (key == sec.active_key) + sec.flags |= SEC_ACTIVE_KEY; + + } else { + if (host_crypto) { + len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, + NULL, (*crypt)->priv); + if (len == 0) { + /* Set a default key of all 0 */ + IEEE80211_DEBUG_WX("Setting key %d to all " + "zero.\n", key); + memset(sec.keys[key], 0, 13); + (*crypt)->ops->set_key(sec.keys[key], 13, NULL, + (*crypt)->priv); + sec.key_sizes[key] = 13; + sec.flags |= (1 << key); + } + } + /* No key data - just set the default TX key index */ + if (key_provided) { + IEEE80211_DEBUG_WX("Setting key %d to default Tx " + "key.\n", key); + ieee->crypt_info.tx_keyidx = key; + sec.active_key = key; + sec.flags |= SEC_ACTIVE_KEY; + } + } + if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) { + ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); + sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : + WLAN_AUTH_SHARED_KEY; + sec.flags |= SEC_AUTH_MODE; + IEEE80211_DEBUG_WX("Auth: %s\n", + sec.auth_mode == WLAN_AUTH_OPEN ? + "OPEN" : "SHARED KEY"); + } + + /* For now we just support WEP, so only set that security level... + * TODO: When WPA is added this is one place that needs to change */ + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ + sec.encode_alg[key] = SEC_ALG_WEP; + + done: + if (ieee->set_security) + ieee->set_security(dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); + return -EINVAL; + } + return 0; +} + +int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + int len, key; + struct lib80211_crypt_data *crypt; + struct ieee80211_security *sec = &ieee->sec; + + IEEE80211_DEBUG_WX("GET_ENCODE\n"); + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + } else + key = ieee->crypt_info.tx_keyidx; + + crypt = ieee->crypt_info.crypt[key]; + erq->flags = key + 1; + + if (!sec->enabled) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + + len = sec->key_sizes[key]; + memcpy(keybuf, sec->keys[key], len); + + erq->length = len; + erq->flags |= IW_ENCODE_ENABLED; + + if (ieee->open_wep) + erq->flags |= IW_ENCODE_OPEN; + else + erq->flags |= IW_ENCODE_RESTRICTED; + + return 0; +} + +int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct net_device *dev = ieee->dev; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int i, idx, ret = 0; + int group_key = 0; + const char *alg, *module; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->crypt_info.tx_keyidx; + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + crypt = &ieee->crypt_info.crypt[idx]; + group_key = 1; + } else { + /* some Cisco APs use idx>0 for unicast in dynamic WEP */ + if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) + return -EINVAL; + if (ieee->iw_mode == IW_MODE_INFRA) + crypt = &ieee->crypt_info.crypt[idx]; + else + return -EINVAL; + } + + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) { + if (*crypt) + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + + for (i = 0; i < WEP_KEYS; i++) + if (ieee->crypt_info.crypt[i] != NULL) + break; + + if (i == WEP_KEYS) { + sec.enabled = 0; + sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_LEVEL; + } + goto done; + } + + sec.enabled = 1; + sec.encrypt = 1; + + if (group_key ? !ieee->host_mc_decrypt : + !(ieee->host_encrypt || ieee->host_decrypt || + ieee->host_encrypt_msdu)) + goto skip_host_crypt; + + switch (ext->alg) { + case IW_ENCODE_ALG_WEP: + alg = "WEP"; + module = "lib80211_crypt_wep"; + break; + case IW_ENCODE_ALG_TKIP: + alg = "TKIP"; + module = "lib80211_crypt_tkip"; + break; + case IW_ENCODE_ALG_CCMP: + alg = "CCMP"; + module = "lib80211_crypt_ccmp"; + break; + default: + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } + + ops = lib80211_get_crypto_ops(alg); + if (ops == NULL) { + request_module(module); + ops = lib80211_get_crypto_ops(alg); + } + if (ops == NULL) { + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct lib80211_crypt_data *new_crypt; + + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + + new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + new_crypt->ops = ops; + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(idx); + if (new_crypt->priv == NULL) { + kfree(new_crypt); + ret = -EINVAL; + goto done; + } + *crypt = new_crypt; + } + + if (ext->key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, + (*crypt)->priv) < 0) { + IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); + ret = -EINVAL; + goto done; + } + + skip_host_crypt: + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + ieee->crypt_info.tx_keyidx = idx; + sec.active_key = idx; + sec.flags |= SEC_ACTIVE_KEY; + } + + if (ext->alg != IW_ENCODE_ALG_NONE) { + memcpy(sec.keys[idx], ext->key, ext->key_len); + sec.key_sizes[idx] = ext->key_len; + sec.flags |= (1 << idx); + if (ext->alg == IW_ENCODE_ALG_WEP) { + sec.encode_alg[idx] = SEC_ALG_WEP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (ext->alg == IW_ENCODE_ALG_TKIP) { + sec.encode_alg[idx] = SEC_ALG_TKIP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (ext->alg == IW_ENCODE_ALG_CCMP) { + sec.encode_alg[idx] = SEC_ALG_CCMP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + /* Don't set sec level for group keys. */ + if (group_key) + sec.flags &= ~SEC_LEVEL; + } + done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + /* + * Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. + */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); + return -EINVAL; + } + + return ret; +} + +int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct ieee80211_security *sec = &ieee->sec; + int idx, max_key_len; + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->crypt_info.tx_keyidx; + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && + ext->alg != IW_ENCODE_ALG_WEP) + if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) + return -EINVAL; + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + if (!sec->enabled) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + } else { + if (sec->encode_alg[idx] == SEC_ALG_WEP) + ext->alg = IW_ENCODE_ALG_WEP; + else if (sec->encode_alg[idx] == SEC_ALG_TKIP) + ext->alg = IW_ENCODE_ALG_TKIP; + else if (sec->encode_alg[idx] == SEC_ALG_CCMP) + ext->alg = IW_ENCODE_ALG_CCMP; + else + return -EINVAL; + + ext->key_len = sec->key_sizes[idx]; + memcpy(ext->key, sec->keys[idx], ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + if (ext->key_len && + (ext->alg == IW_ENCODE_ALG_TKIP || + ext->alg == IW_ENCODE_ALG_CCMP)) + ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; + + } + + return 0; +} + +EXPORT_SYMBOL(ieee80211_wx_set_encodeext); +EXPORT_SYMBOL(ieee80211_wx_get_encodeext); + +EXPORT_SYMBOL(ieee80211_wx_get_scan); +EXPORT_SYMBOL(ieee80211_wx_set_encode); +EXPORT_SYMBOL(ieee80211_wx_get_encode); -- cgit v1.1 From da81dede95cf69b0e51442cb472f1581583381e4 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 12 Nov 2008 14:37:11 -0500 Subject: rtl8180: adapt for deprecated IEEE80211_CONF_SHORT_SLOT_TIME flag This updates rtl8180 handling for short slot after "mac80211: fix short slot handling". Only rtl8180_rtl8225 actually had code for handling short slot times, so the other RF devices are untouched by this change. Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180_dev.c | 12 ++++++++++++ drivers/net/wireless/rtl818x/rtl8180_rtl8225.c | 14 +++++++++++--- drivers/net/wireless/rtl818x/rtl818x.h | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 6c226c0..5f887fb 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -720,6 +720,17 @@ static int rtl8180_config_interface(struct ieee80211_hw *dev, return 0; } +static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8180_priv *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) + priv->rf->conf_erp(dev, info); +} + static void rtl8180_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -760,6 +771,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .config_interface = rtl8180_config_interface, + .bss_info_changed = rtl8180_bss_info_changed, .configure_filter = rtl8180_configure_filter, }; diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c index cd22781..4d2be0d 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c @@ -725,8 +725,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); +} + +static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev, + struct ieee80211_bss_conf *info) +{ + struct rtl8180_priv *priv = dev->priv; - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + if (info->use_short_slot) { rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); @@ -745,14 +751,16 @@ static const struct rtl818x_rf_ops rtl8225_ops = { .name = "rtl8225", .init = rtl8225_rf_init, .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel + .set_chan = rtl8225_rf_set_channel, + .conf_erp = rtl8225_rf_conf_erp, }; static const struct rtl818x_rf_ops rtl8225z2_ops = { .name = "rtl8225z2", .init = rtl8225z2_rf_init, .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel + .set_chan = rtl8225_rf_set_channel, + .conf_erp = rtl8225_rf_conf_erp, }; const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 3538b15..34a5555 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -191,6 +191,7 @@ struct rtl818x_rf_ops { void (*init)(struct ieee80211_hw *); void (*stop)(struct ieee80211_hw *); void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); + void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); }; /* Tx/Rx flags are common between RTL818X chips */ -- cgit v1.1 From 3461fc12a423c09169c6bb350319808ca4ec4b86 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 12 Nov 2008 17:31:52 -0600 Subject: rtl8187: Update file authorship in comments Modify the file comments to reflect the current maintainers. Signed-off-by: Larry Finger Acked-by: Herton Ronaldo Krzesinski Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index e1399d0..4a9f76f 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -7,6 +7,11 @@ * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello , et al. * + * The driver was extended to the RTL8187B in 2008 by: + * Herton Ronaldo Krzesinski + * Hin-Tak Leung + * Larry Finger + * * Magic delays and register offsets below are taken from the original * r8187 driver sources. Thanks to Realtek for their support! * @@ -27,6 +32,9 @@ MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); +MODULE_AUTHOR("Herton Ronaldo Krzesinski "); +MODULE_AUTHOR("Hin-Tak Leung "); +MODULE_AUTHOR("Larry Finger "); MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); -- cgit v1.1 From 9764f3f9c3700620f9f8a1f9af57f58758e835da Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2008 18:56:59 +0100 Subject: ath5k: name pci driver "ath5k" too Call the ath5k pci driver struct "ath5k" too to be less confusing in sysfs. Signed-off-by: Johannes Berg Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 34cd1a4..7fdb59c 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -200,7 +200,7 @@ static int ath5k_pci_resume(struct pci_dev *pdev); #endif /* CONFIG_PM */ static struct pci_driver ath5k_pci_driver = { - .name = "ath5k_pci", + .name = KBUILD_MODNAME, .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, .remove = __devexit_p(ath5k_pci_remove), -- cgit v1.1 From c9c3b1a5deac4297503145840fffcd122b253db5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 10 Nov 2008 19:41:40 +0100 Subject: rt2x00: Cleanup indirect register access All code which accessed indirect registers was similar in respect to the for-loop, the given timeout, etc. Move it into a seperate function, which for PCI drivers can be moved into rt2x00pci. This allows us to cleanup the cleanup the code further by removing the goto statementsand making the codepath look a bit nicer. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 125 +++++++++---------------- drivers/net/wireless/rt2x00/rt2500pci.c | 125 +++++++++---------------- drivers/net/wireless/rt2x00/rt2500usb.c | 140 ++++++++++++--------------- drivers/net/wireless/rt2x00/rt2x00pci.c | 25 +++++ drivers/net/wireless/rt2x00/rt2x00pci.h | 18 ++++ drivers/net/wireless/rt2x00/rt61pci.c | 161 ++++++++++++-------------------- drivers/net/wireless/rt2x00/rt73usb.c | 147 +++++++++++++---------------- 7 files changed, 310 insertions(+), 431 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 78fca1bc..6a97767 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -49,20 +49,10 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); - if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) @@ -72,31 +62,20 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); - - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - - mutex_unlock(&rt2x00dev->csr_mutex); - - return; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + } -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); } static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -107,75 +86,55 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); - /* - * Write the request into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) - goto exit_fail; + WAIT_FOR_BBP(rt2x00dev, ®); + } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; mutex_lock(&rt2x00dev->csr_mutex); - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, RFCSR, ®); - if (!rt2x00_get_field32(reg, RFCSR_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); } mutex_unlock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, RFCSR_VALUE, value); - rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); - rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); - rt2x00_set_field32(®, RFCSR_BUSY, 1); - - rt2x00pci_register_write(rt2x00dev, RFCSR, reg); - rt2x00_rf_write(rt2x00dev, word, value); - - mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 972b5a5..d3bc218 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -49,20 +49,10 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); - if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) @@ -72,31 +62,20 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); - - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - - mutex_unlock(&rt2x00dev->csr_mutex); - - return; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + } -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); } static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -107,75 +86,55 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); - /* - * Write the request into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) - goto exit_fail; + WAIT_FOR_BBP(rt2x00dev, ®); + } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; mutex_lock(&rt2x00dev->csr_mutex); - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, RFCSR, ®); - if (!rt2x00_get_field32(reg, RFCSR_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); } mutex_unlock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, RFCSR_VALUE, value); - rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); - rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); - rt2x00_set_field32(®, RFCSR_BUSY, 1); - - rt2x00pci_register_write(rt2x00dev, RFCSR, reg); - rt2x00_rf_write(rt2x00dev, word, value); - - mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index e6bae4a..40eb643 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -57,7 +57,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, __le16 reg; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le16_to_cpu(reg); } @@ -68,7 +68,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, __le16 reg; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le16_to_cpu(reg); } @@ -89,7 +89,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, __le16 reg = cpu_to_le16(value); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, @@ -99,7 +99,7 @@ static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, __le16 reg = cpu_to_le16(value); rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, @@ -112,21 +112,32 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT16(length)); } -static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev) +static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field16 field, + u16 *reg) { - u16 reg; unsigned int i; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, ®); - if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - break; + rt2500usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field16(*reg, field)) + return 1; udelay(REGISTER_BUSY_DELAY); } - return reg; + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; } +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg)) + static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { @@ -135,30 +146,19 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. - */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field16(®, PHY_CSR7_DATA, value); - rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); - rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); - - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - - mutex_unlock(&rt2x00dev->csr_mutex); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_DATA, value); + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); - return; + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + } -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); } static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -169,77 +169,57 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. - */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); - rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) + rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); + } - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); mutex_unlock(&rt2x00dev->csr_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); - *value = 0xff; } static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u16 reg; - unsigned int i; if (!word) return; mutex_lock(&rt2x00dev->csr_mutex); - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®); - if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - mutex_unlock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); - reg = 0; - rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); - rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); - rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); - rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); + reg = 0; + rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); + rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); + rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); + rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); - rt2x00_rf_write(rt2x00dev, word, value); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } mutex_unlock(&rt2x00dev->csr_mutex); } diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index e33bd0f..d52b22b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -32,6 +32,31 @@ #include "rt2x00pci.h" /* + * Register access. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg) +{ + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); + +/* * TX data handlers. */ int rt2x00pci_write_tx_data(struct queue_entry *entry) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 96a2082..9c0a4d7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -77,6 +77,24 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, } /** + * rt2x00pci_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg); + +/** * rt2x00pci_write_tx_data - Initialize data for TX operation * @entry: The entry where the frame is located * diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 89ac34f..d54443c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -55,20 +55,13 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PHY_CSR3, ®); - if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) @@ -78,30 +71,20 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_VALUE, value); - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); - mutex_unlock(&rt2x00dev->csr_mutex); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - return; + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + } -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); } static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -112,72 +95,53 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - /* - * Write the request into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + WAIT_FOR_BBP(rt2x00dev, ®); + } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); - mutex_unlock(&rt2x00dev->csr_mutex); - - return; -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; mutex_lock(&rt2x00dev->csr_mutex); - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); - if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - mutex_unlock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); - rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); - rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); - rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); - rt2x00_rf_write(rt2x00dev, word, value); + rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } mutex_unlock(&rt2x00dev->csr_mutex); } @@ -196,32 +160,25 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); - rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); - - if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) - goto exit_fail; - - rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); - - rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); - rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); - rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); - - mutex_unlock(&rt2x00dev->csr_mutex); + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); - return; + rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); + } -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, - "mcu request error. Request 0x%02x failed for token 0x%02x.\n", - command, token); } #endif /* CONFIG_RT2X00_LIB_LEDS */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d1a63e00..b4ca848 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -63,7 +63,7 @@ static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, __le32 reg; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le32_to_cpu(reg); } @@ -73,7 +73,7 @@ static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev, __le32 reg; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le32_to_cpu(reg); } @@ -93,7 +93,7 @@ static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, __le32 reg = cpu_to_le32(value); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev, @@ -102,7 +102,7 @@ static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev, __le32 reg = cpu_to_le32(value); rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, @@ -115,21 +115,32 @@ static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT32(length)); } -static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) +static int rt73usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg) { - u32 reg; unsigned int i; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, ®); - if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - break; + rt73usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; udelay(REGISTER_BUSY_DELAY); } - return reg; + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; } +#define WAIT_FOR_BBP(__dev, __reg) \ + rt73usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt73usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) + static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { @@ -138,30 +149,20 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_VALUE, value); - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - mutex_unlock(&rt2x00dev->csr_mutex); - - return; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + } -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); } static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -172,79 +173,59 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - /* - * Write the request into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + WAIT_FOR_BBP(rt2x00dev, ®); + } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); - mutex_unlock(&rt2x00dev->csr_mutex); - - return; -exit_fail: mutex_unlock(&rt2x00dev->csr_mutex); - - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; } static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; mutex_lock(&rt2x00dev->csr_mutex); - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, ®); - if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - mutex_unlock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); - /* - * RF5225 and RF2527 contain 21 bits per RF register value, - * all others contain 20 bits. + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. */ - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, - 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527))); - rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); - rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); - - rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); - rt2x00_rf_write(rt2x00dev, word, value); + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + /* + * RF5225 and RF2527 contain 21 bits per RF register value, + * all others contain 20 bits. + */ + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, + 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } mutex_unlock(&rt2x00dev->csr_mutex); } -- cgit v1.1 From 0f829b1d6f499447052f98098e41fd6a091eadd0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 10 Nov 2008 19:42:18 +0100 Subject: rt2x00: Move rt73usb register access wrappers into rt2x00usb rt2500usb and rt73usb have different register word sizes, for that reason the register access wrappers were never moved into rt2x00usb. With rt2800usb on its way, we should favor the 32bit register access and move those wrappers into rt2x00usb. That saves duplicate code, since only rt2500usb will need the special 16bit wrappers. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 22 +++ drivers/net/wireless/rt2x00/rt2x00usb.h | 136 ++++++++++++++ drivers/net/wireless/rt2x00/rt73usb.c | 323 ++++++++++++-------------------- 3 files changed, 280 insertions(+), 201 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index c507b0d..2fbf78f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -154,6 +154,28 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); +int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg) +{ + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + /* * TX data handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 4104f0e..2bd4ac8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT16(length)); } +/** + * rt2x00usb_regbusy_read - Read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +/** + * rt2x00usb_register_read_lock - Read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_req_buff_lock(). + */ +static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +/** + * rt2x00usb_register_multiread - Read 32bit register words + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * @length: Length of the data + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, + REGISTER_TIMEOUT32(length)); +} + +/** + * rt2x00usb_register_write - Write 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); +} + +/** + * rt2x00usb_register_write_lock - Write 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_req_buff_lock(). + */ +static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); +} + +/** + * rt2x00usb_register_multiwrite - Write 32bit register words + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * @length: Length of the data + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, + REGISTER_TIMEOUT32(length)); +} + +/** + * rt2x00usb_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg); + /* * Radio handlers */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b4ca848..ee59b4e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* * Register access. * All access to the CSR registers will go through the methods - * rt73usb_register_read and rt73usb_register_write. + * rt2x00usb_register_read and rt2x00usb_register_write. * BBP and RF register require indirect register access, * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, @@ -57,89 +57,10 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * and we will print an error. * The _lock versions must be used if you already hold the csr_mutex */ -static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value) -{ - __le32 reg; - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(reg), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value) -{ - __le32 reg; - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(reg), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - value, length, - REGISTER_TIMEOUT32(length)); -} - -static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value) -{ - __le32 reg = cpu_to_le32(value); - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(reg), REGISTER_TIMEOUT); -} - -static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value) -{ - __le32 reg = cpu_to_le32(value); - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(reg), REGISTER_TIMEOUT); -} - -static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - value, length, - REGISTER_TIMEOUT32(length)); -} - -static int rt73usb_regbusy_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - struct rt2x00_field32 field, - u32 *reg) -{ - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, offset, reg); - if (!rt2x00_get_field32(*reg, field)) - return 1; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "Indirect register access failed: " - "offset=0x%.08x, value=0x%.08x\n", offset, *reg); - *reg = ~0; - - return 0; -} - #define WAIT_FOR_BBP(__dev, __reg) \ - rt73usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) + rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) #define WAIT_FOR_RF(__dev, __reg) \ - rt73usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) + rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) @@ -159,7 +80,7 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -186,7 +107,7 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); WAIT_FOR_BBP(rt2x00dev, ®); } @@ -223,7 +144,7 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); rt2x00_rf_write(rt2x00dev, word, value); } @@ -234,8 +155,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt73usb_register_read, - .write = rt73usb_register_write, + .read = rt2x00usb_register_read, + .write = rt2x00usb_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, .word_size = sizeof(u32), @@ -314,10 +235,10 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt73usb_register_read(led->rt2x00dev, MAC_CSR14, ®); + rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, ®); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); - rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg); + rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg); return 0; } @@ -360,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); reg &= mask; if (reg && reg == mask) @@ -397,16 +318,16 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt73usb_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR1, ®); rt2x00_set_field32(®, field, crypto->cipher); - rt73usb_register_write(rt2x00dev, SEC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt73usb_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR5, ®); rt2x00_set_field32(®, field, crypto->cipher); - rt73usb_register_write(rt2x00dev, SEC_CSR5, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg); } /* @@ -429,12 +350,12 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg); return 0; } @@ -459,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key, * otherwise we use the first invalid entry. */ - rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); if (reg && reg == ~0) return -ENOSPC; } @@ -490,14 +411,14 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, /* * Send the address and cipher type to the hardware register. * This data fits within the CSR cache size, so we can use - * rt73usb_register_multiwrite() directly. + * rt2x00usb_register_multiwrite() directly. */ memset(&addr_entry, 0, sizeof(addr_entry)); memcpy(&addr_entry, crypto->address, ETH_ALEN); addr_entry.cipher = crypto->cipher; reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); - rt73usb_register_multiwrite(rt2x00dev, reg, + rt2x00usb_register_multiwrite(rt2x00dev, reg, &addr_entry, sizeof(addr_entry)); /* @@ -505,9 +426,9 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * without this received frames will not be decrypted * by the hardware. */ - rt73usb_register_read(rt2x00dev, SEC_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR4, ®); reg |= (1 << crypto->bssidx); - rt73usb_register_write(rt2x00dev, SEC_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg); /* * The driver does not support the IV/EIV generation @@ -530,21 +451,21 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR2, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg); } else { mask = 1 << (key->hw_key_idx - 32); - rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR3, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg); } return 0; @@ -561,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -579,7 +500,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, !(filter_flags & FIF_CONTROL)); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, @@ -598,16 +519,16 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, * bits which (when set to 0) will invalidate the entire beacon. */ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt73usb_register_write(rt2x00dev, beacon_base, 0); + rt2x00usb_register_write(rt2x00dev, beacon_base, 0); /* * Enable synchronisation. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } if (flags & CONFIG_UPDATE_MAC) { @@ -615,7 +536,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); conf->mac[1] = cpu_to_le32(reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, + rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2, conf->mac, sizeof(conf->mac)); } @@ -624,7 +545,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); conf->bssid[1] = cpu_to_le32(reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, + rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4, conf->bssid, sizeof(conf->bssid)); } } @@ -634,26 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - rt73usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR8, ®); rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); - rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -799,14 +720,14 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)); - rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg); if (rt2x00_rf(&rt2x00dev->chip, RF5226) || rt2x00_rf(&rt2x00dev->chip, RF5225)) @@ -896,12 +817,12 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, libconf->conf->long_frame_max_tx_count); rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, libconf->conf->short_frame_max_tx_count); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); } static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, @@ -909,18 +830,18 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, libconf->conf->beacon_int * 16); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt73usb_config(struct rt2x00_dev *rt2x00dev, @@ -953,13 +874,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1119,7 +1040,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); if (reg) break; msleep(1); @@ -1161,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, ®); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1176,12 +1097,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg); /* * CCK TXD BBP registers */ - rt73usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, ®); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1190,77 +1111,77 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg); /* * OFDM TXD BBP registers */ - rt73usb_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, ®); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, ®); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); - rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, ®); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); - rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); - rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); - rt73usb_register_read(rt2x00dev, MAC_CSR6, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR6, ®); rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); - rt73usb_register_write(rt2x00dev, MAC_CSR6, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg); - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); + rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) return -EBUSY; - rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); + rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); /* * Invalidate all Shared Keys (SEC_CSR0), * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) */ - rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); - rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); - rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); reg = 0x000023b0; if (rt2x00_rf(&rt2x00dev->chip, RF5225) || rt2x00_rf(&rt2x00dev->chip, RF2527)) rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); - rt73usb_register_write(rt2x00dev, PHY_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg); - rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); - rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); - rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); + rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); + rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); /* * Clear all beacons @@ -1268,36 +1189,36 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) * the first byte since that byte contains the VALID and OWNER * bits which (when set to 0) will invalidate the entire beacon. */ - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); /* * We must clear the error counters. * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt73usb_register_read(rt2x00dev, STA_CSR0, ®); - rt73usb_register_read(rt2x00dev, STA_CSR1, ®); - rt73usb_register_read(rt2x00dev, STA_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR2, ®); /* * Reset MAC and BBP registers. */ - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); return 0; } @@ -1375,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, (state == STATE_RADIO_RX_OFF) || (state == STATE_RADIO_RX_OFF_LINK)); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -1396,12 +1317,12 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); /* * Disable synchronisation. */ - rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0); rt2x00usb_disable_radio(rt2x00dev); } @@ -1414,10 +1335,10 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); - rt73usb_register_write(rt2x00dev, MAC_CSR12, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); /* * Device is not guaranteed to be in the requested state yet. @@ -1425,7 +1346,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1565,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); /* * Write entire beacon with descriptor to register. @@ -1616,14 +1537,14 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, * For Wi-Fi faily generated beacons between participating stations. * Set TBTT phase adaptive adjustment step to 8us (default 16us) */ - rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } } @@ -1862,7 +1783,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) { @@ -2216,33 +2137,33 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, field.bit_offset = queue_idx * 16; field.bit_mask = 0xffff << field.bit_offset; - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); rt2x00_set_field32(®, field, queue->txop); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + rt2x00usb_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, ®); + rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); rt2x00_set_field32(®, field, queue->txop); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + rt2x00usb_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, ®); + rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, ®); rt2x00_set_field32(®, field, queue->aifs); - rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg); - rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, ®); rt2x00_set_field32(®, field, queue->cw_min); - rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg); - rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, ®); rt2x00_set_field32(®, field, queue->cw_max); - rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg); return 0; } @@ -2260,9 +2181,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) u64 tsf; u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR13, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, ®); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt73usb_register_read(rt2x00dev, TXRX_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, ®); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; -- cgit v1.1 From 0e3de99846489424c2cba952e0a52c269f01009a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 12 Nov 2008 00:01:37 +0100 Subject: rt2x00: Fix TX failure path The callback function write_tx_data() can only fail when our ENTRY_OWNER_DEVICE_DATA flag on a queue entry failed to determine the entry was not available and it is in fact still owned by the hardware. This means that if that function fails the queue must be stopped in mac80211. When rt2x00queue_get_queue() returns NULL in the TX path, it means mac80211 has passed us an invalid queue, although this should be impossible, it shouldn't hurt if we send mac80211 a signal to stop the queue either. Both issues can simply be resolved by removing their manual failure handler and making them use the failure path provided in rt2x00mac_tx(). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00queue.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 48636b0..4c03957 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -132,8 +132,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", qid, DRV_PROJECT); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + goto exit_fail; } /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index d7752db..b8de9d2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -386,7 +386,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) - return -EINVAL; + return -ENOBUFS; if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, @@ -415,7 +415,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) tx_info = IEEE80211_SKB_CB(skb); rate_idx = tx_info->control.rates[0].idx; rate_flags = tx_info->control.rates[0].flags; - skbdesc = get_skb_frame_desc(entry->skb); + skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; skbdesc->tx_rate_idx = rate_idx; @@ -427,20 +427,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) * the frame so we can provide it to the driver seperately. */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && - !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) rt2x00crypto_tx_remove_iv(skb, iv_len); - } /* * It could be possible that the queue was corrupted and this - * call failed. Just drop the frame, we cannot rollback and pass - * the frame to mac80211 because the skb->cb has now been tainted. + * call failed. Since we always return NETDEV_TX_OK to mac80211, + * this frame will simply be dropped. */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - dev_kfree_skb_any(entry->skb); entry->skb = NULL; - return 0; + return -EIO; } if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) -- cgit v1.1 From cee53ddb46eb520079335d0868d0e81c8d311089 Mon Sep 17 00:00:00 2001 From: "Kolekar, Abhijeet" Date: Wed, 12 Nov 2008 13:14:04 -0800 Subject: iwl3945 : Simplify iwl3945_pci_probe Patch aligns iwl3945_pci_probe with iwlwifi's iwl_pci_probe. Added few comments and code simplified to make readable. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 195 +++++++++++++++++----------- 1 file changed, 117 insertions(+), 78 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3344841..18d2a2a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7787,6 +7787,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); unsigned long flags; + /*********************** + * 1. Allocating HW data + * ********************/ + /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ if (iwl3945_param_disable_hw_scan) { @@ -7810,27 +7814,24 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = -ENOMEM; goto out; } - SET_IEEE80211_DEV(hw, &pdev->dev); - hw->rate_control_algorithm = "iwl-3945-rs"; - hw->sta_data_size = sizeof(struct iwl3945_sta_priv); + SET_IEEE80211_DEV(hw, &pdev->dev); - IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); priv = hw->priv; priv->hw = hw; - priv->pci_dev = pdev; priv->cfg = cfg; + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + hw->rate_control_algorithm = "iwl-3945-rs"; + hw->sta_data_size = sizeof(struct iwl3945_sta_priv); + /* Select antenna (may be helpful if only one antenna is connected) */ priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; #ifdef CONFIG_IWL3945_DEBUG iwl3945_debug_level = iwl3945_param_debug; atomic_set(&priv->restrict_refcnt, 0); #endif - priv->retry_rate = 1; - - priv->ibss_beacon = NULL; /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | @@ -7844,14 +7845,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* 4 EDCA QOS priorities */ hw->queues = 4; - spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); + /*************************** + * 2. Initializing PCI bus + * *************************/ if (pci_enable_device(pdev)) { err = -ENODEV; goto out_ieee80211_free_hw; @@ -7859,14 +7855,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - /* Clear the driver's (not device's) station table */ - iwl3945_clear_stations_table(priv); - - priv->data_retry_limit = -1; - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); @@ -7880,10 +7868,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_pci_disable_device; - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_write_config_byte(pdev, 0x41, 0x00); - + /*********************** + * 3. Read REV Register + * ********************/ priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -7894,25 +7881,70 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); - /* Initialize module parameter values here */ + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (iwl3945_param_disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO("Radio disabled.\n"); - } + /* nic init */ + iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - priv->iw_mode = NL80211_IFTYPE_STATION; + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out_remove_sysfs; + } - printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + /*********************** + * 4. Read EEPROM + * ********************/ + /* Read the EEPROM */ + err = iwl3945_eeprom_init(priv); + if (err) { + IWL_ERROR("Unable to init EEPROM\n"); + goto out_remove_sysfs; + } + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + /*********************** + * 5. Setup HW Constants + * ********************/ /* Device-specific setup */ if (iwl3945_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); goto out_iounmap; } + /*********************** + * 6. Setup priv + * ********************/ + priv->retry_rate = 1; + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + INIT_LIST_HEAD(&priv->free_frames); + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwl3945_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = NL80211_IFTYPE_STATION; + if (iwl3945_param_qos_enable) priv->qos_data.qos_enable = 1; @@ -7921,70 +7953,76 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; - iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - iwl3945_setup_deferred_work(priv); - iwl3945_setup_rx_handlers(priv); priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; - spin_lock_irqsave(&priv->lock, flags); - iwl3945_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); + err = iwl3945_init_channel_map(priv); if (err) { - IWL_ERROR("failed to create sysfs device attributes\n"); + IWL_ERROR("initializing regulatory failed: %d\n", err); goto out_release_irq; } - /* nic init */ - iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); - goto out_remove_sysfs; - } - /* Read the EEPROM */ - err = iwl3945_eeprom_init(priv); + err = iwl3945_init_geos(priv); if (err) { - IWL_ERROR("Unable to init EEPROM\n"); - goto out_remove_sysfs; + IWL_ERROR("initializing geos failed: %d\n", err); + goto out_free_channel_map; } - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); - SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - err = iwl3945_init_channel_map(priv); - if (err) { - IWL_ERROR("initializing regulatory failed: %d\n", err); - goto out_remove_sysfs; + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + + /*********************************** + * 7. Initialize Module Parameters + * **********************************/ + + /* Initialize module parameter values here */ + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (iwl3945_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); } - err = iwl3945_init_geos(priv); + + /*********************** + * 8. Setup Services + * ********************/ + + spin_lock_irqsave(&priv->lock, flags); + iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); if (err) { - IWL_ERROR("initializing geos failed: %d\n", err); - goto out_free_channel_map; + IWL_ERROR("failed to create sysfs device attributes\n"); + goto out_free_geos; } + iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + iwl3945_setup_deferred_work(priv); + iwl3945_setup_rx_handlers(priv); + + /*********************** + * 9. Conclude + * ********************/ + pci_save_state(pdev); + pci_disable_device(pdev); + + /********************************* + * 10. Setup and Register mac80211 + * *******************************/ + err = ieee80211_register_hw(priv->hw); if (err) { IWL_ERROR("Failed to register network device (error %d)\n", err); - goto out_free_geos; + goto out_remove_sysfs; } priv->hw->conf.beacon_int = 100; priv->mac80211_registered = 1; - pci_save_state(pdev); - pci_disable_device(pdev); + err = iwl3945_rfkill_init(priv); if (err) @@ -7993,12 +8031,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); out_free_geos: iwl3945_free_geos(priv); out_free_channel_map: iwl3945_free_channel_map(priv); - out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + out_release_irq: destroy_workqueue(priv->workqueue); -- cgit v1.1 From 9f58671e8d4f4896acea30020308ce72bf94ec6e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 12 Nov 2008 13:14:05 -0800 Subject: iwlwifi: consolidate station management code This patch moves code around and group most of the station management code into iwl-sta.c No functional changes (yet) Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 47 ++--------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 - drivers/net/wireless/iwlwifi/iwl-dev.h | 5 -- drivers/net/wireless/iwlwifi/iwl-rx.c | 75 ------------------ drivers/net/wireless/iwlwifi/iwl-sta.c | 134 ++++++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-sta.h | 13 +++- 8 files changed, 148 insertions(+), 132 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c43cf2f..17f4098 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1909,7 +1909,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ee3613d..b6d7e91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -969,7 +969,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8fa4f7a..03acad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3058,49 +3058,11 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) { - struct iwl_priv *priv = hw->priv; - u8 sta_id = IWL_INVALID_STATION; - unsigned long flags; - __le16 key_flags = 0; - int i; + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", - addr); - return; - } - - if (iwl_scan_cancel(priv)) { - /* cancel scan failed, just live w/ bad key and rely - briefly on SW decryption */ - return; - } - - key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (sta_id == priv->hw_params.bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].sta.key.key_flags = key_flags; - priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; - - for (i = 0; i < 5; i++) - priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = - cpu_to_le16(phase1key[i]); - - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - - spin_unlock_irqrestore(&priv->sta_lock, flags); + iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); IWL_DEBUG_MAC80211("leave\n"); } @@ -3239,10 +3201,10 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - return iwl_rx_agg_start(priv, sta->addr, tid, *ssn); + return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); - return iwl_rx_agg_stop(priv, sta->addr, tid); + return iwl_sta_rx_agg_stop(priv, sta->addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); return iwl_tx_agg_start(priv, sta->addr, tid, ssn); @@ -3256,6 +3218,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, } return 0; } + static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ff966b8..5d4e2e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -206,8 +206,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); -int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index bd3df55..0e97d6a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -574,11 +574,6 @@ struct iwl_hw_params { * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ -struct iwl_addsta_cmd; -extern int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); extern void iwl_update_chain_flags(struct iwl_priv *priv); extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); extern const u8 iwl_bcast_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 876afd4..8d2b73e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -499,49 +499,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); -int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; - priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} -EXPORT_SYMBOL(iwl_rx_agg_start); - -int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; - priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} -EXPORT_SYMBOL(iwl_rx_agg_stop); - /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know @@ -1017,38 +974,6 @@ static inline int iwl_calc_rssi(struct iwl_priv *priv, } -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) -{ - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); - - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; - - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } -} - /* This is necessary only for a number of statistics, see the caller. */ static int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 0c5f122..109136a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -132,7 +132,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, return 1; } -int iwl_send_add_sta(struct iwl_priv *priv, +static int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { struct iwl_rx_packet *res = NULL; @@ -180,7 +180,6 @@ int iwl_send_add_sta(struct iwl_priv *priv, return ret; } -EXPORT_SYMBOL(iwl_send_add_sta); static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, struct ieee80211_sta_ht_cap *sta_ht_inf) @@ -703,6 +702,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, return ret; } +void iwl_update_tkip_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + const u8 *addr, u32 iv32, u16 *phase1key) +{ + u8 sta_id = IWL_INVALID_STATION; + unsigned long flags; + __le16 key_flags = 0; + int i; + DECLARE_MAC_BUF(mac); + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); + return; + } + + if (iwl_scan_cancel(priv)) { + /* cancel scan failed, just live w/ bad key and rely + briefly on SW decryption */ + return; + } + + key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == priv->hw_params.bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) + priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = + cpu_to_le16(phase1key[i]); + + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + +} +EXPORT_SYMBOL(iwl_update_tkip_key); + int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) @@ -989,9 +1037,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) EXPORT_SYMBOL(iwl_get_sta_id); /** - * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table + * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table */ -void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) +void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) { unsigned long flags; @@ -1004,5 +1052,81 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); +EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); + +int iwl_sta_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_rx_agg_start); + +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_rx_agg_stop); + +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +{ + /* FIXME: need locking over ps_status ??? */ + u8 sta_id = iwl_find_station(priv, addr); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 221b93e..61eede5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -47,9 +47,20 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); +void iwl_update_tkip_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + const u8 *addr, u32 iv32, u16 *phase1key); + int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); -void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags, + struct ieee80211_sta_ht_cap *ht_info); +void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); +int iwl_sta_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn); +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); +void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr); #endif /* __iwl_sta_h__ */ -- cgit v1.1 From 417f114bf2efa6183477a75da272c0d452e1cda3 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 12 Nov 2008 13:14:06 -0800 Subject: iwlwifi: rs: remove fc variable and other cleanups This patch 1. Removes use once use only fc variables, they are useless after refactoring ieee80211 frame control handlers 2. Other trivial cleanups Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 48 ++++++++++++------------------- 1 file changed, 19 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 0332805..d8ac45d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -281,10 +281,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, u32 time_diff; s32 index; struct iwl_traffic_load *tl = NULL; - __le16 fc = hdr->frame_control; u8 tid; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } else @@ -773,7 +772,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, int status; u8 retries; int rs_index, index = 0; - struct iwl_lq_sta *lq_sta; + struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -785,12 +784,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; - __le16 fc = hdr->frame_control; s32 tpt = 0; IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return; /* This packet was aggregated but doesn't carry rate scale info */ @@ -803,8 +802,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (retries > 15) retries = 15; - lq_sta = (struct iwl_lq_sta *)priv_sta; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) goto out; @@ -1675,7 +1672,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, int high_tpt = IWL_INVALID_VALUE; u32 fail_count; s8 scale_action = 0; - __le16 fc; u16 rate_mask; u8 update_lq = 0; struct iwl_scale_tbl_info *tbl, *tbl1; @@ -1690,13 +1686,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { - /* Send management frames and broadcast/multicast data using - * lowest rate. */ - /* TODO: this could probably be improved.. */ + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return; - } if (!sta || !lq_sta) return; @@ -2095,29 +2090,26 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { - int i; struct sk_buff *skb = txrc->skb; struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - __le16 fc; - struct iwl_lq_sta *lq_sta; + struct iwl_lq_sta *lq_sta = priv_sta; + int rate_idx; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); /* Send management frames and broadcast/multicast data using lowest * rate. */ - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta || !priv_sta) { + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) { info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } - lq_sta = (struct iwl_lq_sta *)priv_sta; - i = lq_sta->last_txrate_idx; + rate_idx = lq_sta->last_txrate_idx; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { @@ -2137,14 +2129,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, } } - if ((i < 0) || (i > IWL_RATE_COUNT)) { - info->control.rates[0].idx = rate_lowest_index(sband, sta); - return; - } + if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + rate_idx = rate_lowest_index(sband, sta); + else if (sband->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; - if (sband->band == IEEE80211_BAND_5GHZ) - i -= IWL_FIRST_OFDM_RATE; - info->control.rates[0].idx = i; + info->control.rates[0].idx = rate_idx; } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, -- cgit v1.1 From dbce56a456f6d6302a77107088340828dcaf9a02 Mon Sep 17 00:00:00 2001 From: "Chatre, Reinette" Date: Wed, 12 Nov 2008 13:14:07 -0800 Subject: iwlwifi: replace magic constants with define use IWL_CCK_RATES_MASK and IWL_OFDM_RATES_MASK instead of their values directly. Signed-off-by: Reinette Chatre cc: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 03acad2..ab599a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -466,9 +466,9 @@ static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) /* Set rate mask*/ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) - rate_mask = priv->active_rate_basic & 0xF; + rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; else - rate_mask = priv->active_rate_basic & 0xFF0; + rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 18d2a2a..1a923c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1425,9 +1425,9 @@ static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv) /* Set rate mask*/ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) - rate_mask = priv->active_rate_basic & 0xF; + rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; else - rate_mask = priv->active_rate_basic & 0xFF0; + rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; i = iwl3945_rates[i].next_ieee) { -- cgit v1.1 From c3056065400aeb437390e1a86b85f9c32fb1c1df Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 12 Nov 2008 13:14:08 -0800 Subject: iwlwifi : fix checkpatch.pl errors Patch fixes checkpatch.pl errors for iwlwifi. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlwifi/iwl-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++-- 9 files changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 1daa3f0..7dea155 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -107,7 +107,7 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l, int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout); IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", addr, bits, mask, - unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); return ret; } #define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 17f4098..9007ff2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -661,7 +661,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, int txq_id = txq->q.id; /* Find out whether to activate Tx queue */ - int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; /* Set up and activate */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), @@ -2025,7 +2025,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? + info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b6d7e91..aeb69ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1111,7 +1111,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? + info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index d8ac45d..3a2b812 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2515,7 +2515,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, for (i = 0; i < LQ_SIZE; i++) { desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" "rate=0x%X\n", - lq_sta->active_tbl == i?"*":"x", + lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ab599a9..e971a89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1492,7 +1492,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) hw_rf_kill = 1; IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); + hw_rf_kill ? "disable radio" : "enable radio"); /* driver only loads ucode once setting the interface up. * the driver as well won't allow loading if RFKILL is set @@ -3657,7 +3657,8 @@ static ssize_t show_power_level(struct device *d, break; } - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); + p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? + "fixed" : "auto"); p += sprintf(p, "\tINDEX:%d", level); p += sprintf(p, "\n"); return p - buf + 1; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 8300f3d..0008a35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -36,7 +36,7 @@ #include "iwl-core.h" -#define IWL_CMD(x) case x : return #x +#define IWL_CMD(x) case x: return #x const char *get_cmd_string(u8 cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 40e0050..bc10435 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -109,7 +109,7 @@ static inline int __iwl_poll_bit(const char *f, u32 l, int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", addr, bits, mask, - unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); return ret; } #define iwl_poll_bit(priv, addr, bits, mask, timeout) \ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 166f000..d9638d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1498,7 +1498,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, ack = bitmap & (1ULL << i); successes += !!ack; IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", - ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, + ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, agg->start_idx + i); } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 1a923c2..baa0d6c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -519,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv) /*************** HOST COMMAND QUEUE FUNCTIONS *****/ -#define IWL_CMD(x) case x : return #x +#define IWL_CMD(x) case x: return #x static const char *get_cmd_string(u8 cmd) { @@ -4320,7 +4320,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); + hw_rf_kill ? "disable radio" : "enable radio"); /* Queue restart only if RF_KILL switch was set to "kill" * when we loaded driver, and is now set to "enable". -- cgit v1.1 From 352bc8de19a7e5e065d422825e226e8e80cd6576 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Wed, 12 Nov 2008 13:14:09 -0800 Subject: iwlwifi: configure_filter rewrite The patch rewrites the mac80211 configure_filter handler to better mapping mac80211 filter flags to iwlwifi hardware filter flags. We now can support 5 mac80211 filter flags: FIF_OTHER_BSS, FIF_ALLMULTI, FIF_PROMISC_IN_BSS, FIF_BCN_PRBRESP_PROMISC and FIF_CONTROL. This patch also avoids reconnecting if the filter flags are changed when the STA is associated. Because rx_assoc is used when full rxon is not necessary. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 1 - drivers/net/wireless/iwlwifi/iwl-agn.c | 65 ++++++++++++++++------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 62 +++++++++++++++------------ 4 files changed, 70 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 7187925..2a924c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -886,7 +886,6 @@ struct iwl3945_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; - struct work_struct set_monitor; struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e971a89..c8ce84a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2224,27 +2224,6 @@ static void iwl_bg_rf_kill(struct work_struct *work) iwl_rfkill_set_hw_state(priv); } -static void iwl_bg_set_monitor(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, - struct iwl_priv, set_monitor); - int ret; - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - ret = iwl_set_mode(priv, NL80211_IFTYPE_MONITOR); - if (ret) { - if (ret == -EAGAIN) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - IWL_ERROR("iwl_set_mode() failed ret = %d\n", ret); - } - - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2890,16 +2869,43 @@ static void iwl_configure_filter(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list) { struct iwl_priv *priv = hw->priv; + __le32 *filter_flags = &priv->staging_rxon.filter_flags; + + IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - NL80211_IFTYPE_MONITOR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); + if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) + *filter_flags |= RXON_FILTER_PROMISC_MSK; + else + *filter_flags &= ~RXON_FILTER_PROMISC_MSK; + } + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) + *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; + else + *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; + } + if (changed_flags & FIF_CONTROL) { + if (*total_flags & FIF_CONTROL) + *filter_flags |= RXON_FILTER_CTL2HOST_MSK; + else + *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; + } + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + + /* We avoid iwl_commit_rxon here to commit the new filter flags + * since mac80211 will call ieee80211_hw_config immediately. + * (mc_list is not supported at this time). Otherwise, we need to + * queue a background iwl_commit_rxon work. + */ + + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } @@ -3796,7 +3802,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl_bg_set_monitor); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0e97d6a1..1b305d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -985,7 +985,6 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; - struct work_struct set_monitor; struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index baa0d6c..beba6e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5996,24 +5996,6 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) iwl3945_rfkill_set_hw_state(priv); } -static void iwl3945_bg_set_monitor(struct work_struct *work) -{ - struct iwl3945_priv *priv = container_of(work, - struct iwl3945_priv, set_monitor); - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - if (!iwl3945_is_ready(priv)) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0) - IWL_ERROR("iwl3945_set_mode() failed\n"); - - mutex_unlock(&priv->mutex); -} - #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) static void iwl3945_bg_scan_check(struct work_struct *data) @@ -6830,16 +6812,43 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list) { struct iwl3945_priv *priv = hw->priv; + __le32 *filter_flags = &priv->staging_rxon.filter_flags; - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - NL80211_IFTYPE_MONITOR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); + IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) + *filter_flags |= RXON_FILTER_PROMISC_MSK; + else + *filter_flags &= ~RXON_FILTER_PROMISC_MSK; + } + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) + *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; + else + *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; + } + if (changed_flags & FIF_CONTROL) { + if (*total_flags & FIF_CONTROL) + *filter_flags |= RXON_FILTER_CTL2HOST_MSK; + else + *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; + } + + /* We avoid iwl_commit_rxon here to commit the new filter flags + * since mac80211 will call ieee80211_hw_config immediately. + * (mc_list is not supported at this time). Otherwise, we need to + * queue a background iwl_commit_rxon work. + */ + + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } @@ -7715,7 +7724,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); -- cgit v1.1 From 34faf780cf342b2c83ae40a2eecf33e55f7002a5 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Wed, 12 Nov 2008 13:14:10 -0800 Subject: iwlwifi: some fh document fix and cleanup This patch cleans up some flow handler related document. It also removes some blank lines. Signed-off-by: Zhu Yi Acked-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-fh.h | 9 ++++----- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ---- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index e46300c..694ebb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -440,7 +440,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) * @lo: low [31:0] portion of the dma address of TX buffer * every even is unaligned on 16 bit boundary * @hi_n_len 0-3 [35:32] portion of dma - * 4-16 length of the tx buffer + * 4-15 length of the tx buffer */ struct iwl_tfd_tb { __le32 lo; @@ -453,7 +453,8 @@ struct iwl_tfd_tb { * Transmit Frame Descriptor (TFD) * * @ __reserved1[3] reserved - * @ num_tbs 0-5 number of active tbs + * @ num_tbs 0-4 number of active tbs + * 5 reserved * 6-7 padding (not used) * @ tbs[20] transmit frame buffer descriptors * @ __pad padding @@ -473,8 +474,6 @@ struct iwl_tfd_tb { * Tx frame, up to 8 KBytes in size. * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. - * - * Bit fields in the control dword (val0): */ struct iwl_tfd { u8 __reserved1[3]; @@ -485,6 +484,6 @@ struct iwl_tfd { /* Keep Warm Size */ -#define IWL_KW_SIZE 0x1000 /*4k */ +#define IWL_KW_SIZE 0x1000 /* 4k */ #endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d9638d7..9f0705b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -587,8 +587,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - - /* Alloc and init all Tx queues, including the command queue (#4) */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? @@ -618,11 +616,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) */ void iwl_txq_ctx_stop(struct iwl_priv *priv) { - int txq_id; unsigned long flags; - /* Turn off all Tx DMA fifos */ spin_lock_irqsave(&priv->lock, flags); if (iwl_grab_nic_access(priv)) { -- cgit v1.1 From e0737a77d6cba100dea7e53bf490d67d110bc037 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 12 Nov 2008 13:14:11 -0800 Subject: iwlwifi: iwl-fh.h cleanup This patch fix value of upper FH register bound plus it reorders and groups registers in more readable way Signed-off-by: Tomas Winkler Acked-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-fh.h | 41 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 694ebb0..bc20acb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -72,7 +72,7 @@ * Addresses are offsets from device's PCI hardware base address. */ #define FH_MEM_LOWER_BOUND (0x1000) -#define FH_MEM_UPPER_BOUND (0x1EF0) +#define FH_MEM_UPPER_BOUND (0x2000) /** * Keep-Warm (KW) buffer base address. @@ -268,6 +268,8 @@ #define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME (0x00008000) +#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ + /** * Rx Shared Status Registers (RSSR) @@ -294,6 +296,13 @@ #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 +/* TFDB Area - TFDs buffer table */ +#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) +#define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900) +#define FH_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958) +#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) +#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) + /** * Transmit DMA Channel Control/Status Registers (TCSR) * @@ -323,6 +332,7 @@ #define FH49_TCSR_CHNL_NUM (7) #define FH50_TCSR_CHNL_NUM (8) +/* TCSR: tx_config register values */ #define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) #define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ @@ -379,31 +389,13 @@ (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) - - -#define FH_REGS_LOWER_BOUND (0x1000) -#define FH_REGS_UPPER_BOUND (0x2000) - /* Tx service channels */ -#define FH_SRVC_CHNL (9) -#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8) -#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0) +#define FH_SRVC_CHNL (9) +#define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8) +#define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) -/* TFDB Area - TFDs buffer table */ -#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) -#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900) -#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958) -#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) -#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) - -/* TCSR: tx_config register values */ -#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ - -#define TFD_QUEUE_SIZE_MAX (256) -#define TFD_QUEUE_SIZE_BC_DUP (64) -#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) /** * struct iwl_rb_status - reseve buffer status @@ -423,9 +415,10 @@ struct iwl_rb_status { } __attribute__ ((packed)); - +#define TFD_QUEUE_SIZE_MAX (256) +#define TFD_QUEUE_SIZE_BC_DUP (64) +#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) #define IWL_TX_DMA_MASK DMA_BIT_MASK(36) - #define IWL_NUM_OF_TBS 20 static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) -- cgit v1.1 From ea4a82dceec7b5782b1259079c8de508d0afe33a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Nov 2008 14:22:04 -0800 Subject: iwlwifi: enable custom fw regulatory solution This enables the custom firmware regulatory solution option on iwlwifi drivers. These devices are uncapable of mapping their EEPROM regulatory domain to a specific ISO / IEC alpha2. Although the new 11n devices (>= iwl 5000) have only 3 regultaory SKUs -- MOW, ABG (no N) and BG -- the older devices (3945 and 4965) have a more complex SKU arrangement and therefore its not practical to move this to the driver. Signed-off-by: Luis R. Rodriguez Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 +++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8bd4d08..fccd150 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -832,6 +832,9 @@ int iwl_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->fw_handles_regulatory = true; + /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index beba6e3..9330dfa 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7850,6 +7850,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->fw_handles_regulatory = true; + /* 4 EDCA QOS priorities */ hw->queues = 4; -- cgit v1.1 From 9f8042021792f8c0e0a7f5b81f326bfab86cda83 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 13 Nov 2008 17:58:41 +0530 Subject: ath9k: INI update for atheros chipets. init values update for various atheros chipsets. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/eeprom.c | 5 + drivers/net/wireless/ath9k/hw.c | 62 +++ drivers/net/wireless/ath9k/hw.h | 23 +- drivers/net/wireless/ath9k/initvals.h | 701 ++++++++++++++++++++++++---------- 4 files changed, 586 insertions(+), 205 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index f5fd03c..9b2fdc5 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -1584,6 +1584,11 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah, return pBase->txMask; case EEP_RX_MASK: return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + default: return 0; } diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index ff6457e..efeef2c 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -557,6 +557,54 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah) return 0; } +static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah) +{ + u32 rxgain_type; + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { + rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE); + + if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_backoff_13db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); + else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_backoff_23db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); + else + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } else + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); +} + +static void ath9k_hw_init_txgain_ini(struct ath_hal *ah) +{ + u32 txgain_type; + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE); + + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_high_power_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); + else + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } else + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); +} + static int ath9k_hw_post_attach(struct ath_hal *ah) { int ecode; @@ -800,6 +848,14 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (ecode != 0) goto bad; + /* rxgain table */ + if (AR_SREV_9280_20_OR_LATER(ah)) + ath9k_hw_init_rxgain_ini(ah); + + /* txgain table */ + if (AR_SREV_9280_20_OR_LATER(ah)) + ath9k_hw_init_txgain_ini(ah); + #ifndef CONFIG_SLOW_ANT_DIV if (ah->ah_devid == AR9280_DEVID_PCI) { for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { @@ -1258,6 +1314,12 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, DO_DELAY(regWrites); } + if (AR_SREV_9280_20_OR_LATER(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites); + + if (AR_SREV_9280_20_OR_LATER(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites); + for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) { u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0); u32 val = INI_RA(&ahp->ah_iniCommon, i, 1); diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 6a29f2d..02256c3 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -415,6 +415,9 @@ struct ar5416Stats { #define AR5416_EEP_MINOR_VER_3 0x3 #define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_9 0x9 +#define AR5416_EEP_MINOR_VER_16 0x10 +#define AR5416_EEP_MINOR_VER_17 0x11 +#define AR5416_EEP_MINOR_VER_19 0x13 #define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_2G_CAL_PIERS 4 @@ -436,6 +439,16 @@ struct ar5416Stats { #define AR5416_MAX_CHAINS 3 #define AR5416_PWR_TABLE_OFFSET -5 +/* Rx gain type values */ +#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 +#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 +#define AR5416_EEP_RXGAIN_ORIG 2 + +/* Tx gain type values */ +#define AR5416_EEP_TXGAIN_ORIGINAL 0 +#define AR5416_EEP_TXGAIN_HIGH_POWER 1 + + enum eeprom_param { EEP_NFTHRESH_5, EEP_NFTHRESH_2, @@ -454,6 +467,8 @@ enum eeprom_param { EEP_MINOR_REV, EEP_TX_MASK, EEP_RX_MASK, + EEP_RXGAIN_TYPE, + EEP_TXGAIN_TYPE, }; enum ar5416_rates { @@ -485,7 +500,11 @@ struct base_eep_header { u32 binBuildNumber; u8 deviceType; u8 pwdclkind; - u8 futureBase[32]; + u8 futureBase_1[2]; + u8 rxGainType; + u8 futureBase_2[3]; + u8 txGainType; + u8 futureBase_3[25]; } __packed; struct spur_chan { @@ -792,6 +811,8 @@ struct ath_hal_5416 { struct ar5416IniArray ah_iniAddac; struct ar5416IniArray ah_iniPcieSerdes; struct ar5416IniArray ah_iniModesAdditional; + struct ar5416IniArray ah_iniModesRxGain; + struct ar5416IniArray ah_iniModesTxGain; }; #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h index 3dd3815..1b08b54 100644 --- a/drivers/net/wireless/ath9k/initvals.h +++ b/drivers/net/wireless/ath9k/initvals.h @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* AR5416 to Fowl ar5146.ini */ static const u32 ar5416Modes_9100[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de }, + { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, @@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00070000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00009808, 0x00000000 }, @@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = { {0x000098c4, 0x00000000 }, }; +/* ar5416 - howl ar5416_howl.ini */ static const u32 ar5416Modes[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = { { 0x0000994c, 0x00020028 }, { 0x0000c95c, 0x004b6a8e }, { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb514 }, + { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -1311,7 +1313,7 @@ static const u32 ar5416Addac[][2] = { {0x000098cc, 0x00000000 }, }; - +/* AR5416 9160 Sowl ar5416_sowl.ini */ static const u32 ar5416Modes_9160[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, @@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00009808, 0x00000000 }, @@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x00750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000a244, 0x00007bb6 }, { 0x0000a248, 0x0fff3ffc }, { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, + { 0x0000a250, 0x0000e000 }, { 0x0000a254, 0x00000000 }, { 0x0000a258, 0x0cc75380 }, { 0x0000a25c, 0x0f0f0f01 }, @@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000a34c, 0x3fffffff }, { 0x0000a350, 0x3fffffff }, { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa33 }, + { 0x0000a358, 0x79bfaa03 }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = { }; static const u32 ar5416Bank6_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = { { 0x000098cc, 0x0000000e }, }; - static u32 ar5416Addac_9160[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = { {0x000098cc, 0x00000000 }, }; - static u32 ar5416Addac_91601_1[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = { {0x000098cc, 0x00000000 }, }; - - +/* XXX 9280 1 */ static const u32 ar9280Modes_9280[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = { { 0x00007898, 0x2a850160 }, }; - - - +/* XXX 9280 2 */ static const u32 ar9280Modes_9280_2[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e }, + { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, - { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 }, + { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 }, { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, - { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c }, - { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, @@ -2587,164 +2581,13 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, - { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, - { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, - { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, - { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, - { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, - { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, - { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, - { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, - { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, - { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, - { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, - { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, - { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, - { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, - { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, - { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, - { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, - { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, - { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, - { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, - { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, - { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, - { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, - { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, @@ -2884,7 +2727,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -2923,6 +2766,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -2939,7 +2783,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00008344, 0x00581043 }, @@ -2973,7 +2817,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x14750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, + { 0x00009968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -2999,13 +2843,14 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, { 0x000099fc, 0x00001042 }, + { 0x0000a208, 0x803e4788 }, { 0x0000a210, 0x4080a333 }, { 0x0000a214, 0x40206c10 }, { 0x0000a218, 0x009c4060 }, { 0x0000a220, 0x01834061 }, { 0x0000a224, 0x00000400 }, { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x233f71c0 }, + { 0x0000a22c, 0x233f7180 }, { 0x0000a234, 0x20202020 }, { 0x0000a238, 0x20202020 }, { 0x0000a23c, 0x13c88000 }, @@ -3022,7 +2867,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000b26c, 0x0ebae9c6 }, { 0x0000d270, 0x00820820 }, { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -3064,7 +2908,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00007808, 0x04924914 }, { 0x0000780c, 0x21084210 }, { 0x00007810, 0x6d801300 }, - { 0x00007814, 0x0019beff }, { 0x00007818, 0x07e41000 }, { 0x0000781c, 0x00392000 }, { 0x00007820, 0x92592480 }, @@ -3073,7 +2916,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000782c, 0x04924914 }, { 0x00007830, 0x21084210 }, { 0x00007834, 0x6d801300 }, - { 0x00007838, 0x0019beff }, { 0x0000783c, 0x07e40000 }, { 0x00007840, 0x00392000 }, { 0x00007844, 0x92592480 }, @@ -3110,12 +2952,465 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = { { 0x00009828, 0x0b020001, 0x0b020001 }, { 0x00009834, 0x00000f0f, 0x00000f0f }, { 0x00009844, 0x03721821, 0x03721821 }, - { 0x00009914, 0x00000898, 0x00000898 }, + { 0x00009914, 0x00000898, 0x00001130 }, { 0x00009918, 0x0000000b, 0x00000016 }, { 0x00009944, 0xdfbc1210, 0xdfbc1210 }, }; +static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, +}; + +static const u32 ar9280Modes_original_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, +}; +static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, + { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, +}; + +static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 }, + { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, +}; + +static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, + { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, +}; static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { {0x00004040, 0x9248fd00 }, @@ -3123,23 +3418,21 @@ static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { {0x00004040, 0xa8000019 }, {0x00004040, 0x13160820 }, {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffc }, - {0x00004040, 0x1aaabe40 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, {0x00004040, 0xbe105554 }, {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, }; - - static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, {0x00004040, 0x13160820 }, {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffd }, - {0x00004040, 0x1aaabe40 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, {0x00004040, 0xbe105554 }, {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, -- cgit v1.1 From f9bbf431beb7dd98b94fa965dab851432be4b762 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 13 Nov 2008 17:59:36 +0530 Subject: ath9k: incorrect noise floor threshold values. This patch fixes incorrect noise floor threshold values. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/calib.c | 4 ++-- drivers/net/wireless/ath9k/eeprom.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c index 1690759..0e214f7 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath9k/calib.c @@ -176,14 +176,14 @@ static bool getNoiseFloorThresh(struct ath_hal *ah, case CHANNEL_A_HT20: case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40MINUS: - *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); + *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); break; case CHANNEL_B: case CHANNEL_G: case CHANNEL_G_HT20: case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40MINUS: - *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); + *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); break; default: DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index 9b2fdc5..180e541 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -1551,9 +1551,9 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah, switch (param) { case EEP_NFTHRESH_5: - return -pModal[0].noiseFloorThreshCh[0]; + return pModal[0].noiseFloorThreshCh[0]; case EEP_NFTHRESH_2: - return -pModal[1].noiseFloorThreshCh[0]; + return pModal[1].noiseFloorThreshCh[0]; case AR_EEPROM_MAC(0): return pBase->macAddr[0] << 8 | pBase->macAddr[1]; case AR_EEPROM_MAC(1): -- cgit v1.1 From e97275cb062cf927cdb086f0107657dd92160801 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 13 Nov 2008 18:00:02 +0530 Subject: ath9k: Build RFKILL feature even when RFKILL subsystem is a MODULE Currently, ath9k builds RFKILL feature only when the RFKILL subsystem is built part of the kernel. Build RFKILL feature regardless of whether RFKILL subsystem is built as a MODULE or part of the kernel. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath9k/core.c | 2 +- drivers/net/wireless/ath9k/hw.c | 6 +++--- drivers/net/wireless/ath9k/main.c | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 3a180ce..6be2b94 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -904,7 +904,7 @@ u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); 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 val); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) void ath9k_enable_rfkill(struct ath_hal *ah); #endif int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 5f5184a..3e94dab 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -705,7 +705,7 @@ void ath_stop(struct ath_softc *sc) } else sc->sc_rxlink = NULL; -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index efeef2c..82c2a42 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2340,7 +2340,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); ath9k_hw_init_qos(ah); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); #endif @@ -3515,7 +3515,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT); if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { ah->ah_rfkill_gpio = @@ -3772,7 +3772,7 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) AR_GPIO_BIT(gpio)); } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) void ath9k_enable_rfkill(struct ath_hal *ah) { REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index fbb2dd2..ce94edee 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -594,7 +594,7 @@ fail: ath_deinit_leds(sc); } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /*******************/ /* Rfkill */ @@ -838,7 +838,7 @@ static void ath_detach(struct ath_softc *sc) ath_deinit_leds(sc); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif ath_rate_control_unregister(); @@ -921,7 +921,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc) /* Initialize LED control */ ath_init_leds(sc); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* Initialze h/w Rfkill */ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); @@ -978,7 +978,7 @@ static int ath9k_start(struct ieee80211_hw *hw) goto exit; } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) error = ath_start_rfkill_poll(sc); #endif @@ -1722,7 +1722,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif @@ -1759,7 +1759,7 @@ static int ath_pci_resume(struct pci_dev *pdev) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* * check the h/w rfkill state on resume * and start the rfkill poll timer -- cgit v1.1 From 306efdd109f086b19d849f1ec0f9104c9fdb3444 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 13 Nov 2008 18:00:37 +0530 Subject: ath9k: IRQ should be disabled before calling free_irq() ath9k frees irq even before IRQs are disabled and existing IRQs are flushed when rfkill_register() fails. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index ce94edee..1ebf606 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -810,9 +810,9 @@ static int ath_start_rfkill_poll(struct ath_softc *sc) rfkill_free(sc->rf_kill.rfkill); /* Deinitialize the device */ + ath_detach(sc); if (sc->pdev->irq) free_irq(sc->pdev->irq, sc); - ath_detach(sc); pci_iounmap(sc->pdev, sc->mem); pci_release_region(sc->pdev, 0); pci_disable_device(sc->pdev); -- cgit v1.1 From db93e7b5bf9dea9175d5b213f9557758c56abbfc Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 13 Nov 2008 18:01:08 +0530 Subject: ath9k: Race condition in accessing TX and RX buffers. Race condition causes RX buffers to be accessed even before it is initialized. The RX and TX buffers are initialized immediately after the hardware is registered with mac80211. The mac80211 start callback is ready to be fired once the device is registered for a case when the wpa_supplicant is also running at the same time. The same race condition is also possible for RKFILL registration as RFKILL init happens after the device registration with mac80211 and it is possible that rfkill_register would be called even before it is initialized. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 1ebf606..c928db9 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -912,14 +912,14 @@ static int ath_attach(u16 devid, struct ath_softc *sc) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; - error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - goto bad; - } + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto detach; - /* Initialize LED control */ - ath_init_leds(sc); + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto detach; #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* Initialze h/w Rfkill */ @@ -931,15 +931,14 @@ static int ath_attach(u16 devid, struct ath_softc *sc) goto detach; #endif - /* initialize tx/rx engine */ - - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto detach; + error = ieee80211_register_hw(hw); + if (error != 0) { + ath_rate_control_unregister(); + goto bad; + } - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto detach; + /* Initialize LED control */ + ath_init_leds(sc); return 0; detach: -- cgit v1.1 From 54ac218ae676931813169e0ca074aca2e4adee38 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Thu, 13 Nov 2008 10:39:14 -0500 Subject: rtl8187: fix 8187B throughput regression Hin-Tak Leung reported that after the change "rtl8187: add short slot handling for 8187B" his RTL8187B started to give low throughput on network transfers. Turns out that the SIFS setting used isn't ok, it doesn't look to be the real aSIFSTime, using the "magical" 0x22 value like on other 818x variants as the vendor does too fixes the issue. Tested-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 4a9f76f..5fe7473 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -935,7 +935,7 @@ static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, difs = 0x32; eifs = 0x5b; } - rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); rtl818x_iowrite8(priv, &priv->map->DIFS, difs); -- cgit v1.1 From b4572a9264312fecdb530a3416b8c8336a3bb9a9 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Thu, 13 Nov 2008 10:39:15 -0500 Subject: rtl8187: implement conf_tx callback to configure tx queues Add conf_tx callback and use it to configure tx queues of 8187L/8187B. Tested-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187.h | 2 + drivers/net/wireless/rtl818x/rtl8187_dev.c | 73 +++++++++++++++++++++++--- drivers/net/wireless/rtl818x/rtl8187_rtl8225.c | 6 --- 3 files changed, 69 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index 33725d0..f09872e 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -111,6 +111,8 @@ struct rtl8187_priv { u8 signal; u8 quality; u8 noise; + u8 slot_time; + u8 aifsn[4]; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 5fe7473..cb5bcef 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -712,6 +712,13 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); + priv->slot_time = 0x9; + priv->aifsn[0] = 2; /* AIFSN[AC_VO] */ + priv->aifsn[1] = 2; /* AIFSN[AC_VI] */ + priv->aifsn[2] = 7; /* AIFSN[AC_BK] */ + priv->aifsn[3] = 3; /* AIFSN[AC_BE] */ + rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); + return 0; } @@ -919,24 +926,38 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, return 0; } +/* + * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for + * example. Thus we have to use raw values for AC_*_PARAM register addresses. + */ +static __le32 *rtl8187b_ac_addr[4] = { + (__le32 *) 0xFFF0, /* AC_VO */ + (__le32 *) 0xFFF4, /* AC_VI */ + (__le32 *) 0xFFFC, /* AC_BK */ + (__le32 *) 0xFFF8, /* AC_BE */ +}; + +#define SIFS_TIME 0xa + static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, bool use_short_preamble) { if (priv->is_rtl8187b) { - u8 difs, eifs, slot_time; + u8 difs, eifs; u16 ack_timeout; + int queue; if (use_short_slot) { - slot_time = 0x9; + priv->slot_time = 0x9; difs = 0x1c; eifs = 0x53; } else { - slot_time = 0x14; + priv->slot_time = 0x14; difs = 0x32; eifs = 0x5b; } rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); + rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time); rtl818x_iowrite8(priv, &priv->map->DIFS, difs); /* @@ -957,18 +978,21 @@ static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, ack_timeout += 144; rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, DIV_ROUND_UP(ack_timeout, 4)); + + for (queue = 0; queue < 4; queue++) + rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue], + priv->aifsn[queue] * priv->slot_time + + SIFS_TIME); } else { rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); if (use_short_slot) { rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); } else { rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); } } } @@ -1017,6 +1041,42 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); } +static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cw_min, cw_max; + + if (queue > 3) + return -EINVAL; + + cw_min = fls(params->cw_min); + cw_max = fls(params->cw_max); + + if (priv->is_rtl8187b) { + priv->aifsn[queue] = params->aifs; + + /* + * This is the structure of AC_*_PARAM registers in 8187B: + * - TXOP limit field, bit offset = 16 + * - ECWmax, bit offset = 12 + * - ECWmin, bit offset = 8 + * - AIFS, bit offset = 0 + */ + rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue], + (params->txop << 16) | (cw_max << 12) | + (cw_min << 8) | (params->aifs * + priv->slot_time + SIFS_TIME)); + } else { + if (queue != 0) + return -EINVAL; + + rtl818x_iowrite8(priv, &priv->map->CW_VAL, + cw_min | (cw_max << 4)); + } + return 0; +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, .start = rtl8187_start, @@ -1027,6 +1087,7 @@ static const struct ieee80211_ops rtl8187_ops = { .config_interface = rtl8187_config_interface, .bss_info_changed = rtl8187_bss_info_changed, .configure_filter = rtl8187_configure_filter, + .conf_tx = rtl8187_conf_tx }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index 69030be..4e75e8e 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -878,12 +878,6 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); - rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); - rtl8225_write_phy_ofdm(dev, 0x97, 0x46); rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); -- cgit v1.1 From 3517afdefc3ad335b276eb5f8691841f48097abf Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Thu, 13 Nov 2008 10:39:16 -0500 Subject: rtl8187: feedback transmitted packets using tx close descriptor for 8187B Realtek 8187B has a receive command queue to feedback beacon interrupt and transmitted packet status. Use it to feedback mac80211 about status of transmitted packets. Unfortunately in the course of testing I found that the sequence number reported by hardware includes entire sequence control in a 12 bit only field, so a workaround is done to check only lowest bits. Tested-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187.h | 5 ++ drivers/net/wireless/rtl818x/rtl8187_dev.c | 135 ++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index f09872e..c385407a9 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -113,6 +113,11 @@ struct rtl8187_priv { u8 noise; u8 slot_time; u8 aifsn[4]; + struct { + __le64 buf; + struct urb *urb; + struct sk_buff_head queue; + } b_tx_status; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index cb5bcef..876d4f9 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -176,8 +176,27 @@ static void rtl8187_tx_cb(struct urb *urb) skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); ieee80211_tx_info_clear_status(info); - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(hw, skb); + + if (!urb->status && + !(info->flags & IEEE80211_TX_CTL_NO_ACK) && + priv->is_rtl8187b) { + skb_queue_tail(&priv->b_tx_status.queue, skb); + + /* queue is "full", discard last items */ + while (skb_queue_len(&priv->b_tx_status.queue) > 5) { + struct sk_buff *old_skb; + + dev_dbg(&priv->udev->dev, + "transmit status queue full\n"); + + old_skb = skb_dequeue(&priv->b_tx_status.queue); + ieee80211_tx_status_irqsafe(hw, old_skb); + } + } else { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status) + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); + } } static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) @@ -219,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); + hdr->retry = cpu_to_le32(info->control.rates[0].count << 8); buf = hdr; ep = 2; @@ -237,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(hdr, 0, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); + hdr->retry = cpu_to_le32(info->control.rates[0].count << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, skb->len, txrate); @@ -403,6 +422,109 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) return 0; } +static void rtl8187b_status_cb(struct urb *urb) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context; + struct rtl8187_priv *priv = hw->priv; + u64 val; + unsigned int cmd_type; + + if (unlikely(urb->status)) { + usb_free_urb(urb); + return; + } + + /* + * Read from status buffer: + * + * bits [30:31] = cmd type: + * - 0 indicates tx beacon interrupt + * - 1 indicates tx close descriptor + * + * In the case of tx beacon interrupt: + * [0:9] = Last Beacon CW + * [10:29] = reserved + * [30:31] = 00b + * [32:63] = Last Beacon TSF + * + * If it's tx close descriptor: + * [0:7] = Packet Retry Count + * [8:14] = RTS Retry Count + * [15] = TOK + * [16:27] = Sequence No + * [28] = LS + * [29] = FS + * [30:31] = 01b + * [32:47] = unused (reserved?) + * [48:63] = MAC Used Time + */ + val = le64_to_cpu(priv->b_tx_status.buf); + + cmd_type = (val >> 30) & 0x3; + if (cmd_type == 1) { + unsigned int pkt_rc, seq_no; + bool tok; + struct sk_buff *skb; + struct ieee80211_hdr *ieee80211hdr; + unsigned long flags; + + pkt_rc = val & 0xFF; + tok = val & (1 << 15); + seq_no = (val >> 16) & 0xFFF; + + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags); + skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) { + ieee80211hdr = (struct ieee80211_hdr *)skb->data; + + /* + * While testing, it was discovered that the seq_no + * doesn't actually contains the sequence number. + * Instead of returning just the 12 bits of sequence + * number, hardware is returning entire sequence control + * (fragment number plus sequence number) in a 12 bit + * only field overflowing after some time. As a + * workaround, just consider the lower bits, and expect + * it's unlikely we wrongly ack some sent data + */ + if ((le16_to_cpu(ieee80211hdr->seq_ctrl) + & 0xFFF) == seq_no) + break; + } + if (skb != (struct sk_buff *) &priv->b_tx_status.queue) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + __skb_unlink(skb, &priv->b_tx_status.queue); + if (tok) + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.rates[0].count = pkt_rc; + + ieee80211_tx_status_irqsafe(hw, skb); + } + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); + } + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct urb *entry; + + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) + return -ENOMEM; + priv->b_tx_status.urb = entry; + + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9), + &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf), + rtl8187b_status_cb, dev); + + usb_submit_urb(entry, GFP_KERNEL); + + return 0; +} + static int rtl8187_cmd_reset(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; @@ -755,6 +877,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) (7 << 0 /* long retry limit */) | (7 << 21 /* MAX TX DMA */)); rtl8187_init_urbs(dev); + rtl8187b_init_status_urb(dev); mutex_unlock(&priv->conf_mutex); return 0; } @@ -831,6 +954,9 @@ static void rtl8187_stop(struct ieee80211_hw *dev) usb_kill_urb(info->urb); kfree_skb(skb); } + while ((skb = skb_dequeue(&priv->b_tx_status.queue))) + dev_kfree_skb_any(skb); + usb_kill_urb(priv->b_tx_status.urb); mutex_unlock(&priv->conf_mutex); } @@ -1317,6 +1443,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } mutex_init(&priv->conf_mutex); + skb_queue_head_init(&priv->b_tx_status.queue); printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", wiphy_name(dev->wiphy), dev->wiphy->perm_addr, -- cgit v1.1 From c8f96974eebbc8f078ad64f2d8041e6dce741d67 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 13 Nov 2008 12:30:41 -0600 Subject: rtl8187: Remove module warning and dependence on CONFIG_EXPERIMENTAL After considerable testing, the initial fears that the driver might damage some flavors of RTL8187B hardware seem to be groundless. Accordingly, the logged warning is removed. In addition, Kconfig is changed to remove the dependence on EXPERIMENTAL. Signed-off-by: Larry Finger Acked-by: Herton Ronaldo Krzesinski Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 +- drivers/net/wireless/rtl818x/rtl8187_dev.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 84b49c8..7ea916b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -508,7 +508,7 @@ config RTL8180 config RTL8187 tristate "Realtek 8187 and 8187B USB support" - depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && USB && WLAN_80211 select EEPROM_93CX6 ---help--- This is a driver for RTL8187 and RTL8187B based cards. diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 876d4f9..180bc50 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1409,9 +1409,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, } if (priv->is_rtl8187b) { - printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " - "is EXPERIMENTAL, and could damage your\n" - " hardware, use at your own risk\n"); + printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); dev->flags |= IEEE80211_HW_SIGNAL_DBM; } else { dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; -- cgit v1.1 From f1ca2167d89d991eed519c789d3902f9682c06b8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 13 Nov 2008 23:07:33 +0100 Subject: rt2x00: Detect USB BULK in/out endpoints Instead of hardcoding the used in/out endpoints we should detect them by walking through all available endpoints. rt2800usb will gain the most out of this, because the legacy drivers indicate that there are multiple endpoints available. However this code might benefit at least rt73usb as well for the MIMO queues, and if we are really lucky rt2500usb will benefit because for the TX and PRIO queues. Even if rt2500usb and rt73usb do not get better performance after this patch, the endpoint detection still belongs to rt2x00usb, and it shouldn't hurt to always try to detect the available endpoints. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 11 ++-- drivers/net/wireless/rt2x00/rt2x00.h | 8 +-- drivers/net/wireless/rt2x00/rt2x00queue.h | 22 +++++++- drivers/net/wireless/rt2x00/rt2x00usb.c | 91 ++++++++++++++++++++++++++++--- drivers/net/wireless/rt2x00/rt73usb.c | 7 +-- 5 files changed, 111 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 40eb643..0447e93 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1108,7 +1108,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); - int pipe = usb_sndbulkpipe(usb_dev, 1); + int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint); int length; u16 reg; @@ -1134,7 +1134,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + length = rt2x00dev->ops->lib->get_tx_data_len(entry); usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe, entry->skb->data, length, rt2500usb_beacondone, @@ -1156,8 +1156,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC); } -static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) +static int rt2500usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1165,8 +1164,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * The length _must_ be a multiple of 2, * but it must _not_ be a multiple of the USB packet size. */ - length = roundup(skb->len, 2); - length += (2 * !(length % rt2x00dev->usb_maxpacket)); + length = roundup(entry->skb->len, 2); + length += (2 * !(length % entry->queue->usb_maxpacket)); return length; } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index fee61be..780ba73 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -555,8 +555,7 @@ struct rt2x00lib_ops { struct txentry_desc *txdesc); int (*write_tx_data) (struct queue_entry *entry); void (*write_beacon) (struct queue_entry *entry); - int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb); + int (*get_tx_data_len) (struct queue_entry *entry); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue); @@ -799,11 +798,6 @@ struct rt2x00_dev { short lna_gain; /* - * USB Max frame size (for rt2500usb & rt73usb). - */ - u16 usb_maxpacket; - - /* * Current TX power value. */ u16 tx_power; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 4d3c724..2e99ab5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -380,6 +380,8 @@ enum queue_index { * @cw_max: The cw max value for outgoing frames (field ignored in RX queue). * @data_size: Maximum data size for the frames in this queue. * @desc_size: Hardware descriptor size for the data in this queue. + * @usb_endpoint: Device endpoint used for communication (USB only) + * @usb_maxpacket: Max packet size for given endpoint (USB only) */ struct data_queue { struct rt2x00_dev *rt2x00dev; @@ -401,6 +403,9 @@ struct data_queue { unsigned short data_size; unsigned short desc_size; + + unsigned short usb_endpoint; + unsigned short usb_maxpacket; }; /** @@ -444,6 +449,19 @@ struct data_queue_desc { &(__dev)->tx[(__dev)->ops->tx_queues] /** + * queue_next - Return pointer to next queue in list (HELPER MACRO). + * @__queue: Current queue for which we need the next queue + * + * Using the current queue address we take the address directly + * after the queue to take the next queue. Note that this macro + * should be used carefully since it does not protect against + * moving past the end of the list. (See macros &queue_end and + * &tx_queue_end for determining the end of the queue). + */ +#define queue_next(__queue) \ + &(__queue)[1] + +/** * queue_loop - Loop through the queues within a specific range (HELPER MACRO). * @__entry: Pointer where the current queue entry will be stored in. * @__start: Start queue pointer. @@ -453,8 +471,8 @@ struct data_queue_desc { */ #define queue_loop(__entry, __start, __end) \ for ((__entry) = (__start); \ - prefetch(&(__entry)[1]), (__entry) != (__end); \ - (__entry) = &(__entry)[1]) + prefetch(queue_next(__entry)), (__entry) != (__end);\ + (__entry) = queue_next(__entry)) /** * queue_for_each - Loop through all queues diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 2fbf78f..83df312 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -234,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry) * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + length = rt2x00dev->ops->lib->get_tx_data_len(entry); usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); @@ -378,10 +378,11 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) struct usb_device *usb_dev = to_usb_device_intf(entry->queue->rt2x00dev->dev); struct queue_entry_priv_usb *entry_priv = entry->priv_data; + int pipe; if (entry->queue->qid == QID_RX) { - usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_rcvbulkpipe(usb_dev, 1), + pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint); + usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe, entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); @@ -393,6 +394,76 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); +static void rt2x00usb_assign_endpoint(struct data_queue *queue, + struct usb_endpoint_descriptor *ep_desc) +{ + struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev); + int pipe; + + queue->usb_endpoint = usb_endpoint_num(ep_desc); + + if (queue->qid == QID_RX) { + pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint); + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0); + } else { + pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint); + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1); + } + + if (!queue->usb_maxpacket) + queue->usb_maxpacket = 1; +} + +static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev) +{ + struct usb_interface *intf = to_usb_interface(rt2x00dev->dev); + struct usb_host_interface *intf_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_desc; + struct data_queue *queue = rt2x00dev->tx; + struct usb_endpoint_descriptor *tx_ep_desc = NULL; + unsigned int i; + + /* + * Walk through all available endpoints to search for "bulk in" + * and "bulk out" endpoints. When we find such endpoints collect + * the information we need from the descriptor and assign it + * to the queue. + */ + for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { + ep_desc = &intf_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep_desc)) { + rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc); + } else if (usb_endpoint_is_bulk_out(ep_desc)) { + rt2x00usb_assign_endpoint(queue, ep_desc); + + if (queue != queue_end(rt2x00dev)) + queue = queue_next(queue); + tx_ep_desc = ep_desc; + } + } + + /* + * At least 1 endpoint for RX and 1 endpoint for TX must be available. + */ + if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) { + ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n"); + return -EPIPE; + } + + /* + * It might be possible not all queues have a dedicated endpoint. + * Loop through all TX queues and copy the endpoint information + * which we have gathered from already assigned endpoints. + */ + txall_queue_for_each(rt2x00dev, queue) { + if (!queue->usb_endpoint) + rt2x00usb_assign_endpoint(queue, tx_ep_desc); + } + + return 0; +} + static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) { @@ -464,6 +535,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) int status; /* + * Find endpoints for each queue + */ + status = rt2x00usb_find_endpoints(rt2x00dev); + if (status) + goto exit; + + /* * Allocate DMA */ queue_for_each(rt2x00dev, queue) { @@ -554,11 +632,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00dev->ops = ops; rt2x00dev->hw = hw; - rt2x00dev->usb_maxpacket = - usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1); - if (!rt2x00dev->usb_maxpacket) - rt2x00dev->usb_maxpacket = 1; - retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) goto exit_free_device; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ee59b4e..37a782d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1508,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry) entry->skb = NULL; } -static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) +static int rt73usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1517,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * The length _must_ be a multiple of 4, * but it must _not_ be a multiple of the USB packet size. */ - length = roundup(skb->len, 4); - length += (4 * !(length % rt2x00dev->usb_maxpacket)); + length = roundup(entry->skb->len, 4); + length += (4 * !(length % entry->queue->usb_maxpacket)); return length; } -- cgit v1.1 From 1d450cfc97bc223e9f94a2fab888bb168e284448 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 13 Nov 2008 19:11:56 -0800 Subject: ath9k: Clarify we only want 32-bit DMA Use DMA_32BIT_MASK to clarify we only want 32-bit DMA memory. What was there before is also 32-bit but this makes it clearer Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index c928db9..9d64ef5 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1591,9 +1591,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_device(pdev)) return -EIO; - /* XXX 32-bit addressing only */ - if (pci_set_dma_mask(pdev, 0xffffffff)) { - printk(KERN_ERR "ath_pci: 32-bit DMA not available\n"); + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); ret = -ENODEV; goto bad; } -- cgit v1.1 From 97b777db57f7226e31a4abd5e69d732037743195 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 13 Nov 2008 19:11:57 -0800 Subject: ath9k: make DMA memory consistent Make the DMAable mameory consistent with pci_set_consistent_dma_mask(). The DMA-mapping.txt Documentation recommends this but for PCI-X considerations and on strange architecture like SGI SN2, not sure why it would fix an issue but lets see if it does, just in case. Before this, this driver was tested with x86_64 with about 7 GB of RAM, not sure if this is really needed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 9d64ef5..3355ba4 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1591,9 +1591,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_device(pdev)) return -EIO; - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); - ret = -ENODEV; + goto bad; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA consistent " + "DMA enable faled\n"); goto bad; } -- cgit v1.1 From d131bb59c142585c389b5284d93743e4e065e393 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 15 Nov 2008 17:02:31 +0100 Subject: p54: enable Mesh Point support This patch enables Mesh Point operation for any p54 device. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1796b8c..e0066c4c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1058,6 +1058,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { *aid = 0; *queue = 3; @@ -1570,6 +1571,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: priv->mode = conf->type; break; default: @@ -1589,6 +1591,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr); break; case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); break; default: @@ -1653,6 +1656,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: memcpy(priv->bssid, conf->bssid, ETH_ALEN); ret = p54_set_freq(dev, dev->conf.channel->center_freq); if (ret) @@ -1826,9 +1830,10 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION | - NL80211_IFTYPE_ADHOC | - NL80211_IFTYPE_AP); + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); dev->channel_change_time = 1000; /* TODO: find actual value */ priv->tx_stats[0].limit = 1; /* Beacon queue */ -- cgit v1.1 From ffed785898a6dfd5f80d069bcb607b8cd5613c76 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 14 Nov 2008 19:41:22 +0100 Subject: p54: minor fixes This patch contains only contains a one-liner fixes and enhancements Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 10 +++++++--- drivers/net/wireless/p54/p54common.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index e0066c4c..6bf5123c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -530,6 +530,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; + if (hdr->rate & 0x10) + rx_status.flag |= RX_FLAG_SHORTPRE; rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? hdr->rate : (hdr->rate - 4)) & 0xf; rx_status.freq = freq; @@ -576,7 +578,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) unsigned long flags; u32 freed = 0, last_addr = priv->rx_start; - if (!skb || !dev) + if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) return; spin_lock_irqsave(&priv->tx_queue.lock, flags); @@ -1199,7 +1201,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->key_type = 0; txhdr->key_len = 0; txhdr->hw_queue = queue; - txhdr->backlog = 32; + if (current_queue) + txhdr->backlog = current_queue->len; + else + txhdr->backlog = 0; memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; @@ -1548,7 +1553,6 @@ static void p54_stop(struct ieee80211_hw *dev) while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - kfree(priv->cached_beacon); priv->cached_beacon = NULL; priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 8c8793c..3419f16 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -259,7 +259,7 @@ enum p54_rx_decrypt_status { P54_DECRYPT_NOCKIPMIC, P54_DECRYPT_FAIL_WEP, P54_DECRYPT_FAIL_TKIP, - P54_DECRYPT_FAIL_MICAHEL, + P54_DECRYPT_FAIL_MICHAEL, P54_DECRYPT_FAIL_CKIPKP, P54_DECRYPT_FAIL_CKIPMIC, P54_DECRYPT_FAIL_AESCCMP -- cgit v1.1 From 40db0b22591f59811feeb7cad26fdde92a190663 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 16 Nov 2008 12:20:32 +0100 Subject: p54pci: cache firmware for suspend/resume Johannes pointed out that the driver has cache the firmware for suspend/resume cycles. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 16 ++++++++++---- drivers/net/wireless/p54/p54pci.c | 42 +++++++++++++++++++----------------- drivers/net/wireless/p54/p54pci.h | 2 +- 3 files changed, 35 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6bf5123c..3373b02 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1524,16 +1524,24 @@ static int p54_start(struct ieee80211_hw *dev) mutex_lock(&priv->conf_mutex); err = priv->open(dev); - if (!err) - priv->mode = NL80211_IFTYPE_MONITOR; + if (err) + goto out; P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); err = p54_set_edcf(dev); - if (!err) - err = p54_init_stats(dev); + if (err) + goto out; + err = p54_init_stats(dev); + if (err) + goto out; + err = p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); + if (err) + goto out; + priv->mode = NL80211_IFTYPE_MONITOR; +out: mutex_unlock(&priv->conf_mutex); return err; } diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index c4a868a..d21c509 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table); static int p54p_upload_firmware(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; __le32 reg; int err; __le32 *data; @@ -73,23 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev); - if (err) { - printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886pci)\n", pci_name(priv->pdev)); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); - if (err) - return err; - } + /* wait for the firmware to reset properly */ + mdelay(10); - err = p54_parse_firmware(dev, fw_entry); - if (err) { - release_firmware(fw_entry); + err = p54_parse_firmware(dev, priv->firmware); + if (err) return err; - } - data = (__le32 *) fw_entry->data; - remains = fw_entry->size; + data = (__le32 *) priv->firmware->data; + remains = priv->firmware->size; device_addr = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { u32 i = 0; @@ -107,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_READ(int_enable); } - release_firmware(fw_entry); - reg = P54P_READ(ctrl_stat); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); @@ -500,15 +489,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev, if (mem_len < sizeof(struct p54p_csr)) { printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", pci_name(pdev)); - pci_disable_device(pdev); - return err; + goto err_disable_dev; } err = pci_request_regions(pdev, "p54pci"); if (err) { printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", pci_name(pdev)); - return err; + goto err_disable_dev; } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || @@ -561,6 +549,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); + err = request_firmware(&priv->firmware, "isl3886pci", + &priv->pdev->dev); + if (err) { + printk(KERN_ERR "%s (p54pci): cannot find firmware " + "(isl3886pci)\n", pci_name(priv->pdev)); + err = request_firmware(&priv->firmware, "isl3886", + &priv->pdev->dev); + if (err) + goto err_free_common; + } + err = p54p_open(dev); if (err) goto err_free_common; @@ -579,6 +578,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, return 0; err_free_common: + release_firmware(priv->firmware); p54_free_common(dev); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); @@ -592,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_reg: pci_release_regions(pdev); + err_disable_dev: pci_disable_device(pdev); return err; } @@ -606,6 +607,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev) ieee80211_unregister_hw(dev); priv = dev->priv; + release_firmware(priv->firmware); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); p54_free_common(dev); diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 4a67780..fbb6839 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -93,7 +93,7 @@ struct p54p_priv { struct pci_dev *pdev; struct p54p_csr __iomem *map; struct tasklet_struct rx_tasklet; - + const struct firmware *firmware; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; -- cgit v1.1 From ced0957442af69c5c41b00db85a933ed7876cc40 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 14 Nov 2008 19:42:39 +0100 Subject: p54: honour bss_info_changed's basic_rates and other settings As was pointed out in "p54: honour bss_info_changed's short slot time settings", bss_info_changed provides more useful settings that can be used by the driver. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 3 +++ drivers/net/wireless/p54/p54common.c | 29 ++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index b585ff6..491ab96 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -102,6 +102,9 @@ struct p54_common { unsigned int output_power; u32 tsf_low32; u32 tsf_high32; + u64 basic_rate_mask; + u16 wakeup_timer; + u16 aid; struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 3373b02..829b3f9 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1249,20 +1249,20 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) setup->rx_antenna = priv->rx_antenna; setup->rx_align = 0; if (priv->fw_var < 0x500) { - setup->v1.basic_rate_mask = cpu_to_le32(0x15f); + setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(setup->v1.rts_rates, 0, 8); setup->v1.rx_addr = cpu_to_le32(priv->rx_end); setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); setup->v1.rxhw = cpu_to_le16(priv->rxhw); - setup->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); setup->v1.unalloc0 = cpu_to_le16(0); } else { setup->v2.rx_addr = cpu_to_le32(priv->rx_end); setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); setup->v2.rxhw = cpu_to_le16(priv->rxhw); - setup->v2.timer = cpu_to_le16(1000); + setup->v2.timer = cpu_to_le16(priv->wakeup_timer); setup->v2.truncate = cpu_to_le16(48896); - setup->v2.basic_rate_mask = cpu_to_le32(0x15f); + setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); setup->v2.sbss_offset = 0; setup->v2.mcast_window = 0; setup->v2.rx_rssi_threshold = 0; @@ -1348,7 +1348,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) } else { chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssical_add = cpu_to_le16(0xfe70); - chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(chan->v2.rts_rates, 0, 8); } priv->tx(dev, skb, 1); @@ -1808,6 +1808,24 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->use_short_slot = info->use_short_slot; p54_set_edcf(dev); } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) + priv->basic_rate_mask = (info->basic_rates << 4); + else + priv->basic_rate_mask = info->basic_rates; + p54_setup_mac(dev, priv->mac_mode, priv->bssid); + if (priv->fw_var >= 0x500) + p54_set_freq(dev, dev->conf.channel->center_freq); + } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc) { + priv->aid = info->aid; + priv->wakeup_timer = info->beacon_int * + info->dtim_period * 5; + p54_setup_mac(dev, priv->mac_mode, priv->bssid); + } + } + } static const struct ieee80211_ops p54_ops = { @@ -1837,6 +1855,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->basic_rate_mask = 0x15f; skb_queue_head_init(&priv->tx_queue); dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | -- cgit v1.1 From 4d3601b234a51fdd268c8ef8068d239e26dd7ef1 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Sat, 15 Nov 2008 00:49:49 +0530 Subject: ath9k: Configure AR_PHY_SWITCH_COM with apropriate antenna control This fixes the poor wireless connection which happens even if we are very well in the range. Signed-off-by: Don.breslin@atheros.com Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index 180e541..466dbce 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -1244,7 +1244,7 @@ bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; - ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config); + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); for (i = 0; i < AR5416_MAX_CHAINS; i++) { -- cgit v1.1 From f941f8590c06c6b1a77c4b5a5df59f39a3c7d1e9 Mon Sep 17 00:00:00 2001 From: Andrey Borzenkov Date: Sat, 15 Nov 2008 17:15:09 +0300 Subject: orinoco: indicate it is using dBm in wireless_stats and spy Since WE7 /proc/net/wireless checks whether level and noise are in dBm and shows them accordingly. Indicate that we return signal and noice levels in dBm. Before: Inter-| sta-| Quality | Discarded packets | Missed | WE face | tus | link level noise | nwid crypt frag retry misc | beacon | 22 eth1: 0000 65. 219. 165. 0 0 148 41 0 0 After: Inter-| sta-| Quality | Discarded packets | Missed | WE face | tus | link level noise | nwid crypt frag retry misc | beacon | 22 eth1: 0000 65. -37. -91. 0 0 0 0 0 0 While at it, replace raw numbers with appropriate macro. Signed-off-by: Andrey Borzenkov Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index fd92639..7ec038a 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -809,7 +809,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) wstats->qual.qual = (int)le16_to_cpu(cq.qual); wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = 7; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; } } @@ -1168,7 +1168,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, wstats.level = level - 0x95; wstats.noise = noise - 0x95; wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = 7; + wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, mac, &wstats); } -- cgit v1.1 From d507748ac6de67369e76058a8a921cd22734f40a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 16 Nov 2008 00:08:50 +0100 Subject: rt2x00: Don't switch off LED on initialization When we switch off the LEDS during initialization we kill rt73usb from proper functioning. The immediate result after the first LED command are MCU failures and a complete breakdown of TX/RX. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00leds.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index 66c61b1..68f4e0fc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -111,12 +111,6 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, led->led_dev.name = name; led->led_dev.brightness = LED_OFF; - /* - * Ensure the LED is off, it might have been enabled - * by the hardware when the device was powered on. - */ - led->led_dev.brightness_set(&led->led_dev, LED_OFF); - retval = led_classdev_register(device, &led->led_dev); if (retval) { ERROR(rt2x00dev, "Failed to register led handler.\n"); -- cgit v1.1 From 1548c86ab1552199a3b99b958ccfb590fc9c8f84 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 17 Nov 2008 09:08:21 -0600 Subject: rtl8187: Fix transmission count sent to mac80211 In the commit entitled "mac80211/drivers: rewrite the rate control API", the meaning of the packet transmit count was changed from the number of retries to the total number. In driver rtl8187, this change was missed. Signed-off-by: Larry Finger Acked-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 180bc50..69ea522 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -496,7 +496,7 @@ static void rtl8187b_status_cb(struct urb *urb) __skb_unlink(skb, &priv->b_tx_status.queue); if (tok) info->flags |= IEEE80211_TX_STAT_ACK; - info->status.rates[0].count = pkt_rc; + info->status.rates[0].count = pkt_rc + 1; ieee80211_tx_status_irqsafe(hw, skb); } -- cgit v1.1 From 3fcdfb4b940a226184bc01bfc5c58b32b509b965 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 18 Nov 2008 01:19:56 +0530 Subject: ath9k: Fix panic while unregistering rfkill [ 6133.670329] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 6133.672802] IP: [] ieee80211_stop_queues+0x26/0x40 [mac80211] [ 6133.672802] PGD 759dc067 PUD 74f1d067 PMD 0 [ 6133.672802] Oops: 0002 [#1] PREEMPT SMP [ 6133.672802] last sysfs file: /sys/class/backlight/acpi_video0/brightness [ 6133.672802] CPU 0 [ 6133.672802] Modules linked in: ath9k(-) mac80211 pciehp pci_hotplug arc4 ecb joydev pcmcia ppdev lp ppp_generic psmouse sg pcspkr s] [ 6133.735830] Pid: 4445, comm: rmmod Tainted: G W 2.6.28-rc5-wl #1 [ 6133.735830] RIP: 0010:[] [] ieee80211_stop_queues+0x26/0x40 [mac80211] [ 6133.735830] RSP: 0018:ffff88007d1efd10 EFLAGS: 00010246 [ 6133.735830] RAX: 0000000000000000 RBX: ffff880074f41aa0 RCX: 0000000000000000 [ 6133.735830] RDX: 0000000000000010 RSI: 0000000000000000 RDI: ffff880074f40340 [ 6133.735830] RBP: ffff880074990000 R08: 0000000000000000 R09: 000000000000224d [ 6133.735830] R10: 0000000000000000 R11: ffffffff8031dc70 R12: 0000000000000000 [ 6133.735830] R13: 0000000000000001 R14: ffff880074f46c9c R15: 0000000000000000 [ 6133.735830] FS: 00007f1e2e0bc6f0(0000) GS:ffffffff805e0b80(0000) knlGS:0000000000000000 [ 6133.735830] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 6133.735830] CR2: 0000000000000010 CR3: 0000000075593000 CR4: 00000000000006e0 [ 6133.735830] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 6133.735830] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 6133.735830] Process rmmod (pid: 4445, threadinfo ffff88007d1ee000, task ffff88007c0c8000) [ 6133.735830] Stack: [ 6133.735830] ffffffffa034d583 ffff88007c7d9410 ffff88007c7d9410 ffff88007c7d9410 [ 6133.735830] ffffffff80481dab ffff880074f41aa0 00000000fffffff0 0000000000000000 [ 6133.735830] 0000000000000001 0000000000000001 ffffffffa034d8a5 ffff88007c7d9400 [ 6133.735830] Call Trace: [ 6133.735830] [] ? ath_radio_disable+0x33/0x150 [ath9k] [ 6133.735830] [] ? __mutex_lock_slowpath+0x20b/0x2a0 [ 6133.735830] [] ? ath_sw_toggle_radio+0x65/0xa0 [ath9k] [ 6133.735830] [] ? rfkill_toggle_radio+0x74/0x140 [rfkill] [ 6133.735830] [] ? rfkill_remove_switch+0x67/0x80 [rfkill] [ 6133.735830] [] ? rfkill_unregister+0x25/0x50 [rfkill] [ 6133.735830] [] ? ath_detach+0xf5/0x140 [ath9k] [ 6133.735830] [] ? ath_pci_remove+0x29/0x80 [ath9k] [ 6133.735830] [] ? pci_device_remove+0x2c/0x60 [ 6133.735830] [] ? __device_release_driver+0x99/0x100 [ 6133.735830] [] ? driver_detach+0xc0/0xd0 [ 6133.735830] [] ? bus_remove_driver+0x8e/0xd0 [ 6133.735830] [] ? pci_unregister_driver+0x36/0xa0 [ 6133.735830] [] ? exit_ath_pci+0x10/0x29 [ath9k] [ 6133.735830] [] ? sys_delete_module+0x1cb/0x2d0 [ 6133.735830] [] ? do_munmap+0x349/0x390 [ 6133.735830] [] ? __up_write+0x21/0x150 [ 6133.735830] [] ? system_call_fastpath+0x16/0x1b [ 6133.735830] Code: c3 0f 1f 40 00 0f b7 57 5e 0f b7 47 5c 01 c2 74 30 31 c9 66 90 48 8b 57 78 0f b7 c1 48 c1 e0 07 48 03 82 00 03 00 [ 6133.735830] RIP [] ieee80211_stop_queues+0x26/0x40 [mac80211] Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 3355ba4..4c2c58e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -834,13 +834,13 @@ static void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); - ieee80211_unregister_hw(hw); - - ath_deinit_leds(sc); - #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif + ath_deinit_leds(sc); + + ieee80211_unregister_hw(hw); + ath_rate_control_unregister(); ath_rate_detach(sc->sc_rc); -- cgit v1.1 From 256b77593f3ec07f58cd1f0d573ffe9ccd941b5b Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:03:12 +0530 Subject: ath9k: Merge struct ath_tx_ratectrl with ath_rate_node Avoid casting of ath_tx_ratctrl and access the elements directly. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 346 +++++++++++++++++++--------------------- drivers/net/wireless/ath9k/rc.h | 71 ++++----- 2 files changed, 192 insertions(+), 225 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 517992d..21116c5 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -542,19 +542,19 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl) + struct ath_rate_node *ath_rc_priv) { u8 i, j, idx, idx_next; - for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) { + for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { for (j = 0; j <= i-1; j++) { - idx = rate_ctrl->valid_rate_index[j]; - idx_next = rate_ctrl->valid_rate_index[j+1]; + idx = ath_rc_priv->valid_rate_index[j]; + idx_next = ath_rc_priv->valid_rate_index[j+1]; if (rate_table->info[idx].ratekbps > rate_table->info[idx_next].ratekbps) { - rate_ctrl->valid_rate_index[j] = idx_next; - rate_ctrl->valid_rate_index[j+1] = idx; + ath_rc_priv->valid_rate_index[j] = idx_next; + ath_rc_priv->valid_rate_index[j+1] = idx; } } } @@ -562,40 +562,40 @@ static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, /* Access functions for valid_txrate_mask */ -static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl) +static void ath_rc_init_valid_txmask(struct ath_rate_node *ath_rc_priv) { u8 i; - for (i = 0; i < rate_ctrl->rate_table_size; i++) - rate_ctrl->valid_rate_index[i] = FALSE; + for (i = 0; i < ath_rc_priv->rate_table_size; i++) + ath_rc_priv->valid_rate_index[i] = FALSE; } -static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline void ath_rc_set_valid_txmask(struct ath_rate_node *ath_rc_priv, u8 index, int valid_tx_rate) { - ASSERT(index <= rate_ctrl->rate_table_size); - rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE; + ASSERT(index <= ath_rc_priv->rate_table_size); + ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE; } -static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline int ath_rc_isvalid_txmask(struct ath_rate_node *ath_rc_priv, u8 index) { - ASSERT(index <= rate_ctrl->rate_table_size); - return rate_ctrl->valid_rate_index[index]; + ASSERT(index <= ath_rc_priv->rate_table_size); + return ath_rc_priv->valid_rate_index[index]; } /* Iterators for valid_txrate_mask */ static inline int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, + struct ath_rate_node *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { u8 i; - for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) { - if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = rate_ctrl->valid_rate_index[i+1]; + for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i+1]; return TRUE; } } @@ -625,14 +625,14 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) static inline int ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, + struct ath_rate_node *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { int8_t i; - for (i = 1; i < rate_ctrl->max_valid_rate ; i++) { - if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = rate_ctrl->valid_rate_index[i-1]; + for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i-1]; return TRUE; } } @@ -647,11 +647,9 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, const struct ath_rate_table *rate_table, u32 capflag) { - struct ath_tx_ratectrl *rate_ctrl; u8 i, hi = 0; u32 valid; - 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 : @@ -663,11 +661,11 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) continue; - valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy]; + valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, i, TRUE); + ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, i, TRUE); hi = A_MAX(hi, i); } } @@ -685,8 +683,6 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, { /* XXX: Clean me up and make identation friendly */ u8 i, j, hi = 0; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); /* Use intersection of working rates and valid rates */ for (i = 0; i < rateset->rs_nrates; i++) { @@ -714,12 +710,12 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, continue; valid_rate_count = - rate_ctrl->valid_phy_ratecnt[phy]; + ath_rc_priv->valid_phy_ratecnt[phy]; - rate_ctrl->valid_phy_rateidx[phy] + ath_rc_priv->valid_phy_rateidx[phy] [valid_rate_count] = j; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, j, TRUE); + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, TRUE); hi = A_MAX(hi, j); } } @@ -733,8 +729,6 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, u8 *mcs_set, u32 capflag) { u8 i, j, hi = 0; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); /* Use intersection of working rates and valid rates */ for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) { @@ -754,10 +748,10 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) continue; - rate_ctrl->valid_phy_rateidx[phy] - [rate_ctrl->valid_phy_ratecnt[phy]] = j; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, j, TRUE); + ath_rc_priv->valid_phy_rateidx[phy] + [ath_rc_priv->valid_phy_ratecnt[phy]] = j; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, TRUE); hi = A_MAX(hi, j); } } @@ -875,16 +869,12 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; int8_t rssi_last, rssi_reduce = 0, index = 0; - struct ath_tx_ratectrl *rate_ctrl = NULL; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ? - (ath_rc_priv) : NULL); *is_probing = FALSE; - rssi_last = median(rate_ctrl->rssi_last, - rate_ctrl->rssi_last_prev, - rate_ctrl->rssi_last_prev2); + rssi_last = median(ath_rc_priv->rssi_last, + ath_rc_priv->rssi_last_prev, + ath_rc_priv->rssi_last_prev2); /* * Age (reduce) last ack rssi based on how old it is. @@ -896,7 +886,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, */ now_msec = jiffies_to_msecs(jiffies); - dt = now_msec - rate_ctrl->rssi_time; + dt = now_msec - ath_rc_priv->rssi_time; if (dt >= 185) rssi_reduce = 10; @@ -915,7 +905,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, */ best_thruput = 0; - maxindex = rate_ctrl->max_valid_rate-1; + maxindex = ath_rc_priv->max_valid_rate-1; minindex = 0; best_rate = minindex; @@ -927,8 +917,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, for (index = maxindex; index >= minindex ; index--) { u8 per_thres; - rate = rate_ctrl->valid_rate_index[index]; - if (rate > rate_ctrl->rate_max_phy) + rate = ath_rc_priv->valid_rate_index[index]; + if (rate > ath_rc_priv->rate_max_phy) continue; /* @@ -942,7 +932,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * 10-15 and we would be worse off then staying * at the current rate. */ - per_thres = rate_ctrl->state[rate].per; + per_thres = ath_rc_priv->state[rate].per; if (per_thres < 12) per_thres = 12; @@ -961,29 +951,29 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * of max retries, use the min rate for the next retry */ if (is_retry) - rate = rate_ctrl->valid_rate_index[minindex]; + rate = ath_rc_priv->valid_rate_index[minindex]; - rate_ctrl->rssi_last_lookup = rssi_last; + ath_rc_priv->rssi_last_lookup = rssi_last; /* * Must check the actual rate (ratekbps) to account for * non-monoticity of 11g's rate table */ - if (rate >= rate_ctrl->rate_max_phy && probe_allowed) { - rate = rate_ctrl->rate_max_phy; + if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) { + rate = ath_rc_priv->rate_max_phy; /* Probe the next allowed phy state */ /* FIXME:XXXX Check to make sure ratMax is checked properly */ if (ath_rc_get_nextvalid_txrate(rate_table, - rate_ctrl, rate, &next_rate) && - (now_msec - rate_ctrl->probe_time > + ath_rc_priv, rate, &next_rate) && + (now_msec - ath_rc_priv->probe_time > rate_table->probe_interval) && - (rate_ctrl->hw_maxretry_pktcnt >= 1)) { + (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { rate = next_rate; - rate_ctrl->probe_rate = rate; - rate_ctrl->probe_time = now_msec; - rate_ctrl->hw_maxretry_pktcnt = 0; + ath_rc_priv->probe_rate = rate; + ath_rc_priv->probe_time = now_msec; + ath_rc_priv->hw_maxretry_pktcnt = 0; *is_probing = TRUE; } } @@ -994,8 +984,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * normally 1 rather than 0 because of the rate 9 vs 6 issue * in the old code. */ - if (rate > (rate_ctrl->rate_table_size - 1)) - rate = rate_ctrl->rate_table_size - 1; + if (rate > (ath_rc_priv->rate_table_size - 1)) + rate = ath_rc_priv->rate_table_size - 1; ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || (rate_table->info[rate].valid_single_stream && @@ -1031,13 +1021,11 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, { u32 j; u8 nextindex; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); if (min_rate) { for (j = RATE_TABLE_SIZE; j > 0; j--) { if (ath_rc_get_nextlowervalid_txrate(rate_table, - rate_ctrl, rix, &nextindex)) + ath_rc_priv, rix, &nextindex)) rix = nextindex; else break; @@ -1045,7 +1033,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, } else { for (j = stepdown; j > 0; j--) { if (ath_rc_get_nextlowervalid_txrate(rate_table, - rate_ctrl, rix, &nextindex)) + ath_rc_priv, rix, &nextindex)) rix = nextindex; else break; @@ -1225,7 +1213,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, struct ath_tx_info_priv *info_priv, int tx_rate, int xretries, int retries) { - struct ath_tx_ratectrl *rate_ctrl; u32 now_msec = jiffies_to_msecs(jiffies); int state_change = FALSE, rate, count; u8 last_per; @@ -1249,8 +1236,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (!ath_rc_priv) return; - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - ASSERT(tx_rate >= 0); if (tx_rate < 0) return; @@ -1262,30 +1247,30 @@ static void ath_rc_update_ht(struct ath_softc *sc, info_priv->tx.ts_rssi < 3 ? 0 : info_priv->tx.ts_rssi - 3; - last_per = rate_ctrl->state[tx_rate].per; + last_per = ath_rc_priv->state[tx_rate].per; if (xretries) { /* Update the PER. */ if (xretries == 1) { - rate_ctrl->state[tx_rate].per += 30; - if (rate_ctrl->state[tx_rate].per > 100) - rate_ctrl->state[tx_rate].per = 100; + ath_rc_priv->state[tx_rate].per += 30; + if (ath_rc_priv->state[tx_rate].per > 100) + ath_rc_priv->state[tx_rate].per = 100; } else { /* xretries == 2 */ count = ARRAY_SIZE(nretry_to_per_lookup); 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) + + ath_rc_priv->state[tx_rate].per = + (u8)(ath_rc_priv->state[tx_rate].per - + (ath_rc_priv->state[tx_rate].per >> 3) + ((100) >> 3)); } /* xretries == 1 or 2 */ - if (rate_ctrl->probe_rate == tx_rate) - rate_ctrl->probe_rate = 0; + if (ath_rc_priv->probe_rate == tx_rate) + ath_rc_priv->probe_rate = 0; } else { /* xretries == 0 */ /* Update the PER. */ @@ -1307,10 +1292,10 @@ static void ath_rc_update_ht(struct ath_softc *sc, * simplified version of the sum of these two terms. */ if (info_priv->n_frames > 0) - rate_ctrl->state[tx_rate].per + ath_rc_priv->state[tx_rate].per = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + + (ath_rc_priv->state[tx_rate].per - + (ath_rc_priv->state[tx_rate].per >> 3) + ((100*(retries*info_priv->n_frames + info_priv->n_bad_frames) / (info_priv->n_frames * @@ -1318,23 +1303,23 @@ static void ath_rc_update_ht(struct ath_softc *sc, } else { /* 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) + + ath_rc_priv->state[tx_rate].per = (u8) + (ath_rc_priv->state[tx_rate].per - + (ath_rc_priv->state[tx_rate].per >> 3) + (nretry_to_per_lookup[retries] >> 3)); } - rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev; - rate_ctrl->rssi_last_prev = rate_ctrl->rssi_last; - rate_ctrl->rssi_last = info_priv->tx.ts_rssi; - rate_ctrl->rssi_time = now_msec; + ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; + ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; + ath_rc_priv->rssi_last = info_priv->tx.ts_rssi; + ath_rc_priv->rssi_time = now_msec; /* * If we got at most one retry then increase the max rate if * this was a probe. Otherwise, ignore the probe. */ - if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) { + if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { if (retries > 0 || 2 * info_priv->n_bad_frames > info_priv->n_frames) { /* @@ -1344,17 +1329,17 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the subframes were bad then also consider * the probe a failure. */ - rate_ctrl->probe_rate = 0; + ath_rc_priv->probe_rate = 0; } else { u8 probe_rate = 0; - rate_ctrl->rate_max_phy = rate_ctrl->probe_rate; - probe_rate = rate_ctrl->probe_rate; + ath_rc_priv->rate_max_phy = ath_rc_priv->probe_rate; + probe_rate = ath_rc_priv->probe_rate; - if (rate_ctrl->state[probe_rate].per > 30) - rate_ctrl->state[probe_rate].per = 20; + if (ath_rc_priv->state[probe_rate].per > 30) + ath_rc_priv->state[probe_rate].per = 20; - rate_ctrl->probe_rate = 0; + ath_rc_priv->probe_rate = 0; /* * Since this probe succeeded, we allow the next @@ -1362,7 +1347,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, * to move up faster if the probes are * succesful. */ - rate_ctrl->probe_time = now_msec - + ath_rc_priv->probe_time = now_msec - rate_table->probe_interval / 2; } } @@ -1373,51 +1358,51 @@ static void ath_rc_update_ht(struct ath_softc *sc, * this was because of collisions or poor signal. * * Later: if rssi_ack is close to - * rate_ctrl->state[txRate].rssi_thres and we see lots + * ath_rc_priv->state[txRate].rssi_thres and we see lots * of retries, then we could increase - * rate_ctrl->state[txRate].rssi_thres. + * ath_rc_priv->state[txRate].rssi_thres. */ - rate_ctrl->hw_maxretry_pktcnt = 0; + ath_rc_priv->hw_maxretry_pktcnt = 0; } else { /* * It worked with no retries. First ignore bogus (small) * rssi_ack values. */ - if (tx_rate == rate_ctrl->rate_max_phy && - rate_ctrl->hw_maxretry_pktcnt < 255) { - rate_ctrl->hw_maxretry_pktcnt++; + if (tx_rate == ath_rc_priv->rate_max_phy && + ath_rc_priv->hw_maxretry_pktcnt < 255) { + ath_rc_priv->hw_maxretry_pktcnt++; } if (info_priv->tx.ts_rssi >= rate_table->info[tx_rate].rssi_ack_validmin) { /* Average the rssi */ - if (tx_rate != rate_ctrl->rssi_sum_rate) { - rate_ctrl->rssi_sum_rate = tx_rate; - rate_ctrl->rssi_sum = - rate_ctrl->rssi_sum_cnt = 0; + if (tx_rate != ath_rc_priv->rssi_sum_rate) { + ath_rc_priv->rssi_sum_rate = tx_rate; + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; } - rate_ctrl->rssi_sum += info_priv->tx.ts_rssi; - rate_ctrl->rssi_sum_cnt++; + ath_rc_priv->rssi_sum += info_priv->tx.ts_rssi; + ath_rc_priv->rssi_sum_cnt++; - if (rate_ctrl->rssi_sum_cnt > 4) { + if (ath_rc_priv->rssi_sum_cnt > 4) { int32_t rssi_ackAvg = - (rate_ctrl->rssi_sum + 2) / 4; + (ath_rc_priv->rssi_sum + 2) / 4; int8_t rssi_thres = - rate_ctrl->state[tx_rate]. + ath_rc_priv->state[tx_rate]. rssi_thres; int8_t rssi_ack_vmin = rate_table->info[tx_rate]. rssi_ack_validmin; - rate_ctrl->rssi_sum = - rate_ctrl->rssi_sum_cnt = 0; + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; /* Now reduce the current * rssi threshold. */ if ((rssi_ackAvg < rssi_thres + 2) && (rssi_thres > rssi_ack_vmin)) { - rate_ctrl->state[tx_rate]. + ath_rc_priv->state[tx_rate]. rssi_thres--; } @@ -1433,14 +1418,14 @@ static void ath_rc_update_ht(struct ath_softc *sc, * If this rate looks bad (high PER) then stop using it for * a while (except if we are probing). */ - if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 && + if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && 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); + rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + (u8) tx_rate, &ath_rc_priv->rate_max_phy); /* Don't probe for a little while. */ - rate_ctrl->probe_time = now_msec; + ath_rc_priv->probe_time = now_msec; } if (state_change) { @@ -1452,16 +1437,16 @@ static void ath_rc_update_ht(struct ath_softc *sc, * increasing between the CCK and OFDM rates.) */ for (rate = tx_rate; rate < - rate_ctrl->rate_table_size - 1; rate++) { + ath_rc_priv->rate_table_size - 1; rate++) { if (rate_table->info[rate+1].phy != rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + + if (ath_rc_priv->state[rate].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]. + ath_rc_priv->state[rate+1].rssi_thres) { + ath_rc_priv->state[rate+1].rssi_thres = + ath_rc_priv->state[rate]. rssi_thres + rate_table->info[rate]. rssi_ack_deltamin; @@ -1474,25 +1459,25 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + + if (ath_rc_priv->state[rate].rssi_thres + rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { - if (rate_ctrl->state[rate+1].rssi_thres < + ath_rc_priv->state[rate+1].rssi_thres) { + if (ath_rc_priv->state[rate+1].rssi_thres < rate_table->info[rate]. rssi_ack_deltamin) - rate_ctrl->state[rate].rssi_thres = 0; + ath_rc_priv->state[rate].rssi_thres = 0; else { - rate_ctrl->state[rate].rssi_thres = - rate_ctrl->state[rate+1]. + ath_rc_priv->state[rate].rssi_thres = + ath_rc_priv->state[rate+1]. rssi_thres - rate_table->info[rate]. rssi_ack_deltamin; } - if (rate_ctrl->state[rate].rssi_thres < + if (ath_rc_priv->state[rate].rssi_thres < rate_table->info[rate]. rssi_ack_validmin) { - rate_ctrl->state[rate].rssi_thres = + ath_rc_priv->state[rate].rssi_thres = rate_table->info[rate]. rssi_ack_validmin; } @@ -1502,50 +1487,50 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ - if (rate_ctrl->state[tx_rate].per < last_per) { + if (ath_rc_priv->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) break; - if (rate_ctrl->state[rate].per > - rate_ctrl->state[rate+1].per) { - rate_ctrl->state[rate].per = - rate_ctrl->state[rate+1].per; + if (ath_rc_priv->state[rate].per > + ath_rc_priv->state[rate+1].per) { + ath_rc_priv->state[rate].per = + ath_rc_priv->state[rate+1].per; } } } /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) { - if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per) - rate_ctrl->state[rate+1].per = - rate_ctrl->state[rate].per; + for (rate = tx_rate; rate < ath_rc_priv->rate_table_size - 1; rate++) { + if (ath_rc_priv->state[rate+1].per < ath_rc_priv->state[rate].per) + ath_rc_priv->state[rate+1].per = + ath_rc_priv->state[rate].per; } /* Every so often, we reduce the thresholds and * PER (different for CCK and OFDM). */ - if (now_msec - rate_ctrl->rssi_down_time >= + if (now_msec - ath_rc_priv->rssi_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { - if (rate_ctrl->state[rate].rssi_thres > + for (rate = 0; rate < ath_rc_priv->rate_table_size; rate++) { + if (ath_rc_priv->state[rate].rssi_thres > rate_table->info[rate].rssi_ack_validmin) - rate_ctrl->state[rate].rssi_thres -= 1; + ath_rc_priv->state[rate].rssi_thres -= 1; } - rate_ctrl->rssi_down_time = now_msec; + ath_rc_priv->rssi_down_time = now_msec; } /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ - if (now_msec - rate_ctrl->per_down_time >= + if (now_msec - ath_rc_priv->per_down_time >= 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; + for (rate = 0; rate < ath_rc_priv->rate_table_size; rate++) { + ath_rc_priv->state[rate].per = + 7 * ath_rc_priv->state[rate].per / 8; } - rate_ctrl->per_down_time = now_msec; + ath_rc_priv->per_down_time = now_msec; } } @@ -1560,7 +1545,6 @@ static void ath_rc_update(struct ath_softc *sc, { 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]; u8 flags; u32 series = 0, rix; @@ -1568,7 +1552,6 @@ static void ath_rc_update(struct ath_softc *sc, memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0])); rate_table = (struct ath_rate_table *) asc->hw_rate_table[sc->sc_curmode]; - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); ASSERT(rcs[0].tries != 0); /* @@ -1583,7 +1566,7 @@ static void ath_rc_update(struct ath_softc *sc, /* If HT40 and we have switched mode from * 40 to 20 => don't update */ if ((flags & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != + (ath_rc_priv->rc_phy_mode != (flags & ATH_RC_CW40_FLAG))) return; if ((flags & ATH_RC_CW40_FLAG) && @@ -1619,7 +1602,7 @@ static void ath_rc_update(struct ath_softc *sc, flags = rcs[series].flags; /* If HT40 and we have switched mode from 40 to 20 => don't update */ if ((flags & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG))) + (ath_rc_priv->rc_phy_mode != (flags & ATH_RC_CW40_FLAG))) return; if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG)) @@ -1697,8 +1680,6 @@ 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; u8 i, j, k, hi = 0, hthi = 0; rate_table = (struct ath_rate_table *) @@ -1706,24 +1687,24 @@ static void ath_rc_sib_update(struct ath_softc *sc, /* Initial rate table size. Will change depending * on the working rate set */ - rate_ctrl->rate_table_size = MAX_TX_RATE_TBL; + ath_rc_priv->rate_table_size = MAX_TX_RATE_TBL; /* Initialize thresholds according to the global rate table */ - for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) { - rate_ctrl->state[i].rssi_thres = + for (i = 0 ; (i < ath_rc_priv->rate_table_size) && (!keep_state); i++) { + ath_rc_priv->state[i].rssi_thres = rate_table->info[i].rssi_ack_validmin; - rate_ctrl->state[i].per = 0; + ath_rc_priv->state[i].per = 0; } /* Determine the valid rates */ - ath_rc_init_valid_txmask(rate_ctrl); + ath_rc_init_valid_txmask(ath_rc_priv); for (i = 0; i < WLAN_RC_PHY_MAX; i++) { for (j = 0; j < MAX_TX_RATE_PHY; j++) - rate_ctrl->valid_phy_rateidx[i][j] = 0; - rate_ctrl->valid_phy_ratecnt[i] = 0; + ath_rc_priv->valid_phy_rateidx[i][j] = 0; + ath_rc_priv->valid_phy_ratecnt[i] = 0; } - rate_ctrl->rc_phy_mode = (capflag & WLAN_RC_40_FLAG); + ath_rc_priv->rc_phy_mode = (capflag & WLAN_RC_40_FLAG); /* Set stream capability */ ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1; @@ -1745,33 +1726,33 @@ static void ath_rc_sib_update(struct ath_softc *sc, hi = A_MAX(hi, hthi); } - rate_ctrl->rate_table_size = hi + 1; - rate_ctrl->rate_max_phy = 0; - ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL); + ath_rc_priv->rate_table_size = hi + 1; + ath_rc_priv->rate_max_phy = 0; + ASSERT(ath_rc_priv->rate_table_size <= MAX_TX_RATE_TBL); for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) { - rate_ctrl->valid_rate_index[k++] = - rate_ctrl->valid_phy_rateidx[i][j]; + for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { + ath_rc_priv->valid_rate_index[k++] = + ath_rc_priv->valid_phy_rateidx[i][j]; } if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE) - || !rate_ctrl->valid_phy_ratecnt[i]) + || !ath_rc_priv->valid_phy_ratecnt[i]) continue; - rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1]; + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; } - ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL); + ASSERT(ath_rc_priv->rate_table_size <= MAX_TX_RATE_TBL); ASSERT(k <= MAX_TX_RATE_TBL); - rate_ctrl->max_valid_rate = k; + ath_rc_priv->max_valid_rate = k; /* * Some third party vendors don't send the supported rate series in * order. So sorting to make sure its in order, otherwise our RateFind * Algo will select wrong rates */ - ath_rc_sort_validrates(rate_table, rate_ctrl); - rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4]; + ath_rc_sort_validrates(rate_table, ath_rc_priv); + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; } /* @@ -1804,10 +1785,7 @@ static int ath_rate_newassoc(struct ath_softc *sc, */ static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv) { - struct ath_tx_ratectrl *rate_ctrl; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies); + ath_rc_priv->rssi_down_time = jiffies_to_msecs(jiffies); } diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 6671097..2166243 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -204,8 +204,22 @@ struct ath_tx_ratectrl_state { u8 per; /* recent estimate of packet error rate (%) */ }; +struct ath_rateset { + u8 rs_nrates; + u8 rs_rates[ATH_RATE_MAX]; +}; + +/* per-device state */ +struct ath_rate_softc { + /* phy tables that contain rate control data */ + const void *hw_rate_table[ATH9K_MODE_MAX]; + + /* -1 or index of fixed rate */ + int fixedrix; +}; + /** - * struct ath_tx_ratectrl - TX Rate control Information + * struct ath_rate_node - Rate Control priv data * @state: RC state * @rssi_last: last ACK rssi * @rssi_last_lookup: last ACK rssi used for lookup @@ -224,9 +238,15 @@ struct ath_tx_ratectrl_state { * @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 + * @prev_data_rix: rate idx of last data frame + * @ht_cap: HT capabilities + * @single_stream: When TRUE, only single TX stream possible + * @neg_rates: Negotatied rates + * @neg_ht_rates: Negotiated HT rates */ -struct ath_tx_ratectrl { - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; + +/* per-node state */ +struct ath_rate_node { int8_t rssi_last; int8_t rssi_last_lookup; int8_t rssi_last_prev; @@ -236,55 +256,24 @@ struct ath_tx_ratectrl { 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 ht_cap; + u8 single_stream; 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 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u32 per_down_time; u32 probe_interval; -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -/* per-device state */ -struct ath_rate_softc { - /* phy tables that contain rate control data */ - const void *hw_rate_table[ATH9K_MODE_MAX]; - - /* -1 or index of fixed rate */ - int fixedrix; -}; - -/* per-node state */ -struct ath_rate_node { - struct ath_tx_ratectrl tx_ratectrl; - - /* rate idx of last data frame */ u32 prev_data_rix; - - /* ht capabilities */ - u8 ht_cap; - - /* When TRUE, only single stream Tx possible */ - u8 single_stream; - - /* Negotiated rates */ + struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; struct ath_rateset neg_rates; - - /* Negotiated HT rates */ struct ath_rateset neg_ht_rates; - struct ath_rate_softc *asc; struct ath_vap *avp; }; -- cgit v1.1 From fe60594a76d04b4fdea597bf93e4186a03d8d60c Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:03:36 +0530 Subject: ath9k: Simplify RC alloc/free functions Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 48 ++++++----------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 21116c5..09d622a 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -780,29 +780,6 @@ struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah) return asc; } -static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp, - struct ath_rate_softc *rsc, - gfp_t gfp) -{ - struct ath_rate_node *anode; - - anode = kzalloc(sizeof(struct ath_rate_node), gfp); - if (anode == NULL) - return NULL; - - anode->avp = avp; - anode->asc = rsc; - avp->rc_node = anode; - - return anode; -} - -static void ath_rate_node_free(struct ath_rate_node *anode) -{ - if (anode != NULL) - kfree(anode); -} - void ath_rate_detach(struct ath_rate_softc *asc) { if (asc != NULL) @@ -1778,17 +1755,6 @@ static int ath_rate_newassoc(struct ath_softc *sc, return 0; } -/* - * This routine is called to initialize the rate control parameters - * in the SIB. It is called initially during system initialization - * or when a station is associated with the AP. - */ -static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv) -{ - ath_rc_priv->rssi_down_time = jiffies_to_msecs(jiffies); -} - - static void ath_setup_rates(struct ath_softc *sc, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, @@ -1964,21 +1930,23 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp struct ath_vap *avp; struct ath_rate_node *rate_priv; - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - vif = sc->sc_vaps[0]; ASSERT(vif); avp = (void *)vif->drv_priv; - rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); + rate_priv = kzalloc(sizeof(struct ath_rate_node), gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to allocate private rc structure\n", __func__); return NULL; } - ath_rc_sib_init(rate_priv); + + rate_priv->avp = avp; + rate_priv->asc = sc->sc_rc; + avp->rc_node = rate_priv; + rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); return rate_priv; } @@ -1987,10 +1955,8 @@ static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) { struct ath_rate_node *rate_priv = priv_sta; - struct ath_softc *sc = priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); - ath_rate_node_free(rate_priv); + kfree(rate_priv); } static struct rate_control_ops ath_rate_ops = { -- cgit v1.1 From 7b4d27357aebfdaa039f365fd24f2a795af5c0bb Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:04:00 +0530 Subject: ath9k: Remove ath_setup_rates Setup legacy rates in ath_rate_init() itself. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 09d622a..798dff6f 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1755,26 +1755,6 @@ static int ath_rate_newassoc(struct ath_softc *sc, return 0; } -static void ath_setup_rates(struct ath_softc *sc, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_rate_node *rc_priv) - -{ - int i, j = 0; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - rc_priv->neg_rates.rs_nrates = j; -} - void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) { struct ath_softc *sc = hw->priv; @@ -1895,11 +1875,17 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ath_rate_node *ath_rc_priv = priv_sta; int i, j = 0; - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + for (i = 0; i < sband->n_bitrates; i++) { + if (sta->supp_rates[sband->band] & BIT(i)) { + ath_rc_priv->neg_rates.rs_rates[j] + = (sband->bitrates[i].bitrate * 2) / 10; + j++; + } + } + ath_rc_priv->neg_rates.rs_nrates = j; - ath_setup_rates(sc, sband, sta, ath_rc_priv); if (sta->ht_cap.ht_supported) { - for (i = 0; i < 77; i++) { + for (i = 0, j = 0; i < 77; i++) { if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) @@ -1907,14 +1893,12 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, } ath_rc_priv->neg_ht_rates.rs_nrates = j; } + ath_rc_node_update(sc->hw, priv_sta); } static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ath_softc *sc = hw->priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); return hw->priv; } -- cgit v1.1 From 4df8ec64fdec5a99ebfe41467d414e235d5d051e Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:04:21 +0530 Subject: ath9k: Remove ath_rate_newassoc() Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 798dff6f..1ec5861 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1732,29 +1732,6 @@ static void ath_rc_sib_update(struct ath_softc *sc, ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; } -/* - * Update rate-control state on station associate/reassociate. - */ -static int ath_rate_newassoc(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - unsigned int capflag, - struct ath_rateset *negotiated_rates, - struct ath_rateset *negotiated_htrates) -{ - - - ath_rc_priv->ht_cap = - ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) | - ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) | - ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) | - ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0); - - ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0, - negotiated_rates, negotiated_htrates); - - return 0; -} - void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) { struct ath_softc *sc = hw->priv; @@ -1766,10 +1743,16 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) capflag |= ATH_RC_CW40_FLAG; } - ath_rate_newassoc(sc, rc_priv, capflag, + rc_priv->ht_cap = + ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) | + ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) | + ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) | + ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0); + + + ath_rc_sib_update(sc, rc_priv, rc_priv->ht_cap, 0, &rc_priv->neg_rates, &rc_priv->neg_ht_rates); - } /* Rate Control callbacks */ -- cgit v1.1 From 46494e6df8f6d9739d56c8b980229af4e5d2353f Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:05:13 +0530 Subject: ath9k: Remove half/quarter rate tables Half/Quarter rate tables are needed only for legacy chipsets. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 2 +- drivers/net/wireless/ath9k/rc.c | 143 +++++--------------------------------- drivers/net/wireless/ath9k/rc.h | 2 +- 3 files changed, 20 insertions(+), 127 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 3e94dab..bab9eaa 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1075,7 +1075,7 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - sc->sc_rc = ath_rate_attach(ah); + sc->sc_rc = ath_rate_attach(sc); if (sc->sc_rc == NULL) { error = -EIO; goto bad2; diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1ec5861..aafd10d 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -348,72 +348,6 @@ static struct ath_rate_table ar5416_11a_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11a_ratetable_Half = { - 8, - { - { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */ - 2700, 0x0b, 0x00, (0x80|6), - 0, 2, 1, 0, 0}, - { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 9 Mb */ - 3900, 0x0f, 0x00, 9, - 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */ - 5000, 0x0a, 0x00, (0x80|12), - 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */ - 6950, 0x0e, 0x00, 18, - 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */ - 8650, 0x09, 0x00, (0x80|24), - 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */ - 11500, 0x0d, 0x00, 36, - 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */ - 13700, 0x08, 0x00, 48, - 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */ - 14650, 0x0c, 0x00, 54, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - -static struct ath_rate_table ar5416_11a_ratetable_Quarter = { - 8, - { - { TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */ - 1350, 0x0b, 0x00, (0x80|3), - 0, 2, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */ - 1950, 0x0f, 0x00, 4, - 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */ - 2500, 0x0a, 0x00, (0x80|6), - 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */ - 3475, 0x0e, 0x00, 9, - 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */ - 4325, 0x09, 0x00, (0x80|12), - 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */ - 5750, 0x0d, 0x00, 18, - 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */ - 6850, 0x08, 0x00, 24, - 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */ - 7325, 0x0c, 0x00, 27, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - static struct ath_rate_table ar5416_11g_ratetable = { 12, { @@ -480,45 +414,6 @@ static struct ath_rate_table ar5416_11b_ratetable = { 0, /* Phy rates allowed initially */ }; -static void ar5416_attach_ratetables(struct ath_rate_softc *sc) -{ - /* - * Attach rate tables. - */ - sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable; - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable; - - sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = - &ar5416_11ng_ratetable; -} - -static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter; - return; -} - -static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half; - return; -} - -static void ar5416_setfull_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - return; -} - /* * Return the median of three numbers */ @@ -758,25 +653,33 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, return hi; } -/* - * Attach to a device instance. Setup the public definition - * of how much per-node space we need and setup the private - * phy tables that have rate control parameters. - */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah) +struct ath_rate_softc *ath_rate_attach(struct ath_softc *sc) { struct ath_rate_softc *asc; - /* we are only in user context so we can sleep for memory */ asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL); if (asc == NULL) return NULL; - ar5416_attach_ratetables(asc); + asc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable; + asc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; + asc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable; + + asc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable; + asc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable; + + asc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = + &ar5416_11na_ratetable; + asc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = + &ar5416_11na_ratetable; + asc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = + &ar5416_11ng_ratetable; + asc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = + &ar5416_11ng_ratetable; /* Save Maximum TX Trigger Level (used for 11n) */ - tx_triglevel_max = ah->ah_caps.tx_triglevel_max; - /* return alias for ath_rate_softc * */ + tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max; + return asc; } @@ -816,16 +719,6 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) { struct ath_rate_softc *asc = sc->sc_rc; - /* For half and quarter rate channles use different - * rate tables - */ - if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF) - ar5416_sethalf_ratetable(asc); - else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER) - ar5416_setquarter_ratetable(asc); - else /* full rate */ - ar5416_setfull_ratetable(asc); - if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) { asc->fixedrix = sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff]; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 2166243..2d8df83 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -290,7 +290,7 @@ struct ath_tx_info_priv { /* * Attach/detach a rate control module. */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah); +struct ath_rate_softc *ath_rate_attach(struct ath_softc *sch); void ath_rate_detach(struct ath_rate_softc *asc); /* -- cgit v1.1 From 2b406f1e68dd5348384fd166ac532af46bfc87fc Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:05:35 +0530 Subject: ath9k: Nuke fixed rate handling in driver Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 4 -- drivers/net/wireless/ath9k/core.h | 8 ---- drivers/net/wireless/ath9k/main.c | 8 ---- drivers/net/wireless/ath9k/rc.c | 92 ++------------------------------------- drivers/net/wireless/ath9k/rc.h | 29 +----------- 5 files changed, 4 insertions(+), 137 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index bab9eaa..ea332a2 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -89,13 +89,9 @@ static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) const struct ath9k_rate_table *rt; int i; - memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); rt = ath9k_hw_getratetable(sc->sc_ah, mode); BUG_ON(!rt); - for (i = 0; i < rt->rateCount; i++) - sc->sc_rixmap[rt->info[i].rateCode] = (u8) i; - memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); for (i = 0; i < 256; i++) { u8 ix = rt->rateCodeToIndex[i]; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 69e8d3e..fe9dc99 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -641,19 +641,12 @@ void ath_get_beaconconfig(struct ath_softc *sc, #define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) -/* VAP configuration (from protocol layer) */ -struct ath_vap_config { - u32 av_fixed_rateset; - u32 av_fixed_retryset; -}; - /* driver-specific vap state */ struct ath_vap { int av_bslot; /* beacon slot index */ enum ath9k_opmode av_opmode; /* VAP operational mode */ struct ath_buf *av_bcbuf; /* beacon buffer */ struct ath_tx_control av_btxctl; /* txctl information for beacon */ - struct ath_vap_config av_config;/* vap configuration parameters*/ struct ath_rate_node *rc_node; }; @@ -915,7 +908,6 @@ struct ath_softc { /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; const struct ath9k_rate_table *sc_currates; - u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */ u8 sc_protrix; /* protection rate index */ struct { u32 rateKbps; /* transfer rate in kbs */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 4c2c58e..60319d7 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -379,7 +379,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, "%s: Unable to set channel\n", __func__); - ath_rate_newstate(sc, avp); /* Update ratectrl about the new state */ ath_rc_node_update(hw, avp->rc_node); @@ -1099,10 +1098,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, /* Set the device opmode */ sc->sc_ah->ah_opmode = ic_opmode; - /* default VAP configuration */ - avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; - avp->av_config.av_fixed_retryset = 0x03030303; - if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ /* Start ANI */ @@ -1205,9 +1200,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - /* Update ratectrl about the new state */ - ath_rate_newstate(sc, avp); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index aafd10d..8a45b25 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -709,27 +709,6 @@ u8 ath_rate_findrateix(struct ath_softc *sc, return 0; } -/* - * Update rate-control state on a device state change. When - * operating as a station this includes associate/reassociate - * with an AP. Otherwise this gets called, for example, when - * the we transition to run state when operating as an AP. - */ -void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) -{ - struct ath_rate_softc *asc = sc->sc_rc; - - if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) { - asc->fixedrix = - sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff]; - /* NB: check the fixed rate exists */ - if (asc->fixedrix == 0xff) - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } else { - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } -} - static u8 ath_rc_ratefind_ht(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv, const struct ath_rate_table *rate_table, @@ -1009,73 +988,11 @@ static void ath_rate_findrate(struct ath_softc *sc, int *is_probe, int is_retry) { - struct ath_vap *avp = ath_rc_priv->avp; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - if (!num_rates || !num_tries) return; - if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) { - ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates, - rcflag, series, is_probe, is_retry); - } else { - /* Fixed rate */ - int idx; - u8 flags; - u32 rix; - struct ath_rate_softc *asc = ath_rc_priv->asc; - struct ath_rate_table *rate_table; - - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; - - for (idx = 0; idx < 4; idx++) { - unsigned int mcs; - u8 series_rix = 0; - - 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); - - if (idx == 3 && (mcs & 0xf0) == 0x70) - mcs = (mcs & ~0xf0)|0x80; - - if (!(mcs & 0x80)) - flags = 0; - else - flags = ((ath_rc_priv->ht_cap & - WLAN_RC_DS_FLAG) ? - ATH_RC_DS_FLAG : 0) | - ((ath_rc_priv->ht_cap & - WLAN_RC_40_FLAG) ? - ATH_RC_CW40_FLAG : 0) | - ((ath_rc_priv->ht_cap & - WLAN_RC_SGI_FLAG) ? - ((ath_rc_priv->ht_cap & - WLAN_RC_40_FLAG) ? - ATH_RC_SGI_FLAG : 0) : 0); - - series[idx].rix = sc->sc_rixmap[mcs]; - series_rix = series[idx].rix; - - /* XXX: Give me some cleanup love */ - if ((flags & ATH_RC_CW40_FLAG) && - (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[series_rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[series_rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[series_rix].cw40index; - else - rix = rate_table->info[series_rix].base_index; - series[idx].max_4ms_framelen = - rate_table->info[rix].max_4ms_framelen; - series[idx].flags = flags; - } - } + ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates, + rcflag, series, is_probe, is_retry); } static void ath_rc_update_ht(struct ath_softc *sc, @@ -1498,11 +1415,8 @@ static void ath_rate_tx_complete(struct ath_softc *sc, { int final_ts_idx = info_priv->tx.ts_rateindex; int tx_status = 0, is_underrun = 0; - 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 (info_priv->tx.ts_status & ATH9K_TXERR_FILT) return; if (info_priv->tx.ts_rssi > 0) { diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 2d8df83..8d0650a 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -60,16 +60,6 @@ struct ath_softc; #define ATH_RATE_MAX 30 -enum ieee80211_fixed_rate_mode { - IEEE80211_FIXED_RATE_NONE = 0, - IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */ -}; - -/* - * Use the hal os glue code to get ms time - */ -#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) - #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 @@ -287,27 +277,10 @@ struct ath_tx_info_priv { u8 min_rate; }; -/* - * Attach/detach a rate control module. - */ struct ath_rate_softc *ath_rate_attach(struct ath_softc *sch); void ath_rate_detach(struct ath_rate_softc *asc); - -/* - * Update/reset rate control state for 802.11 state transitions. - * Important mostly as the analog to ath_rate_newassoc when operating - * in station mode. - */ 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 rate index for given Dot11 Rate. - */ -u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11_rate); - -/* Routines to register/unregister rate control algorithm */ +u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); void ath_rate_control_unregister(void); -- cgit v1.1 From be0418ada3fad110977a9d5fa16d4907d4e7d726 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:05:55 +0530 Subject: ath9k: Revamp RX handling Remove a lot of old, crufty code and make RX status reporting a bit sane and clean. Do not do anything to the RX skb before unmapping. So in ath_rx_tasklet(), move the skb_put() after PCI unmap. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 53 +--- drivers/net/wireless/ath9k/main.c | 100 ------- drivers/net/wireless/ath9k/recv.c | 575 ++++++++++++++------------------------ 3 files changed, 209 insertions(+), 519 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index fe9dc99..5500ef4 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -279,13 +279,6 @@ struct ath_descdma { dma_addr_t dd_dmacontext; }; -/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */ - -struct ath_rx_context { - struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */ -}; -#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb) - int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head, @@ -298,61 +291,21 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head); -/******/ -/* RX */ -/******/ +/***********/ +/* RX / TX */ +/***********/ #define ATH_MAX_ANTENNA 3 #define ATH_RXBUF 512 #define WME_NUM_TID 16 -/* per frame rx status block */ -struct ath_recv_status { - u64 tsf; /* mac tsf */ - int8_t rssi; /* RSSI (noise floor ajusted) */ - int8_t rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int8_t rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int8_t abs_rssi; /* absolute RSSI */ - u8 rateieee; /* data rate received (IEEE rate code) */ - u8 ratecode; /* phy rate code */ - int rateKbps; /* data rate received (Kbps) */ - int antenna; /* rx antenna */ - int flags; /* status of associated skb */ -#define ATH_RX_FCS_ERROR 0x01 -#define ATH_RX_MIC_ERROR 0x02 -#define ATH_RX_DECRYPT_ERROR 0x04 -#define ATH_RX_RSSI_VALID 0x08 -/* if any of ctl,extn chainrssis are valid */ -#define ATH_RX_CHAIN_RSSI_VALID 0x10 -/* if extn chain rssis are valid */ -#define ATH_RX_RSSI_EXTN_VALID 0x20 -/* set if 40Mhz, clear if 20Mhz */ -#define ATH_RX_40MHZ 0x40 -/* set if short GI, clear if full GI */ -#define ATH_RX_SHORT_GI 0x80 -}; - -struct ath_rxbuf { - struct sk_buff *rx_wbuf; - unsigned long rx_time; /* system time when received */ - struct ath_recv_status rx_status; /* cached rx status */ -}; - int ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); void ath_flushrecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); -void ath_handle_rx_intr(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); void ath_rx_cleanup(struct ath_softc *sc); int ath_rx_tasklet(struct ath_softc *sc, int flush); -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix); -/******/ -/* TX */ -/******/ #define ATH_TXBUF 512 /* max number of transmit attempts (tries) */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 60319d7..c9ac5e8 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -236,68 +236,6 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } -static int ath_rate2idx(struct ath_softc *sc, int rate) -{ - int i = 0, cur_band, n_rates; - struct ieee80211_hw *hw = sc->hw; - - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; - - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].bitrate == rate) - break; - } - - /* - * NB:mac80211 validates rx rate index against the supported legacy rate - * index only (should be done against ht rates also), return the highest - * legacy rate index for rx rate which does not match any one of the - * supported basic and extended rates to make mac80211 happy. - * The following hack will be cleaned up once the issue with - * the rx rate index validation in mac80211 is fixed. - */ - if (i == n_rates) - return n_rates - 1; - return i; -} - -static void ath9k_rx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - rx_status->mactime = status->tsf; - rx_status->band = curchan->band; - rx_status->freq = curchan->center_freq; - rx_status->noise = sc->sc_ani.sc_noise_floor; - rx_status->signal = rx_status->noise + status->rssi; - rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); - rx_status->antenna = status->antenna; - - /* at 45 you will be able to use MCS 15 reliably. A more elaborate - * scheme can be used here but it requires tables of SNR/throughput for - * each possible mode used. */ - rx_status->qual = status->rssi * 100 / 45; - - /* rssi can be more than 45 though, anything above that - * should be considered at 100% */ - if (rx_status->qual > 100) - rx_status->qual = 100; - - if (status->flags & ATH_RX_MIC_ERROR) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - if (status->flags & ATH_RX_FCS_ERROR) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - - rx_status->flag |= RX_FLAG_TSFT; -} - static void ath9k_ht_conf(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { @@ -440,44 +378,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ieee80211_tx_status(hw, skb); } -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_rx_status rx_status; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - int padsize; - - /* see if any padding is done by the hw and remove it */ - if (hdrlen & 3) { - padsize = hdrlen % 4; - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && - !(status->flags & ATH_RX_DECRYPT_ERROR)) { - rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) - && !(status->flags & ATH_RX_DECRYPT_ERROR) - && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, sc->sc_keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; - } - - __ieee80211_rx(hw, skb, &rx_status); - - return 0; -} - /********************************/ /* LED functions */ /********************************/ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 2d72ac1..000e189 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -14,10 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Implementation of receive path. - */ - #include "core.h" /* @@ -27,10 +23,7 @@ * MAC acknowledges BA status as long as it copies frames to host * buffer (or rx fifo). This can incorrectly acknowledge packets * to a sender if last desc is self-linked. - * - * NOTE: Caller should hold the rxbuf lock. */ - static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; @@ -40,19 +33,17 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ATH_RXBUF_RESET(bf); ds = bf->bf_desc; - ds->ds_link = 0; /* link to null */ + ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; - /* XXX For RADAR? - * virtual addr of the beginning of the buffer. */ + /* virtual addr of the beginning of the buffer. */ skb = bf->bf_mpdu; ASSERT(skb != NULL); ds->ds_vdata = skb->data; /* setup rx descriptors */ - ath9k_hw_setuprxdesc(ah, - ds, - skb_tailroom(skb), /* buffer size */ + ath9k_hw_setuprxdesc(ah, ds, + skb_tailroom(skb), /* buffer size */ 0); if (sc->sc_rxlink == NULL) @@ -64,8 +55,7 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ath9k_hw_rxena(ah); } -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, - u32 len) +static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { struct sk_buff *skb; u32 off; @@ -91,59 +81,154 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, return skb; } -static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb) +static void ath_rx_requeue(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; + struct sk_buff *skb; ASSERT(bf != NULL); - spin_lock_bh(&sc->sc_rxbuflock); - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - /* - * This buffer is still held for hw acess. - * Mark it as free to be re-queued it later. - */ - bf->bf_status |= ATH_BUFSTATUS_FREE; - } else { - /* XXX: we probably never enter here, remove after - * verification */ - list_add_tail(&bf->list, &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf); + if (bf->bf_mpdu == NULL) { + skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); + if (skb != NULL) { + bf->bf_mpdu = skb; + 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; + + } } - spin_unlock_bh(&sc->sc_rxbuflock); + + list_move_tail(&bf->list, &sc->sc_rxbuf); + ath_rx_buf_link(sc, bf); +} + + +static int ath_rate2idx(struct ath_softc *sc, int rate) +{ + int i = 0, cur_band, n_rates; + struct ieee80211_hw *hw = sc->hw; + + cur_band = hw->conf.channel->band; + n_rates = sc->sbands[cur_band].n_bitrates; + + for (i = 0; i < n_rates; i++) { + if (sc->sbands[cur_band].bitrates[i].bitrate == rate) + break; + } + + /* + * NB:mac80211 validates rx rate index against the supported legacy rate + * index only (should be done against ht rates also), return the highest + * legacy rate index for rx rate which does not match any one of the + * supported basic and extended rates to make mac80211 happy. + * The following hack will be cleaned up once the issue with + * the rx rate index validation in mac80211 is fixed. + */ + if (i == n_rates) + return n_rates - 1; + + return i; } /* - * The skb indicated to upper stack won't be returned to us. - * So we have to allocate a new one and queue it by ourselves. + * For Decrypt or Demic errors, we only mark packet status here and always push + * up the frame up to let mac80211 handle the actual error case, be it no + * decryption key or real decryption error. This let us keep statistics there. */ -static int ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) +static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, + struct ieee80211_rx_status *rx_status, bool *decrypt_error, + struct ath_softc *sc) { - struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; - struct sk_buff *nskb; - int type; - - /* indicate frame to the stack, which will free the old skb. */ - 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); - if (nskb != NULL) { - bf->bf_mpdu = nskb; - 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; + struct ieee80211_hdr *hdr; + int ratekbps; + u8 ratecode; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + if (ds->ds_rxstat.rs_more) { + /* + * Frame spans multiple descriptors; this cannot happen yet + * as we don't support jumbograms. If not in monitor mode, + * discard the frame. Enable this if you want to see + * error frames in Monitor mode. + */ + if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) + goto rx_next; + } else if (ds->ds_rxstat.rs_status != 0) { + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) + goto rx_next; - /* queue the new wbuf to H/W */ - ath_rx_requeue(sc, nskb); + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { + *decrypt_error = true; + } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { + if (ieee80211_is_ctl(fc)) + /* + * Sometimes, we get invalid + * MIC failures on valid control frames. + * Remove these mic errors. + */ + ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; + else + rx_status->flag |= RX_FLAG_MMIC_ERROR; + } + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_CRC)) + goto rx_next; + } else { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { + goto rx_next; + } + } } - return type; + ratecode = ds->ds_rxstat.rs_rate; + ratekbps = sc->sc_hwmap[ratecode].rateKbps; + + /* HT rate */ + if (ratecode & 0x80) { + if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) + ratekbps = (ratekbps * 27) / 13; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) + ratekbps = (ratekbps * 10) / 9; + } + + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); + rx_status->band = sc->hw->conf.channel->band; + rx_status->freq = sc->hw->conf.channel->center_freq; + rx_status->noise = sc->sc_ani.sc_noise_floor; + rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->rate_idx = ath_rate2idx(sc, (ratekbps / 100)); + rx_status->antenna = ds->ds_rxstat.rs_antenna; + + /* at 45 you will be able to use MCS 15 reliably. A more elaborate + * scheme can be used here but it requires tables of SNR/throughput for + * each possible mode used. */ + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + + /* rssi can be more than 45 though, anything above that + * should be considered at 100% */ + if (rx_status->qual > 100) + rx_status->qual = 100; + + rx_status->flag |= RX_FLAG_TSFT; + + return 1; +rx_next: + return 0; } static void ath_opmode_init(struct ath_softc *sc) @@ -185,12 +270,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->sc_rxbuflock); - /* - * Cisco's VPN software requires that drivers be able to - * receive encapsulated frames that are larger than the MTU. - * Since we can't be sure how large a frame we'll get, setup - * to handle the larges on possible. - */ sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN, min(sc->sc_cachelsz, (u16)64)); @@ -209,8 +288,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) break; } - /* Pre-allocate a wbuf for each rx buffer */ - list_for_each_entry(bf, &sc->sc_rxbuf, list) { skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); if (skb == NULL) { @@ -223,7 +300,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) 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; @@ -235,8 +311,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) return error; } -/* Reclaim all rx queue resources */ - void ath_rx_cleanup(struct ath_softc *sc) { struct sk_buff *skb; @@ -248,8 +322,6 @@ void ath_rx_cleanup(struct ath_softc *sc) dev_kfree_skb(skb); } - /* cleanup rx descriptors */ - if (sc->sc_rxdma.dd_desc_len != 0) ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); } @@ -297,20 +369,19 @@ u32 ath_calcrxfilter(struct ath_softc *sc) } if (sc->sc_ah->ah_opmode == ATH9K_M_STA || - sc->sc_ah->ah_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_ah->ah_opmode == ATH9K_M_HOSTAP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); + return rfilt; #undef RX_FILTER_PRESERVE } -/* Enable the receive h/w following a reset. */ - int ath_startrecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; @@ -322,21 +393,6 @@ int ath_startrecv(struct ath_softc *sc) sc->sc_rxlink = NULL; list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) { - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - /* restarting h/w, no need for holding descriptors */ - bf->bf_status &= ~ATH_BUFSTATUS_STALE; - /* - * Upper layer may not be done with the frame yet so - * we can't just re-queue it to hardware. Remove it - * from h/w queue. It'll be re-queued when upper layer - * returns the frame and ath_rx_requeue_mpdu is called. - */ - if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) { - list_del(&bf->list); - continue; - } - } - /* chain descriptors */ ath_rx_buf_link(sc, bf); } @@ -346,120 +402,69 @@ int ath_startrecv(struct ath_softc *sc) bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); ath9k_hw_putrxbuf(ah, bf->bf_daddr); - ath9k_hw_rxena(ah); /* enable recv descriptors */ + ath9k_hw_rxena(ah); start_recv: spin_unlock_bh(&sc->sc_rxbuflock); - ath_opmode_init(sc); /* set filters, etc. */ - ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */ + ath_opmode_init(sc); + ath9k_hw_startpcureceive(ah); + return 0; } -/* Disable the receive h/w in preparation for a reset. */ - bool ath_stoprecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; - u64 tsf; bool stopped; - ath9k_hw_stoppcurecv(ah); /* disable PCU */ - ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */ - stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */ - mdelay(3); /* 3ms is long enough for 1 frame */ - tsf = ath9k_hw_gettsf64(ah); - sc->sc_rxlink = NULL; /* just in case */ + ath9k_hw_stoppcurecv(ah); + ath9k_hw_setrxfilter(ah, 0); + stopped = ath9k_hw_stopdmarecv(ah); + mdelay(3); /* 3ms is long enough for 1 frame */ + sc->sc_rxlink = NULL; + return stopped; } -/* Flush receive queue */ - void ath_flushrecv(struct ath_softc *sc) { - /* - * ath_rx_tasklet may be used to handle rx interrupt and flush receive - * queue at the same time. Use a lock to serialize the access of rx - * queue. - * ath_rx_tasklet cannot hold the spinlock while indicating packets. - * Instead, do not claim the spinlock but check for a flush in - * progress (see references to sc_rxflush) - */ spin_lock_bh(&sc->sc_rxflushlock); sc->sc_flags |= SC_OP_RXFLUSH; - ath_rx_tasklet(sc, 1); - sc->sc_flags &= ~SC_OP_RXFLUSH; spin_unlock_bh(&sc->sc_rxflushlock); } -/* Process receive queue, as well as LED, etc. */ - int ath_rx_tasklet(struct ath_softc *sc, int flush) { #define PA2DESC(_sc, _pa) \ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) - struct ath_buf *bf, *bf_held = NULL; + struct ath_buf *bf; struct ath_desc *ds; - struct ieee80211_hdr *hdr; struct sk_buff *skb = NULL; - struct ath_recv_status rx_status; + struct ieee80211_rx_status rx_status; struct ath_hal *ah = sc->sc_ah; - int type, rx_processed = 0; - u32 phyerr; - u8 chainreset = 0; - int retval; - __le16 fc; + struct ieee80211_hdr *hdr; + int hdrlen, padsize, retval; + bool decrypt_error = false; + u8 keyix; + + spin_lock_bh(&sc->sc_rxbuflock); do { /* If handling rx interrupt and flush is in progress => exit */ if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; - spin_lock_bh(&sc->sc_rxbuflock); if (list_empty(&sc->sc_rxbuf)) { sc->sc_rxlink = NULL; - spin_unlock_bh(&sc->sc_rxbuflock); break; } bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); - - /* - * There is a race condition that BH gets scheduled after sw - * writes RxE and before hw re-load the last descriptor to get - * the newly chained one. Software must keep the last DONE - * descriptor as a holding descriptor - software does so by - * marking it with the STALE flag. - */ - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - bf_held = bf; - if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) { - /* - * The holding descriptor is the last - * descriptor in queue. It's safe to - * remove the last holding descriptor - * in BH context. - */ - list_del(&bf_held->list); - bf_held->bf_status &= ~ATH_BUFSTATUS_STALE; - sc->sc_rxlink = NULL; - - if (bf_held->bf_status & ATH_BUFSTATUS_FREE) { - list_add_tail(&bf_held->list, - &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf_held); - } - spin_unlock_bh(&sc->sc_rxbuflock); - break; - } - bf = list_entry(bf->list.next, struct ath_buf, list); - } - ds = bf->bf_desc; - ++rx_processed; /* * Must provide the virtual address of the current @@ -472,8 +477,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ - retval = ath9k_hw_rxprocdesc(ah, - ds, + retval = ath9k_hw_rxprocdesc(ah, ds, bf->bf_daddr, PA2DESC(sc, ds->ds_link), 0); @@ -482,7 +486,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_desc *tds; if (list_is_last(&bf->list, &sc->sc_rxbuf)) { - spin_unlock_bh(&sc->sc_rxbuflock); + sc->sc_rxlink = NULL; break; } @@ -500,215 +504,70 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ tds = tbf->bf_desc; - retval = ath9k_hw_rxprocdesc(ah, - tds, tbf->bf_daddr, - PA2DESC(sc, tds->ds_link), 0); + retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, + PA2DESC(sc, tds->ds_link), 0); if (retval == -EINPROGRESS) { - spin_unlock_bh(&sc->sc_rxbuflock); break; } } - /* XXX: we do not support frames spanning - * multiple descriptors */ - bf->bf_status |= ATH_BUFSTATUS_DONE; - skb = bf->bf_mpdu; - if (skb == NULL) { /* XXX ??? can this happen */ - spin_unlock_bh(&sc->sc_rxbuflock); + if (!skb) continue; - } - /* - * Now we know it's a completed frame, we can indicate the - * frame. Remove the previous holding descriptor and leave - * this one in the queue as the new holding descriptor. - */ - if (bf_held) { - list_del(&bf_held->list); - bf_held->bf_status &= ~ATH_BUFSTATUS_STALE; - if (bf_held->bf_status & ATH_BUFSTATUS_FREE) { - list_add_tail(&bf_held->list, &sc->sc_rxbuf); - /* try to requeue this descriptor */ - ath_rx_buf_link(sc, bf_held); - } - } - bf->bf_status |= ATH_BUFSTATUS_STALE; - bf_held = bf; /* - * Release the lock here in case ieee80211_input() return - * the frame immediately by calling ath_rx_mpdu_requeue(). + * If we're asked to flush receive queue, directly + * chain it back at the queue without processing it. */ - spin_unlock_bh(&sc->sc_rxbuflock); - - if (flush) { - /* - * If we're asked to flush receive queue, directly - * chain it back at the queue without processing it. - */ + if (flush) goto rx_next; - } - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - memset(&rx_status, 0, sizeof(struct ath_recv_status)); - - if (ds->ds_rxstat.rs_more) { - /* - * Frame spans multiple descriptors; this - * cannot happen yet as we don't support - * jumbograms. If not in monitor mode, - * discard the frame. - */ -#ifndef ERROR_FRAMES - /* - * Enable this if you want to see - * error frames in Monitor mode. - */ - if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) - goto rx_next; -#endif - /* fall thru for monitor mode handling... */ - } else if (ds->ds_rxstat.rs_status != 0) { - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) - rx_status.flags |= ATH_RX_FCS_ERROR; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { - phyerr = ds->ds_rxstat.rs_phyerr & 0x1f; - goto rx_next; - } + if (!ds->ds_rxstat.rs_datalen) + goto rx_next; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { - /* - * Decrypt error. We only mark packet status - * here and always push up the frame up to let - * mac80211 handle the actual error case, be - * it no decryption key or real decryption - * error. This let us keep statistics there. - */ - rx_status.flags |= ATH_RX_DECRYPT_ERROR; - } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { - /* - * Demic error. We only mark frame status here - * and always push up the frame up to let - * mac80211 handle the actual error case. This - * let us keep statistics there. Hardware may - * post a false-positive MIC error. - */ - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - ds->ds_rxstat.rs_status &= - ~ATH9K_RXERR_MIC; - else - rx_status.flags |= ATH_RX_MIC_ERROR; - } - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } - /* - * The status portion of the descriptor could get corrupted. - */ + /* The status portion of the descriptor could get corrupted. */ if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen) goto rx_next; - /* - * Sync and unmap the frame. At this point we're - * committed to passing the sk_buff somewhere so - * clear buf_skb; this means a new sk_buff must be - * allocated when the rx descriptor is setup again - * to receive another frame. - */ - skb_put(skb, ds->ds_rxstat.rs_datalen); - skb->protocol = cpu_to_be16(ETH_P_CONTROL); - rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); - rx_status.rateieee = - sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate; - rx_status.rateKbps = - sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps; - rx_status.ratecode = ds->ds_rxstat.rs_rate; - - /* HT rate */ - if (rx_status.ratecode & 0x80) { - /* TODO - add table to avoid division */ - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { - rx_status.flags |= ATH_RX_40MHZ; - rx_status.rateKbps = - (rx_status.rateKbps * 27) / 13; - } - if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) - rx_status.rateKbps = - (rx_status.rateKbps * 10) / 9; - else - rx_status.flags |= ATH_RX_SHORT_GI; - } - /* sc_noise_floor is only available when the station - attaches to an AP, so we use a default value - if we are not yet attached. */ - rx_status.abs_rssi = - ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor; + if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) + goto rx_next; - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, + /* Sync and unmap the frame */ + pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, skb_tailroom(skb), PCI_DMA_FROMDEVICE); - pci_unmap_single(sc->pdev, - bf->bf_buf_addr, + pci_unmap_single(sc->pdev, bf->bf_buf_addr, sc->sc_rxbufsize, PCI_DMA_FROMDEVICE); - /* XXX: Ah! make me more readable, use a helper */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - if (ds->ds_rxstat.rs_moreaggr == 0) { - rx_status.rssictl[0] = - ds->ds_rxstat.rs_rssi_ctl0; - rx_status.rssictl[1] = - ds->ds_rxstat.rs_rssi_ctl1; - rx_status.rssictl[2] = - ds->ds_rxstat.rs_rssi_ctl2; - rx_status.rssi = ds->ds_rxstat.rs_rssi; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { - rx_status.rssiextn[0] = - ds->ds_rxstat.rs_rssi_ext0; - rx_status.rssiextn[1] = - ds->ds_rxstat.rs_rssi_ext1; - rx_status.rssiextn[2] = - ds->ds_rxstat.rs_rssi_ext2; - rx_status.flags |= - ATH_RX_RSSI_EXTN_VALID; - } - rx_status.flags |= ATH_RX_RSSI_VALID | - ATH_RX_CHAIN_RSSI_VALID; - } - } else { - /* - * Need to insert the "combined" rssi into the - * status structure for upper layer processing - */ - rx_status.rssi = ds->ds_rxstat.rs_rssi; - rx_status.flags |= ATH_RX_RSSI_VALID; + skb_put(skb, ds->ds_rxstat.rs_datalen); + skb->protocol = cpu_to_be16(ETH_P_CONTROL); + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *)skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + if (hdrlen & 3) { + padsize = hdrlen % 4; + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } - /* Pass frames up to the stack. */ + keyix = ds->ds_rxstat.rs_keyix; - type = ath_rx_indicate(sc, skb, - &rx_status, ds->ds_rxstat.rs_keyix); + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + rx_status.flag |= RX_FLAG_DECRYPTED; + } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, sc->sc_keymap)) + rx_status.flag |= RX_FLAG_DECRYPTED; + } + + /* Send the frame to mac80211 */ + __ieee80211_rx(sc->hw, skb, &rx_status); + bf->bf_mpdu = NULL; /* * change the default rx antenna if rx diversity chooses the @@ -716,37 +575,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ if (sc->sc_defant != ds->ds_rxstat.rs_antenna) { if (++sc->sc_rxotherant >= 3) - ath_setdefantenna(sc, - ds->ds_rxstat.rs_antenna); + ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); } else { sc->sc_rxotherant = 0; } - -#ifdef CONFIG_SLOW_ANT_DIV - if ((rx_status.flags & ATH_RX_RSSI_VALID) && - ieee80211_is_beacon(fc)) { - ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat); - } -#endif - /* - * For frames successfully indicated, the buffer will be - * returned to us by upper layers by calling - * ath_rx_mpdu_requeue, either synchronusly or asynchronously. - * So we don't want to do it here in this loop. - */ - continue; - rx_next: - bf->bf_status |= ATH_BUFSTATUS_FREE; - } while (TRUE); - - if (chainreset) { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Reset rx chain mask. " - "Do internal reset\n", __func__); - ASSERT(flush == 0); - ath_reset(sc, false); - } + ath_rx_requeue(sc, bf); + } while (1); + + spin_unlock_bh(&sc->sc_rxbuflock); return 0; #undef PA2DESC -- cgit v1.1 From ffd651c620a2f27502ee5d4517a122c072f13073 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:06:18 +0530 Subject: ath9k: We don't support non-HT devices, so remove superfluous code. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 39 --------------------------------------- 1 file changed, 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 8937728..44735b6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -14,10 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Implementation of transmit path. - */ - #include "core.h" #define BITS_PER_BYTE 8 @@ -699,41 +695,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) } /* - * For non-HT devices, calculate RTS/CTS duration in software - * and disable multi-rate retry. - */ - if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) { - /* - * Compute the transmit duration based on the frame - * size and the size of an ACK frame. We call into the - * HAL to do the computation since it depends on the - * characteristics of the actual PHY being used. - * - * NB: CTS is assumed the same size as an ACK so we can - * use the precalculated ACK durations. - */ - if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */ - ctsduration += bf_isshpreamble(bf) ? - rt->info[cix].spAckDuration : - rt->info[cix].lpAckDuration; - } - - ctsduration += series[0].PktDuration; - - if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */ - ctsduration += bf_isshpreamble(bf) ? - rt->info[rix].spAckDuration : - rt->info[rix].lpAckDuration; - } - - /* - * Disable multi-rate retry when using RTS/CTS by clearing - * series 1, 2 and 3. - */ - memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3); - } - - /* * set dur_update_en for l-sig computation except for PS-Poll frames */ ath9k_hw_set11n_ratescenario(ah, ds, lastds, -- cgit v1.1 From 5ddfac3b550250388f1222ec7d09069784a68af6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:06:44 +0530 Subject: ath9k: Remove rate control reference in VAP Rate control init is now confined to itself, using the HT capabilites of the STA from rate_init(). Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 47 +++++++++++----------- drivers/net/wireless/ath9k/main.c | 4 -- drivers/net/wireless/ath9k/rc.c | 82 +++++++++++++-------------------------- drivers/net/wireless/ath9k/rc.h | 2 - 4 files changed, 50 insertions(+), 85 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 5500ef4..2ff33b8 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -540,6 +540,29 @@ void ath_newassoc(struct ath_softc *sc, void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta); void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta); +/********/ +/* VAPs */ +/********/ + +/* + * Define the scheme that we select MAC address for multiple + * BSS on the same radio. The very first VAP will just use the MAC + * address from the EEPROM. For the next 3 VAPs, we set the + * U/L bit (bit 1) in MAC address, and use the next two bits as the + * index of the VAP. + */ + +#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ + ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) + +/* driver-specific vap state */ +struct ath_vap { + int av_bslot; /* beacon slot index */ + enum ath9k_opmode av_opmode; /* VAP operational mode */ + struct ath_buf *av_bcbuf; /* beacon buffer */ + struct ath_tx_control av_btxctl; /* txctl information for beacon */ +}; + /*******************/ /* Beacon Handling */ /*******************/ @@ -579,30 +602,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); -/********/ -/* VAPs */ -/********/ - -/* - * Define the scheme that we select MAC address for multiple - * BSS on the same radio. The very first VAP will just use the MAC - * address from the EEPROM. For the next 3 VAPs, we set the - * U/L bit (bit 1) in MAC address, and use the next two bits as the - * index of the VAP. - */ - -#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ - ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) - -/* driver-specific vap state */ -struct ath_vap { - int av_bslot; /* beacon slot index */ - enum ath9k_opmode av_opmode; /* VAP operational mode */ - struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_tx_control av_btxctl; /* txctl information for beacon */ - struct ath_rate_node *rc_node; -}; - /*********************/ /* Antenna diversity */ /*********************/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index c9ac5e8..7b84382 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -316,10 +316,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", __func__); - - /* Update ratectrl about the new state */ - ath_rc_node_update(hw, avp->rc_node); - /* Start ANI */ mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 8a45b25..0fa1b30 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1446,35 +1446,39 @@ static void ath_rate_tx_complete(struct ath_softc *sc, info_priv->tx.ts_longretry); } -/* - * Update the SIB's rate control information - * - * This should be called when the supported rates change - * (e.g. SME operation, wireless mode change) - * - * It will determine which rates are valid for use. - */ -static void ath_rc_sib_update(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - u32 capflag, int keep_state, - struct ath_rateset *negotiated_rates, - struct ath_rateset *negotiated_htrates) +static void ath_rc_init(struct ath_softc *sc, + struct ath_rate_node *ath_rc_priv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) { struct ath_rate_table *rate_table = NULL; 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_rateset *rateset = &ath_rc_priv->neg_rates; + u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; rate_table = (struct ath_rate_table *) asc->hw_rate_table[sc->sc_curmode]; + if (sta->ht_cap.ht_supported) { + if (sband->band == IEEE80211_BAND_2GHZ) + rate_table = (struct ath_rate_table *) + asc->hw_rate_table[ATH9K_MODE_11NG_HT20]; + else + rate_table = (struct ath_rate_table *) + asc->hw_rate_table[ATH9K_MODE_11NA_HT20]; + + ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; + } + /* Initial rate table size. Will change depending * on the working rate set */ ath_rc_priv->rate_table_size = MAX_TX_RATE_TBL; /* Initialize thresholds according to the global rate table */ - for (i = 0 ; (i < ath_rc_priv->rate_table_size) && (!keep_state); i++) { + for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { ath_rc_priv->state[i].rssi_thres = rate_table->info[i].rssi_ack_validmin; ath_rc_priv->state[i].per = 0; @@ -1488,24 +1492,24 @@ static void ath_rc_sib_update(struct ath_softc *sc, ath_rc_priv->valid_phy_rateidx[i][j] = 0; ath_rc_priv->valid_phy_ratecnt[i] = 0; } - ath_rc_priv->rc_phy_mode = (capflag & WLAN_RC_40_FLAG); + ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); /* Set stream capability */ - ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1; + ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table, - capflag); + ath_rc_priv->ht_cap); } else { /* Use intersection of working rates and valid rates */ hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table, - rateset, capflag); - if (capflag & WLAN_RC_HT_FLAG) { + rateset, ath_rc_priv->ht_cap); + if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv, rate_table, ht_mcs, - capflag); + ath_rc_priv->ht_cap); } hi = A_MAX(hi, hthi); } @@ -1539,29 +1543,6 @@ static void ath_rc_sib_update(struct ath_softc *sc, ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; } -void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) -{ - struct ath_softc *sc = hw->priv; - u32 capflag = 0; - - if (hw->conf.ht.enabled) { - capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; - if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) - capflag |= ATH_RC_CW40_FLAG; - } - - rc_priv->ht_cap = - ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) | - ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) | - ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) | - ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0); - - - ath_rc_sib_update(sc, rc_priv, rc_priv->ht_cap, 0, - &rc_priv->neg_rates, - &rc_priv->neg_ht_rates); -} - /* Rate Control callbacks */ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, @@ -1684,7 +1665,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, ath_rc_priv->neg_ht_rates.rs_nrates = j; } - ath_rc_node_update(sc->hw, priv_sta); + ath_rc_init(sc, priv_sta, sband, sta); } static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) @@ -1699,16 +1680,9 @@ static void ath_rate_free(void *priv) static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { - struct ieee80211_vif *vif; struct ath_softc *sc = priv; - struct ath_vap *avp; struct ath_rate_node *rate_priv; - vif = sc->sc_vaps[0]; - ASSERT(vif); - - avp = (void *)vif->drv_priv; - rate_priv = kzalloc(sizeof(struct ath_rate_node), gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, @@ -1717,9 +1691,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp return NULL; } - rate_priv->avp = avp; rate_priv->asc = sc->sc_rc; - avp->rc_node = rate_priv; rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); return rate_priv; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 8d0650a..07319c6 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -265,7 +265,6 @@ struct ath_rate_node { struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; - struct ath_vap *avp; }; /* Driver data of ieee80211_tx_info */ @@ -279,7 +278,6 @@ struct ath_tx_info_priv { struct ath_rate_softc *ath_rate_attach(struct ath_softc *sch); void ath_rate_detach(struct ath_rate_softc *asc); -void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv); u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); void ath_rate_control_unregister(void); -- cgit v1.1 From fe7f4a77450c1d0e463a9b1456b40c2305433e41 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:07:06 +0530 Subject: ath9k: Remove ath_rate_softc Move the hw rate tables to ath_softc, and access them directly. tx_triglevel_max is global, move it to ath_rate_node. Now that ath_rate_softc is gone, rate control attach becomes simpler. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 6 +-- drivers/net/wireless/ath9k/core.h | 2 +- drivers/net/wireless/ath9k/main.c | 1 - drivers/net/wireless/ath9k/rc.c | 110 ++++++++++++++------------------------ drivers/net/wireless/ath9k/rc.h | 13 +---- 5 files changed, 45 insertions(+), 87 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index ea332a2..6c872e7 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1071,11 +1071,7 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - sc->sc_rc = ath_rate_attach(sc); - if (sc->sc_rc == NULL) { - error = -EIO; - goto bad2; - } + ath_rate_attach(sc); if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_TKIP, NULL)) { diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 2ff33b8..cf2d941 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -784,7 +784,6 @@ struct ath_softc { struct tasklet_struct bcon_tasklet; struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; void __iomem *mem; u8 sc_curbssid[ETH_ALEN]; @@ -859,6 +858,7 @@ struct ath_softc { /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; + struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; const struct ath9k_rate_table *sc_currates; u8 sc_protrix; /* protection rate index */ struct { diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7b84382..ca78098 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -737,7 +737,6 @@ static void ath_detach(struct ath_softc *sc) ieee80211_unregister_hw(hw); ath_rate_control_unregister(); - ath_rate_detach(sc->sc_rc); ath_rx_cleanup(sc); ath_tx_cleanup(sc); diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 0fa1b30..59c146c 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -23,8 +23,6 @@ /* FIXME: remove this include! */ #include "../net/mac80211/rate.h" -static u32 tx_triglevel_max; - static struct ath_rate_table ar5416_11na_ratetable = { 42, { @@ -436,7 +434,7 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } } -static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, +static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, struct ath_rate_node *ath_rc_priv) { u8 i, j, idx, idx_next; @@ -481,7 +479,7 @@ static inline int ath_rc_isvalid_txmask(struct ath_rate_node *ath_rc_priv, /* Iterators for valid_txrate_mask */ static inline int -ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, +ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, struct ath_rate_node *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) @@ -519,7 +517,7 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) } static inline int -ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, +ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, struct ath_rate_node *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { @@ -539,7 +537,7 @@ ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, */ static u8 ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_table *rate_table, u32 capflag) { u8 i, hi = 0; @@ -572,7 +570,7 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, */ static u8 ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_table *rate_table, struct ath_rateset *rateset, u32 capflag) { @@ -620,7 +618,7 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, static u8 ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_table *rate_table, u8 *mcs_set, u32 capflag) { u8 i, j, hi = 0; @@ -653,50 +651,13 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, return hi; } -struct ath_rate_softc *ath_rate_attach(struct ath_softc *sc) -{ - struct ath_rate_softc *asc; - - asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL); - if (asc == NULL) - return NULL; - - asc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable; - asc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - asc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable; - - asc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable; - asc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable; - - asc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = - &ar5416_11na_ratetable; - asc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = - &ar5416_11na_ratetable; - asc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = - &ar5416_11ng_ratetable; - asc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = - &ar5416_11ng_ratetable; - - /* Save Maximum TX Trigger Level (used for 11n) */ - tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max; - - return asc; -} - -void ath_rate_detach(struct ath_rate_softc *asc) -{ - if (asc != NULL) - kfree(asc); -} - u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11rate) { - const struct ath_rate_table *ratetable; - struct ath_rate_softc *rsc = sc->sc_rc; + struct ath_rate_table *ratetable; int i; - ratetable = rsc->hw_rate_table[sc->sc_curmode]; + ratetable = sc->hw_rate_table[sc->sc_curmode]; if (WARN_ON(!ratetable)) return 0; @@ -711,7 +672,7 @@ u8 ath_rate_findrateix(struct ath_softc *sc, static u8 ath_rc_ratefind_ht(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_table *rate_table, int probe_allowed, int *is_probing, int is_retry) { @@ -843,7 +804,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, return rate; } -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table , +static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , struct ath_rc_series *series, u8 tries, u8 rix, @@ -864,7 +825,7 @@ 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, + struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) { @@ -898,11 +859,9 @@ static void ath_rc_ratefind(struct ath_softc *sc, int is_retry) { u8 try_per_rate = 0, i = 0, rix, nrix; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table; - rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; + rate_table = sc->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); @@ -1003,10 +962,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_table *rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; - + struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; static u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, 100 * 1 / 4, @@ -1330,15 +1286,13 @@ 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_table *rate_table; struct ath_rc_series rcs[4]; u8 flags; u32 series = 0, rix; memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0])); - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; + rate_table = sc->hw_rate_table[sc->sc_curmode]; ASSERT(rcs[0].tries != 0); /* @@ -1432,7 +1386,7 @@ static void ath_rate_tx_complete(struct ath_softc *sc, */ if (info_priv->tx.ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) { + ((sc->sc_ah->ah_txTrigLevel) >= rc_priv->tx_triglevel_max)) { tx_status = 1; is_underrun = 1; } @@ -1452,21 +1406,17 @@ static void ath_rc_init(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_rate_table *rate_table = NULL; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rateset *rateset = &ath_rc_priv->neg_rates; u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; + rate_table = sc->hw_rate_table[sc->sc_curmode]; if (sta->ht_cap.ht_supported) { if (sband->band == IEEE80211_BAND_2GHZ) - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[ATH9K_MODE_11NG_HT20]; + rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20]; else - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[ATH9K_MODE_11NA_HT20]; + rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) @@ -1691,8 +1641,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp return NULL; } - rate_priv->asc = sc->sc_rc; rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); + rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max; return rate_priv; } @@ -1717,6 +1667,28 @@ static struct rate_control_ops ath_rate_ops = { .free_sta = ath_rate_free_sta, }; +void ath_rate_attach(struct ath_softc *sc) +{ + sc->hw_rate_table[ATH9K_MODE_11B] = + &ar5416_11b_ratetable; + sc->hw_rate_table[ATH9K_MODE_11A] = + &ar5416_11a_ratetable; + sc->hw_rate_table[ATH9K_MODE_11G] = + &ar5416_11g_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = + &ar5416_11ng_ratetable; +} + int ath_rate_control_register(void) { return ieee80211_rate_control_register(&ath_rate_ops); diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 07319c6..30248de 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -199,15 +199,6 @@ struct ath_rateset { u8 rs_rates[ATH_RATE_MAX]; }; -/* per-device state */ -struct ath_rate_softc { - /* phy tables that contain rate control data */ - const void *hw_rate_table[ATH9K_MODE_MAX]; - - /* -1 or index of fixed rate */ - int fixedrix; -}; - /** * struct ath_rate_node - Rate Control priv data * @state: RC state @@ -261,6 +252,7 @@ struct ath_rate_node { u32 per_down_time; u32 probe_interval; u32 prev_data_rix; + u32 tx_triglevel_max; struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; @@ -276,8 +268,7 @@ struct ath_tx_info_priv { u8 min_rate; }; -struct ath_rate_softc *ath_rate_attach(struct ath_softc *sch); -void ath_rate_detach(struct ath_rate_softc *asc); +void ath_rate_attach(struct ath_softc *sc); u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); void ath_rate_control_unregister(void); -- cgit v1.1 From a8efee4f4740c61fccaf73608df282c4ee24ae86 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:07:30 +0530 Subject: ath9k: Use rate_driver_data Remove the hack using vif, and use rate_driver_data within skb->cb to hold driver specific rate information. Setup the rate series in the skb's tx control area and remove all references to ath9k specific rate series ( using struct ath_rc_series ). Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 - drivers/net/wireless/ath9k/main.c | 9 +-- drivers/net/wireless/ath9k/rc.c | 145 ++++++++++++++-------------------- drivers/net/wireless/ath9k/rc.h | 17 ---- drivers/net/wireless/ath9k/xmit.c | 162 ++++++++++---------------------------- 5 files changed, 108 insertions(+), 226 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index cf2d941..255f860 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -203,7 +203,6 @@ struct ath_buf_state { 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 */ u32 bf_type; /* BUF_* (enum buffer_type) */ /* key type use to encrypt this frame */ u32 bfs_keyix; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index ca78098..11d7bee 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -350,13 +350,12 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, DPRINTF(sc, ATH_DBG_XMIT, "%s: TX complete: skb: %p\n", __func__, skb); - ieee80211_tx_info_clear_status(tx_info); if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info, XXX: HACK! */ - if (tx_info->control.vif != NULL) - kfree(tx_info->control.vif); - tx_info->control.vif = NULL; + if (tx_info->rate_driver_data[0] != NULL) { + kfree(tx_info->rate_driver_data[0]); + tx_info->rate_driver_data[0] = NULL; + } } if (tx_status->flags & ATH_TX_BAR) { diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 59c146c..156b245 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -805,22 +805,22 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, } static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , - struct ath_rc_series *series, + struct ieee80211_tx_rate *rate, u8 tries, u8 rix, int rtsctsenable) { - series->tries = tries; - series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) | - (WLAN_RC_PHY_DS(rate_table->info[rix].phy) ? - ATH_RC_DS_FLAG : 0) | - (WLAN_RC_PHY_40(rate_table->info[rix].phy) ? - ATH_RC_CW40_FLAG : 0) | - (WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ? - ATH_RC_SGI_FLAG : 0); - - series->rix = rate_table->info[rix].base_index; - series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen; + rate->count = tries; + rate->idx = rix; + + if (rtsctsenable) + rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_MCS; } static u8 ath_rc_rate_getidx(struct ath_softc *sc, @@ -855,11 +855,12 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, static void ath_rc_ratefind(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, + struct ieee80211_tx_info *tx_info, int *is_probe, int is_retry) { u8 try_per_rate = 0, i = 0, rix, nrix; struct ath_rate_table *rate_table; + struct ieee80211_tx_rate *rates = tx_info->control.rates; rate_table = sc->hw_rate_table[sc->sc_curmode]; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, @@ -871,7 +872,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* set one try for probe rates. For the * probes don't enable rts */ ath_rc_rate_set_series(rate_table, - &series[i++], 1, nrix, FALSE); + &rates[i++], 1, nrix, FALSE); try_per_rate = (num_tries/num_rates); /* Get the next tried/allowed rate. No RTS for the next series @@ -880,12 +881,12 @@ static void ath_rc_ratefind(struct ath_softc *sc, nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, FALSE); ath_rc_rate_set_series(rate_table, - &series[i++], try_per_rate, nrix, 0); + &rates[i++], try_per_rate, nrix, 0); } else { try_per_rate = (num_tries/num_rates); /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, - &series[i++], try_per_rate, nrix, FALSE); + &rates[i++], try_per_rate, nrix, FALSE); } /* Fill in the other rates for multirate retry */ @@ -902,7 +903,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, 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); + &rates[i], try_num, nrix, TRUE); } /* @@ -928,9 +929,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, if (i == 4 && ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_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; + rates[3].idx = rates[2].idx; + rates[3].flags = rates[2].flags; } } } @@ -943,7 +943,7 @@ static void ath_rate_findrate(struct ath_softc *sc, int num_tries, int num_rates, unsigned int rcflag, - struct ath_rc_series series[], + struct ieee80211_tx_info *tx_info, int *is_probe, int is_retry) { @@ -951,7 +951,7 @@ static void ath_rate_findrate(struct ath_softc *sc, return; ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates, - rcflag, series, is_probe, is_retry); + rcflag, tx_info, is_probe, is_retry); } static void ath_rc_update_ht(struct ath_softc *sc, @@ -1283,17 +1283,17 @@ static void ath_rc_update_ht(struct ath_softc *sc, */ static void ath_rc_update(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *info_priv, int final_ts_idx, + struct ieee80211_tx_info *tx_info, int final_ts_idx, int xretries, int long_retry) { + struct ath_tx_info_priv *info_priv = + (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; struct ath_rate_table *rate_table; - struct ath_rc_series rcs[4]; + struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; u32 series = 0, rix; - memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0])); rate_table = sc->hw_rate_table[sc->sc_curmode]; - ASSERT(rcs[0].tries != 0); /* * If the first rate is not the final index, there @@ -1302,31 +1302,31 @@ static void ath_rc_update(struct ath_softc *sc, if (final_ts_idx != 0) { /* Process intermediate rates that failed.*/ for (series = 0; series < final_ts_idx ; series++) { - if (rcs[series].tries != 0) { - flags = rcs[series].flags; + if (rates[series].count != 0) { + flags = rates[series].flags; /* If HT40 and we have switched mode from * 40 to 20 => don't update */ - if ((flags & ATH_RC_CW40_FLAG) && + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (ath_rc_priv->rc_phy_mode != - (flags & ATH_RC_CW40_FLAG))) + (flags & IEEE80211_TX_RC_40_MHZ_WIDTH))) return; - if ((flags & ATH_RC_CW40_FLAG) && - (flags & ATH_RC_SGI_FLAG)) + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (flags & IEEE80211_TX_RC_SHORT_GI)) rix = rate_table->info[ - rcs[series].rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) + rates[series].idx].ht_index; + else if (flags & IEEE80211_TX_RC_SHORT_GI) rix = rate_table->info[ - rcs[series].rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) + rates[series].idx].sgi_index; + else if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) rix = rate_table->info[ - rcs[series].rix].cw40index; + rates[series].idx].cw40index; else rix = rate_table->info[ - rcs[series].rix].base_index; + rates[series].idx].base_index; ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix, xretries ? 1 : 2, - rcs[series].tries); + rates[series].count); } } } else { @@ -1336,24 +1336,24 @@ static void ath_rc_update(struct ath_softc *sc, * Treating it as an excessive retry penalizes the rate * inordinately. */ - if (rcs[0].tries == 1 && xretries == 1) + if (rates[0].count == 1 && xretries == 1) xretries = 2; } - flags = rcs[series].flags; + flags = rates[series].flags; /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & ATH_RC_CW40_FLAG) && - (ath_rc_priv->rc_phy_mode != (flags & ATH_RC_CW40_FLAG))) + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != (flags & IEEE80211_TX_RC_40_MHZ_WIDTH))) return; - if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[rcs[series].rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[rcs[series].rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[rcs[series].rix].cw40index; + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (flags & IEEE80211_TX_RC_SHORT_GI)) + rix = rate_table->info[rates[series].idx].ht_index; + else if (flags & IEEE80211_TX_RC_SHORT_GI) + rix = rate_table->info[rates[series].idx].sgi_index; + else if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rix = rate_table->info[rates[series].idx].cw40index; else - rix = rate_table->info[rcs[series].rix].base_index; + rix = rate_table->info[rates[series].idx].base_index; ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix, xretries, long_retry); @@ -1365,8 +1365,10 @@ static void ath_rc_update(struct ath_softc *sc, static void ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, struct ath_rate_node *rc_priv, - struct ath_tx_info_priv *info_priv) + struct ieee80211_tx_info *tx_info) { + struct ath_tx_info_priv *info_priv = + (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; int final_ts_idx = info_priv->tx.ts_rateindex; int tx_status = 0, is_underrun = 0; @@ -1395,7 +1397,7 @@ static void ath_rate_tx_complete(struct ath_softc *sc, (info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) tx_status = 1; - ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status, + ath_rc_update(sc, rc_priv, tx_info, final_ts_idx, tx_status, (is_underrun) ? ATH_11N_TXMAXTRY : info_priv->tx.ts_longretry); } @@ -1507,8 +1509,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - /* XXX: UGLY HACK!! */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; + tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; an = (struct ath_node *)sta->drv_priv; @@ -1516,10 +1517,9 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, return; if (an && priv_sta && ieee80211_is_data(fc)) - ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); + ath_rate_tx_complete(sc, an, priv_sta, tx_info); kfree(tx_info_priv); - tx_info->control.vif = NULL; } static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, @@ -1530,28 +1530,18 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; - struct ath_tx_info_priv *tx_info_priv; struct ath_rate_node *ath_rc_priv = priv_sta; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); int is_probe = FALSE; - s8 lowest_idx; __le16 fc = hdr->frame_control; u8 *qc, tid; - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - /* allocate driver private area of tx_info, XXX: UGLY HACK! */ - tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - ASSERT(tx_info_priv != NULL); - - lowest_idx = rate_lowest_index(sband, sta); - 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) { - tx_info->control.rates[0].idx = lowest_idx; + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); + tx_info->control.rates[0].count = + is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; return; } @@ -1559,24 +1549,11 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, ath_rate_findrate(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, ATH_RC_PROBE_ALLOWED, - tx_info_priv->rcs, + tx_info, &is_probe, false); -#if 0 - if (is_probe) - sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; -#endif - - /* Ratecontrol sometimes returns invalid rate index */ - if (tx_info_priv->rcs[0].rix != 0xff) - ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix; - else - tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix; - - tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix; /* Check if aggregation has to be enabled for this tid */ - if (hw->conf.ht.enabled) { if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 30248de..3324bed 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -169,20 +169,6 @@ struct ath_rate_table { #define ATH_RC_PROBE_ALLOWED 0x00000001 #define ATH_RC_MINRATE_LASTRATE 0x00000002 -struct ath_rc_series { - u8 rix; - u8 tries; - u8 flags; - u32 max_4ms_framelen; -}; - -/* rcs_flags definition */ -#define ATH_RC_DS_FLAG 0x01 -#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */ -#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */ -#define ATH_RC_HT_FLAG 0x08 /* HT */ -#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */ - /* * State structures for new rate adaptation code */ @@ -259,13 +245,10 @@ struct ath_rate_node { struct ath_rate_softc *asc; }; -/* Driver data of ieee80211_tx_info */ struct ath_tx_info_priv { - struct ath_rc_series rcs[4]; struct ath_tx_status tx; int n_frames; int n_bad_frames; - u8 min_rate; }; void ath_rate_attach(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 44735b6..baf5cb9 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -102,23 +102,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, ath9k_hw_txstart(ah, txq->axq_qnum); } -/* Get transmit rate index using rate in Kbps */ - -static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate) -{ - int i; - int ndx = 0; - - for (i = 0; i < rt->rateCount; i++) { - if (rt->info[i].rateKbps == rate) { - ndx = i; - break; - } - } - - return ndx; -} - /* Check if it's okay to send out aggregates */ static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) @@ -158,26 +141,23 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) return htype; } -static bool check_min_rate(struct sk_buff *skb) +static bool is_pae(struct sk_buff *skb) { struct ieee80211_hdr *hdr; - bool use_minrate = false; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - use_minrate = true; - } else if (ieee80211_is_data(fc)) { + if (ieee80211_is_data(fc)) { if (ieee80211_is_nullfunc(fc) || /* Port Access Entity (IEEE 802.1X) */ (skb->protocol == cpu_to_be16(ETH_P_PAE))) { - use_minrate = true; + return true; } } - return use_minrate; + return false; } static int get_hw_crypto_keytype(struct sk_buff *skb) @@ -199,50 +179,19 @@ static int get_hw_crypto_keytype(struct sk_buff *skb) static void setup_rate_retries(struct ath_softc *sc, struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; - struct ath_rc_series *rcs; + struct ieee80211_tx_rate *rates = tx_info->control.rates; struct ieee80211_hdr *hdr; - const struct ath9k_rate_table *rt; - bool use_minrate; __le16 fc; - u8 rix; - - rt = sc->sc_currates; - BUG_ON(!rt); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; /* HACK */ - rcs = tx_info_priv->rcs; - - /* Check if min rates have to be used */ - use_minrate = check_min_rate(skb); - - if (ieee80211_is_data(fc) && !use_minrate) { - if (is_multicast_ether_addr(hdr->addr1)) { - rcs[0].rix = - ath_tx_findindex(rt, tx_info_priv->min_rate); - /* mcast packets are not re-tried */ - rcs[0].tries = 1; - } - } else { - /* for management and control frames, - or for NULL and EAPOL frames */ - if (use_minrate) - rcs[0].rix = ath_rate_findrateix(sc, tx_info_priv->min_rate); - else - rcs[0].rix = 0; - rcs[0].tries = ATH_MGT_TXMAXTRY; - } - - rix = rcs[0].rix; if (ieee80211_has_morefrags(fc) || (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; - rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; + rates[1].count = rates[2].count = rates[3].count = 0; + rates[1].idx = rates[2].idx = rates[3].idx = 0; /* reset tries but keep rate index */ - rcs[0].tries = ATH_TXMAXTRY; + rates[0].count = ATH_TXMAXTRY; } } @@ -274,7 +223,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, /* Get seqno */ - if (ieee80211_is_data(fc) && !check_min_rate(skb)) { + if (ieee80211_is_data(fc) && !is_pae(skb)) { /* For HT capable stations, we save tidno for later use. * We also override seqno set by upper layer with the one * in tx aggregation state. @@ -573,9 +522,11 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->rate_driver_data[0]; if (tx_info->control.sta) an = (struct ath_node *)tx_info->control.sta->drv_priv; @@ -584,9 +535,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * get the cix for the lowest valid rix. */ rt = sc->sc_currates; - for (i = 4; i--;) { - if (bf->bf_rcs[i].tries) { - rix = bf->bf_rcs[i].rix; + for (i = 3; i >= 0; i--) { + if (rates[i].count) { + rix = rates[i].idx; break; } } @@ -662,27 +613,27 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); for (i = 0; i < 4; i++) { - if (!bf->bf_rcs[i].tries) + if (!rates[i].count) continue; - rix = bf->bf_rcs[i].rix; + rix = rates[i].idx; series[i].Rate = rt->info[rix].rateCode | (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); - series[i].Tries = bf->bf_rcs[i].tries; + series[i].Tries = rates[i].count; series[i].RateFlags = ( - (bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ? + (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ? ATH9K_RATESERIES_RTS_CTS : 0) | - ((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ? + ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? ATH9K_RATESERIES_2040 : 0) | - ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ? + ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ? ATH9K_RATESERIES_HALFGI : 0); series[i].PktDuration = ath_pkt_duration(sc, rix, bf, - (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, - (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), + (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, + (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), bf_isshpreamble(bf)); if (bf_isht(bf) && an) @@ -718,22 +669,12 @@ static int ath_tx_send_normal(struct ath_softc *sc, struct list_head *bf_head) { struct ath_buf *bf; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ - skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - - /* XXX: HACK! */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); - /* update starting sequence number for subsequent ADDBA request */ INCR(tid->seq_start, IEEE80211_SEQ_MAX); @@ -1124,8 +1065,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - /* XXX: HACK! */ - tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif; + tx_info_priv = + (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && @@ -1268,9 +1209,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, struct ath_tx_control *txctl) { struct ath_buf *bf; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; BUG_ON(list_empty(bf_head)); @@ -1296,12 +1234,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, return 0; } - skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - /* XXX: HACK! */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; - memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); - /* Add sub-frame to BAW */ ath_tx_addto_baw(sc, tid, bf); @@ -1323,9 +1255,11 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) { + struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; const struct ath9k_rate_table *rt = sc->sc_currates; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frame_length; u16 aggr_limit, legacy = 0, maxampdu; @@ -1333,10 +1267,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc, skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->control.vif; /* XXX: HACK! */ - memcpy(bf->bf_rcs, - tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); + rates = tx_info->control.rates; + tx_info_priv = + (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; /* * Find the lowest frame length among the rate series that will have a @@ -1346,14 +1279,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; for (i = 0; i < 4; i++) { - if (bf->bf_rcs[i].tries) { - frame_length = bf->bf_rcs[i].max_4ms_framelen; - - if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) { + if (rates[i].count) { + if (rt->info[rates[i].idx].phy != PHY_HT) { legacy = 1; break; } + frame_length = + rate_table->info[rates[i].idx].max_4ms_framelen; max_4ms_framelen = min(max_4ms_framelen, frame_length); } } @@ -1393,6 +1326,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, u16 frmlen) { const struct ath9k_rate_table *rt = sc->sc_currates; + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; u16 minlen; u8 rc, flags, rix; @@ -1425,11 +1360,11 @@ static int ath_compute_num_delims(struct ath_softc *sc, if (mpdudensity == 0) return ndelim; - rix = bf->bf_rcs[0].rix; - flags = bf->bf_rcs[0].flags; + rix = tx_info->control.rates[0].idx; + flags = tx_info->control.rates[0].flags; rc = rt->info[rix].rateCode; - width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0; - half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0; + width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; + half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; if (half_gi) nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); @@ -1471,7 +1406,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; - int prev_al = 0, is_ds_rate = 0; + int prev_al = 0; INIT_LIST_HEAD(&bf_head); BUG_ON(list_empty(&tid->buf_q)); @@ -1492,11 +1427,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, if (!rl) { aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; - /* - * Is rate dual stream - */ - is_ds_rate = - (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0; } /* @@ -1739,14 +1669,13 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_tx_info_priv *tx_info_priv; - struct ath_rc_series *rcs; int hdrlen; __le16 fc; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; + tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_KERNEL); + tx_info->rate_driver_data[0] = tx_info_priv; hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; - rcs = tx_info_priv->rcs; ATH_TXBUF_RESET(bf); @@ -1766,7 +1695,7 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); - (sc->hw->conf.ht.enabled && + (sc->hw->conf.ht.enabled && !is_pae(skb) && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ? (bf->bf_state.bf_type |= BUF_HT) : (bf->bf_state.bf_type &= ~BUF_HT); @@ -1788,11 +1717,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, setup_rate_retries(sc, skb); - bf->bf_rcs[0] = rcs[0]; - bf->bf_rcs[1] = rcs[1]; - bf->bf_rcs[2] = rcs[2]; - bf->bf_rcs[3] = rcs[3]; - /* Assign seqno, tidno */ if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) -- cgit v1.1 From e63835b0f4d8545942fd41b3ca32bbf71bd73e4b Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:07:53 +0530 Subject: ath9k: Remove ath9k_rate_table Maintaining two sets of rate tables is redundant, remove one and use struct ath_rate_table exclusively. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 26 +---- drivers/net/wireless/ath9k/beacon.c | 8 +- drivers/net/wireless/ath9k/core.c | 52 ++-------- drivers/net/wireless/ath9k/core.h | 5 - drivers/net/wireless/ath9k/hw.c | 190 +----------------------------------- drivers/net/wireless/ath9k/main.c | 2 + drivers/net/wireless/ath9k/rc.c | 51 ++++++++-- drivers/net/wireless/ath9k/rc.h | 3 + drivers/net/wireless/ath9k/recv.c | 6 +- drivers/net/wireless/ath9k/xmit.c | 163 +++++++++++-------------------- 10 files changed, 132 insertions(+), 374 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 6be2b94..c4012c8 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -401,22 +401,6 @@ enum ath9k_int { ATH9K_INT_NOCARD = 0xffffffff }; -struct ath9k_rate_table { - int rateCount; - u8 rateCodeToIndex[256]; - struct { - u8 valid; - u8 phy; - u32 rateKbps; - u8 rateCode; - u8 shortPreamble; - u8 dot11Rate; - u8 controlRate; - u16 lpAckDuration; - u16 spAckDuration; - } info[32]; -}; - #define ATH9K_RATESERIES_RTS_CTS 0x0001 #define ATH9K_RATESERIES_2040 0x0002 #define ATH9K_RATESERIES_HALFGI 0x0004 @@ -828,6 +812,8 @@ struct chan_centers { u16 ext_center; }; +struct ath_rate_table; + /* Helpers */ enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, @@ -838,7 +824,7 @@ bool ath9k_get_channel_edges(struct ath_hal *ah, u16 flags, u16 *low, u16 *high); u16 ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, + struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble); u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); @@ -883,12 +869,6 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, const struct ath9k_beacon_state *bs); - -/* Rate table */ - -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode); - /* HW Capabilities */ bool ath9k_hw_fill_cap_info(struct ath_hal *ah); diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index d186cd4..dcf2383 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -68,7 +68,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - const struct ath9k_rate_table *rt; + struct ath_rate_table *rt; int flags, antenna; u8 rix, rate; int ctsrate = 0; @@ -106,10 +106,10 @@ static void ath_beacon_setup(struct ath_softc *sc, * XXX everything at min xmit rate */ rix = 0; - rt = sc->sc_currates; - rate = rt->info[rix].rateCode; + rt = sc->hw_rate_table[sc->sc_curmode]; + rate = rt->info[rix].ratecode; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= rt->info[rix].shortPreamble; + rate |= rt->info[rix].short_preamble; ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, /* frame length */ diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 6c872e7..fb6a013 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -80,38 +80,9 @@ static u8 parse_mpdudensity(u8 mpdudensity) /* * Set current operating mode - * - * This function initializes and fills the rate table in the ATH object based - * on the operating mode. */ static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { - const struct ath9k_rate_table *rt; - int i; - - rt = ath9k_hw_getratetable(sc->sc_ah, mode); - BUG_ON(!rt); - - memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); - for (i = 0; i < 256; i++) { - u8 ix = rt->rateCodeToIndex[i]; - - if (ix == 0xff) - continue; - - sc->sc_hwmap[i].ieeerate = - rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; - sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps; - - if (rt->info[ix].shortPreamble || - rt->info[ix].phy == PHY_OFDM) { - /* XXX: Handle this */ - } - - /* NB: this uses the last entry if the rate isn't found */ - /* XXX beware of overlow */ - } - sc->sc_currates = rt; sc->sc_curmode = mode; /* * All protection frames are transmited at 2Mb/s for @@ -126,37 +97,36 @@ static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) */ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) { - struct ath_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt = NULL; + struct ath_rate_table *rate_table = NULL; struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; int i, maxrates; switch (band) { case IEEE80211_BAND_2GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G); + rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; break; case IEEE80211_BAND_5GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A); + rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; break; default: break; } - if (rt == NULL) + if (rate_table == NULL) return; sband = &sc->sbands[band]; rate = sc->rates[band]; - if (rt->rateCount > ATH_RATE_MAX) + if (rate_table->rate_cnt > ATH_RATE_MAX) maxrates = ATH_RATE_MAX; else - maxrates = rt->rateCount; + maxrates = rate_table->rate_cnt; for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rt->info[i].rateKbps / 100; - rate[i].hw_value = rt->info[i].rateCode; + rate[i].bitrate = rate_table->info[i].ratekbps / 100; + rate[i].hw_value = rate_table->info[i].ratecode; sband->n_bitrates++; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Rate: %2dMbps, ratecode: %2d\n", @@ -1000,12 +970,10 @@ int ath_init(u16 devid, struct ath_softc *sc) /* Setup rate tables */ + ath_rate_attach(sc); ath_setup_rates(sc, IEEE80211_BAND_2GHZ); ath_setup_rates(sc, IEEE80211_BAND_5GHZ); - /* NB: setup here so ath_rate_update is happy */ - ath_setcurmode(sc, ATH9K_MODE_11A); - /* * Allocate hardware transmit queues: one queue for * beacon frames and one data queue for each QoS @@ -1071,8 +1039,6 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - ath_rate_attach(sc); - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_TKIP, NULL)) { /* diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 255f860..0c34820 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -858,12 +858,7 @@ struct ath_softc { /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; - const struct ath9k_rate_table *sc_currates; u8 sc_protrix; /* protection rate index */ - struct { - u32 rateKbps; /* transfer rate in kbs */ - u8 ieeerate; /* IEEE rate */ - } sc_hwmap[256]; /* h/w rate ix mappings */ /* Channel, Band */ struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 82c2a42..a26867c 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -142,14 +142,14 @@ bool ath9k_get_channel_edges(struct ath_hal *ah, } u16 ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, + struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble) { u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; u32 kbps; - kbps = rates->info[rateix].rateKbps; + kbps = rates->info[rateix].ratekbps; if (kbps == 0) return 0; @@ -157,7 +157,7 @@ u16 ath9k_hw_computetxtime(struct ath_hal *ah, switch (rates->info[rateix].phy) { case PHY_CCK: phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (shortPreamble && rates->info[rateix].shortPreamble) + if (shortPreamble && rates->info[rateix].short_preamble) phyTime >>= 1; numBits = frameLen << 3; txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); @@ -3190,190 +3190,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, } -/***************/ -/* Rate tables */ -/***************/ - -static struct ath9k_rate_table ar5416_11a_table = { - 8, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4} - }, -}; - -static struct ath9k_rate_table ar5416_11b_table = { - 4, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1} - }, -}; - -static struct ath9k_rate_table ar5416_11g_table = { - 12, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8} - }, -}; - -static struct ath9k_rate_table ar5416_11ng_table = { - 28, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 4}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 6}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 6}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 8}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 8}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 8}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 8}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 8}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 4}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 6}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8}, - }, -}; - -static struct ath9k_rate_table ar5416_11na_table = { - 24, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 0}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 2}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 2}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 4}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 4}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 4}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 4}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 4}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 0}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 2}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4}, - }, -}; - -static void ath9k_hw_setup_rate_table(struct ath_hal *ah, - struct ath9k_rate_table *rt) -{ - int i; - - if (rt->rateCodeToIndex[0] != 0) - return; - - for (i = 0; i < 256; i++) - rt->rateCodeToIndex[i] = (u8) -1; - - for (i = 0; i < rt->rateCount; i++) { - u8 code = rt->info[i].rateCode; - u8 cix = rt->info[i].controlRate; - - rt->rateCodeToIndex[code] = i; - rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; - - rt->info[i].lpAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - false); - rt->info[i].spAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - true); - } -} - -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode) -{ - struct ath9k_rate_table *rt; - - switch (mode) { - case ATH9K_MODE_11A: - rt = &ar5416_11a_table; - break; - case ATH9K_MODE_11B: - rt = &ar5416_11b_table; - break; - case ATH9K_MODE_11G: - rt = &ar5416_11g_table; - break; - case ATH9K_MODE_11NG_HT20: - case ATH9K_MODE_11NG_HT40PLUS: - case ATH9K_MODE_11NG_HT40MINUS: - rt = &ar5416_11ng_table; - break; - case ATH9K_MODE_11NA_HT20: - case ATH9K_MODE_11NA_HT40PLUS: - case ATH9K_MODE_11NA_HT40MINUS: - rt = &ar5416_11na_table; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n", - __func__, mode); - return NULL; - } - - ath9k_hw_setup_rate_table(ah, rt); - - return rt; -} - /*******************/ /* HW Capabilities */ /*******************/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 11d7bee..e86bcd2 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -780,6 +780,8 @@ static int ath_attach(u16 devid, struct ath_softc *sc) BIT(NL80211_IFTYPE_ADHOC); hw->queues = 4; + hw->max_rates = 4; + hw->max_rate_tries = ATH_11N_TXMAXTRY; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vap); diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 156b245..bf637aa 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -25,6 +25,7 @@ static struct ath_rate_table ar5416_11na_ratetable = { 42, + {0}, { { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, @@ -168,6 +169,7 @@ static struct ath_rate_table ar5416_11na_ratetable = { static struct ath_rate_table ar5416_11ng_ratetable = { 46, + {0}, { { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, @@ -315,6 +317,7 @@ static struct ath_rate_table ar5416_11ng_ratetable = { static struct ath_rate_table ar5416_11a_ratetable = { 8, + {0}, { { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), @@ -348,6 +351,7 @@ static struct ath_rate_table ar5416_11a_ratetable = { static struct ath_rate_table ar5416_11g_ratetable = { 12, + {0}, { { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, @@ -393,6 +397,7 @@ static struct ath_rate_table ar5416_11g_ratetable = { static struct ath_rate_table ar5416_11b_ratetable = { 4, + {0}, { { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, (0x80|2), @@ -1302,14 +1307,14 @@ static void ath_rc_update(struct ath_softc *sc, if (final_ts_idx != 0) { /* Process intermediate rates that failed.*/ for (series = 0; series < final_ts_idx ; series++) { - if (rates[series].count != 0) { + if (rates[series].count != 0 && (rates[series].idx >= 0)) { flags = rates[series].flags; /* If HT40 and we have switched mode from * 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (ath_rc_priv->rc_phy_mode != - (flags & IEEE80211_TX_RC_40_MHZ_WIDTH))) + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) return; + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (flags & IEEE80211_TX_RC_SHORT_GI)) rix = rate_table->info[ @@ -1343,8 +1348,9 @@ static void ath_rc_update(struct ath_softc *sc, flags = rates[series].flags; /* If HT40 and we have switched mode from 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (ath_rc_priv->rc_phy_mode != (flags & IEEE80211_TX_RC_40_MHZ_WIDTH))) + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { return; + } if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (flags & IEEE80211_TX_RC_SHORT_GI)) rix = rate_table->info[rates[series].idx].ht_index; @@ -1628,7 +1634,6 @@ static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) { struct ath_rate_node *rate_priv = priv_sta; - kfree(rate_priv); } @@ -1644,6 +1649,35 @@ static struct rate_control_ops ath_rate_ops = { .free_sta = ath_rate_free_sta, }; +static void ath_setup_rate_table(struct ath_softc *sc, + struct ath_rate_table *rate_table) +{ + int i; + + for (i = 0; i < 256; i++) + rate_table->rateCodeToIndex[i] = (u8)-1; + + for (i = 0; i < rate_table->rate_cnt; i++) { + u8 code = rate_table->info[i].ratecode; + u8 cix = rate_table->info[i].ctrl_rate; + u8 sh = rate_table->info[i].short_preamble; + + rate_table->rateCodeToIndex[code] = i; + rate_table->rateCodeToIndex[code | sh] = i; + + rate_table->info[i].lpAckDuration = + ath9k_hw_computetxtime(sc->sc_ah, rate_table, + WLAN_CTRL_FRAME_SIZE, + cix, + false); + rate_table->info[i].spAckDuration = + ath9k_hw_computetxtime(sc->sc_ah, rate_table, + WLAN_CTRL_FRAME_SIZE, + cix, + true); + } +} + void ath_rate_attach(struct ath_softc *sc) { sc->hw_rate_table[ATH9K_MODE_11B] = @@ -1664,6 +1698,12 @@ void ath_rate_attach(struct ath_softc *sc) &ar5416_11ng_ratetable; sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable; + + ath_setup_rate_table(sc, &ar5416_11b_ratetable); + ath_setup_rate_table(sc, &ar5416_11a_ratetable); + ath_setup_rate_table(sc, &ar5416_11g_ratetable); + ath_setup_rate_table(sc, &ar5416_11na_ratetable); + ath_setup_rate_table(sc, &ar5416_11ng_ratetable); } int ath_rate_control_register(void) @@ -1675,4 +1715,3 @@ void ath_rate_control_unregister(void) { ieee80211_rate_control_unregister(&ath_rate_ops); } - diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 3324bed..c1e370c 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -143,6 +143,7 @@ enum { */ struct ath_rate_table { int rate_cnt; + u8 rateCodeToIndex[256]; struct { int valid; int valid_single_stream; @@ -160,6 +161,8 @@ struct ath_rate_table { u8 sgi_index; u8 ht_index; u32 max_4ms_framelen; + u16 lpAckDuration; + u16 spAckDuration; } info[RATE_TABLE_SIZE]; u32 probe_interval; u32 rssi_reduce_interval; diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 000e189..20f8377 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -140,8 +140,9 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, struct ieee80211_rx_status *rx_status, bool *decrypt_error, struct ath_softc *sc) { + struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; struct ieee80211_hdr *hdr; - int ratekbps; + int ratekbps, rix; u8 ratecode; __le16 fc; @@ -196,7 +197,8 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } ratecode = ds->ds_rxstat.rs_rate; - ratekbps = sc->sc_hwmap[ratecode].rateKbps; + rix = rate_table->rateCodeToIndex[ratecode]; + ratekbps = rate_table->info[rix].ratekbps; /* HT rate */ if (ratecode & 0x80) { diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index baf5cb9..b2d0cca 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -176,25 +176,6 @@ static int get_hw_crypto_keytype(struct sk_buff *skb) return ATH9K_KEY_TYPE_CLEAR; } -static void setup_rate_retries(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - rates[1].count = rates[2].count = rates[3].count = 0; - rates[1].idx = rates[2].idx = rates[3].idx = 0; - /* reset tries but keep rate index */ - rates[0].count = ATH_TXMAXTRY; - } -} - /* Called only when tx aggregation is enabled and HT is supported */ static void assign_aggr_tid_seqno(struct sk_buff *skb, @@ -468,27 +449,23 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, * width - 0 for 20 MHz, 1 for 40 MHz * half_gi - to use 4us v/s 3.6 us for symbol time */ - static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, int width, int half_gi, bool shortPreamble) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; u32 nbits, nsymbits, duration, nsymbols; u8 rc; int streams, pktlen; pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; - rc = rt->info[rix].rateCode; + rc = rate_table->info[rix].ratecode; - /* - * for legacy rates, use old function to compute packet duration - */ + /* for legacy rates, use old function to compute packet duration */ if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, rt, pktlen, rix, - shortPreamble); - /* - * find number of symbols: PLCP + data - */ + return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, + rix, shortPreamble); + + /* find number of symbols: PLCP + data */ nbits = (pktlen << 3) + OFDM_PLCP_BITS; nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; nsymbols = (nbits + nsymbits - 1) / nsymbits; @@ -498,9 +475,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, else duration = SYMBOL_TIME_HALFGI(nsymbols); - /* - * addup duration for legacy/ht training and signal fields - */ + /* addup duration for legacy/ht training and signal fields */ streams = HT_RC_2_STREAMS(rc); duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); @@ -512,114 +487,104 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt; + struct ath_rate_table *rt; struct ath_desc *ds = bf->bf_desc; struct ath_desc *lastds = bf->bf_lastbf->bf_desc; struct ath9k_11n_rate_series series[4]; - int i, flags, rtsctsena = 0; - u32 ctsduration = 0; - u8 rix = 0, cix, ctsrate = 0; struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; + struct ieee80211_hdr *hdr; + int i, flags, rtsctsena = 0; + u32 ctsduration = 0; + u8 rix = 0, cix, ctsrate = 0; + __le16 fc; + + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); skb = (struct sk_buff *)bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; tx_info = IEEE80211_SKB_CB(skb); - rates = tx_info->rate_driver_data[0]; + rates = tx_info->control.rates; if (tx_info->control.sta) an = (struct ath_node *)tx_info->control.sta->drv_priv; - /* - * get the cix for the lowest valid rix. - */ - rt = sc->sc_currates; + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { + rates[1].count = rates[2].count = rates[3].count = 0; + rates[1].idx = rates[2].idx = rates[3].idx = 0; + rates[0].count = ATH_TXMAXTRY; + } + + /* get the cix for the lowest valid rix */ + rt = sc->hw_rate_table[sc->sc_curmode]; for (i = 3; i >= 0; i--) { - if (rates[i].count) { + if (rates[i].count && (rates[i].idx >= 0)) { rix = rates[i].idx; break; } } + flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)); - cix = rt->info[rix].controlRate; + cix = rt->info[rix].ctrl_rate; /* - * If 802.11g protection is enabled, determine whether - * to use RTS/CTS or just CTS. Note that this is only - * done for OFDM/HT unicast frames. + * If 802.11g protection is enabled, determine whether to use RTS/CTS or + * just CTS. Note that this is only done for OFDM/HT unicast frames. */ - if (sc->sc_protmode != PROT_M_NONE && - (rt->info[rix].phy == PHY_OFDM || - rt->info[rix].phy == PHY_HT) && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { + if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK) + && (rt->info[rix].phy == WLAN_PHY_OFDM || + WLAN_RC_PHY_HT(rt->info[rix].phy))) { if (sc->sc_protmode == PROT_M_RTSCTS) flags = ATH9K_TXDESC_RTSENA; else if (sc->sc_protmode == PROT_M_CTSONLY) flags = ATH9K_TXDESC_CTSENA; - cix = rt->info[sc->sc_protrix].controlRate; + cix = rt->info[sc->sc_protrix].ctrl_rate; rtsctsena = 1; } - /* For 11n, the default behavior is to enable RTS for - * hw retried frames. We enable the global flag here and - * let rate series flags determine which rates will actually - * use RTS. + /* For 11n, the default behavior is to enable RTS for hw retried frames. + * We enable the global flag here and let rate series flags determine + * which rates will actually use RTS. */ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { - /* - * 802.11g protection not needed, use our default behavior - */ + /* 802.11g protection not needed, use our default behavior */ if (!rtsctsena) flags = ATH9K_TXDESC_RTSENA; } - /* - * Set protection if aggregate protection on - */ + /* Set protection if aggregate protection on */ if (sc->sc_config.ath_aggr_prot && (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { flags = ATH9K_TXDESC_RTSENA; - cix = rt->info[sc->sc_protrix].controlRate; + cix = rt->info[sc->sc_protrix].ctrl_rate; rtsctsena = 1; } - /* - * For AR5416 - RTS cannot be followed by a frame larger than 8K. - */ - if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) { - /* - * Ensure that in the case of SM Dynamic power save - * while we are bursting the second aggregate the - * RTS is cleared. - */ + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) flags &= ~(ATH9K_TXDESC_RTSENA); - } - - /* - * CTS transmit rate is derived from the transmit rate - * by looking in the h/w rate table. We must also factor - * in whether or not a short preamble is to be used. - * NB: cix is set above where RTS/CTS is enabled - */ - BUG_ON(cix == 0xff); - ctsrate = rt->info[cix].rateCode | - (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); /* - * Setup HAL rate series + * CTS transmit rate is derived from the transmit rate by looking in the + * h/w rate table. We must also factor in whether or not a short + * preamble is to be used. NB: cix is set above where RTS/CTS is enabled */ - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + ctsrate = rt->info[cix].ratecode | + (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0); for (i = 0; i < 4; i++) { - if (!rates[i].count) + if (!rates[i].count || (rates[i].idx < 0)) continue; rix = rates[i].idx; - series[i].Rate = rt->info[rix].rateCode | - (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); + series[i].Rate = rt->info[rix].ratecode | + (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0); series[i].Tries = rates[i].count; @@ -645,13 +610,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; } - /* - * set dur_update_en for l-sig computation except for PS-Poll frames - */ - ath9k_hw_set11n_ratescenario(ah, ds, lastds, - !bf_ispspoll(bf), - ctsrate, - ctsduration, + /* set dur_update_en for l-sig computation except for PS-Poll frames */ + ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf), + ctsrate, ctsduration, series, 4, flags); if (sc->sc_config.ath_aggr_prot && flags) @@ -662,7 +623,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Function to send a normal HT (non-AMPDU) frame * NB: must be called with txq lock held */ - static int ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, @@ -1256,7 +1216,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; - const struct ath9k_rate_table *rt = sc->sc_currates; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -1280,7 +1239,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, for (i = 0; i < 4; i++) { if (rates[i].count) { - if (rt->info[rates[i].idx].phy != PHY_HT) { + if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { legacy = 1; break; } @@ -1325,7 +1284,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *bf, u16 frmlen) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rt = sc->hw_rate_table[sc->sc_curmode]; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; @@ -1362,7 +1321,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, rix = tx_info->control.rates[0].idx; flags = tx_info->control.rates[0].flags; - rc = rt->info[rix].rateCode; + rc = rt->info[rix].ratecode; width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; @@ -1713,10 +1672,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, bf->bf_keyix = ATH9K_TXKEYIX_INVALID; } - /* Rate series */ - - setup_rate_retries(sc, skb); - /* Assign seqno, tidno */ if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) -- cgit v1.1 From 46d14a58ffb42702e4c1b8bb88cfa05414617f4c Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:08:13 +0530 Subject: ath9k: General code scrub Replace TRUE/FALSE macros with VALID/INVALID macros. Follow a consistent variable convention. Remove unnecessary comments. Add all RC phy macros into a single enum. Merge functions into reasonably sized entities. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 18 +- drivers/net/wireless/ath9k/hw.c | 4 +- drivers/net/wireless/ath9k/main.c | 9 +- drivers/net/wireless/ath9k/rc.c | 546 ++++++++++++++++--------------------- drivers/net/wireless/ath9k/rc.h | 110 ++------ drivers/net/wireless/ath9k/xmit.c | 2 +- 6 files changed, 277 insertions(+), 412 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index c4012c8..6b0e3dd 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -686,13 +686,19 @@ enum ath9k_ani_cmd { ATH9K_ANI_ALL = 0xff }; -enum phytype { - PHY_DS, - PHY_FH, - PHY_OFDM, - PHY_HT, +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, + WLAN_RC_PHY_HT_20_SS, + WLAN_RC_PHY_HT_20_DS, + WLAN_RC_PHY_HT_40_SS, + WLAN_RC_PHY_HT_40_DS, + WLAN_RC_PHY_HT_20_SS_HGI, + WLAN_RC_PHY_HT_20_DS_HGI, + WLAN_RC_PHY_HT_40_SS_HGI, + WLAN_RC_PHY_HT_40_DS_HGI, + WLAN_RC_PHY_MAX }; -#define PHY_CCK PHY_DS enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index a26867c..eb14451 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -155,14 +155,14 @@ u16 ath9k_hw_computetxtime(struct ath_hal *ah, return 0; switch (rates->info[rateix].phy) { - case PHY_CCK: + case WLAN_RC_PHY_CCK: phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; if (shortPreamble && rates->info[rateix].short_preamble) phyTime >>= 1; numBits = frameLen << 3; txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); break; - case PHY_OFDM: + case WLAN_RC_PHY_OFDM: if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index e86bcd2..9a79824 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -346,16 +346,15 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); DPRINTF(sc, ATH_DBG_XMIT, "%s: TX complete: skb: %p\n", __func__, skb); if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - if (tx_info->rate_driver_data[0] != NULL) { - kfree(tx_info->rate_driver_data[0]); - tx_info->rate_driver_data[0] = NULL; - } + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; } if (tx_status->flags & ATH_TX_BAR) { diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index bf637aa..51f51af 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -15,142 +15,136 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Atheros rate control algorithm - */ - #include "core.h" -/* FIXME: remove this include! */ -#include "../net/mac80211/rate.h" static struct ath_rate_table ar5416_11na_ratetable = { 42, {0}, { - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 0, 2, 1, 0, 0, 0, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, 2, 4, 2, 2, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 2, 6, 2, 3, 3, 3, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, 4, 10, 3, 4, 4, 4, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 4, 14, 3, 5, 5, 5, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 4, 20, 3, 6, 6, 6, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 23, 3, 7, 7, 7, 7, 0 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 0, 2, 3, 8, 24, 8, 24, 3216 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, 2, 4, 3, 9, 25, 9, 25, 6434 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, 2, 6, 3, 10, 26, 10, 26, 9650 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, 4, 10, 3, 11, 27, 11, 27, 12868 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, 4, 14, 3, 12, 28, 12, 28, 19304 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, 4, 20, 3, 13, 29, 13, 29, 25740 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, 4, 23, 3, 14, 30, 14, 30, 28956 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 15, 32, 32180 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, 2, 4, 3, 17, 34, 17, 34, 12860 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, 2, 6, 3, 18, 35, 18, 35, 19300 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, 4, 10, 3, 19, 36, 19, 36, 25736 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, 4, 14, 3, 20, 37, 20, 37, 38600 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, 4, 20, 3, 21, 38, 21, 38, 51472 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, 4, 23, 3, 22, 39, 22, 39, 57890 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 23, 41, 64320 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, 0, 2, 3, 8, 24, 24, 24, 6684 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, 2, 4, 3, 9, 25, 25, 25, 13368 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, 2, 6, 3, 10, 26, 26, 26, 20052 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, 4, 10, 3, 11, 27, 27, 27, 26738 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, 4, 14, 3, 12, 28, 28, 28, 40104 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, 4, 20, 3, 13, 29, 29, 29, 53476 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, 4, 23, 3, 14, 30, 30, 30, 60156 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 32, 32, 66840 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 32, 32, 74200 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, 0, 2, 3, 16, 33, 33, 33, 13360 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, 2, 4, 3, 17, 34, 34, 34, 26720 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, 2, 6, 3, 18, 35, 35, 35, 40080 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, 4, 10, 3, 19, 36, 36, 36, 53440 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, 4, 14, 3, 20, 37, 37, 37, 80160 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, 4, 20, 3, 21, 38, 38, 38, 106880 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, 4, 23, 3, 22, 39, 39, 39, 120240 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 41, 41, 133600 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 41, 41, 148400 }, }, @@ -159,10 +153,10 @@ static struct ath_rate_table ar5416_11na_ratetable = { WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; -/* TRUE_ALL - valid for 20/40/Legacy, - * TRUE - Legacy only, - * TRUE_20 - HT 20 only, - * TRUE_40 - HT 40 only */ +/* VALID_ALL - valid for 20/40/Legacy, + * VALID - Legacy only, + * VALID_20 - HT 20 only, + * VALID_40 - HT 40 only */ /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ @@ -171,142 +165,142 @@ static struct ath_rate_table ar5416_11ng_ratetable = { 46, {0}, { - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, 0, 0, 1, 0, 0, 0, 0, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, 1, 1, 1, 1, 1, 1, 1, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, 2, 2, 2, 2, 2, 2, 2, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, 3, 3, 2, 3, 3, 3, 3, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 4, 2, 1, 4, 4, 4, 4, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 4, 3, 1, 5, 5, 5, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10100, 0x0a, 0x00, 24, 6, 4, 1, 6, 6, 6, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 14100, 0x0e, 0x00, 36, 6, 6, 2, 7, 7, 7, 7, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17700, 0x09, 0x00, 48, 8, 10, 3, 8, 8, 8, 8, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23700, 0x0d, 0x00, 72, 8, 14, 3, 9, 9, 9, 9, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 8, 20, 3, 10, 10, 10, 10, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 30900, 0x0c, 0x00, 108, 8, 23, 3, 11, 11, 11, 11, 0 }, - { FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 4, 2, 3, 12, 28, 12, 28, 3216 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, 6, 4, 3, 13, 29, 13, 29, 6434 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, 6, 6, 3, 14, 30, 14, 30, 9650 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, 8, 10, 3, 15, 31, 15, 31, 12868 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, 8, 14, 3, 16, 32, 16, 32, 19304 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, 8, 20, 3, 17, 33, 17, 33, 25740 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, 8, 23, 3, 18, 34, 18, 34, 28956 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, 8, 25, 3, 19, 35, 19, 36, 32180 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, 4, 2, 3, 20, 37, 20, 37, 6430 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, 6, 4, 3, 21, 38, 21, 38, 12860 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, 6, 6, 3, 22, 39, 22, 39, 19300 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, 8, 10, 3, 23, 40, 23, 40, 25736 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, 8, 14, 3, 24, 41, 24, 41, 38600 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, 8, 20, 3, 25, 42, 25, 42, 51472 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, 8, 23, 3, 26, 43, 26, 44, 57890 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, 8, 25, 3, 27, 44, 27, 45, 64320 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, 8, 2, 3, 12, 28, 28, 28, 6684 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, 8, 4, 3, 13, 29, 29, 29, 13368 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, 8, 6, 3, 14, 30, 30, 30, 20052 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, 8, 10, 3, 15, 31, 31, 31, 26738 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, 8, 14, 3, 16, 32, 32, 32, 40104 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, 8, 20, 3, 17, 33, 33, 33, 53476 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, 8, 23, 3, 18, 34, 34, 34, 60156 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, 8, 23, 3, 19, 35, 36, 36, 66840 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, 8, 25, 3, 19, 35, 36, 36, 74200 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, 8, 2, 3, 20, 37, 37, 37, 13360 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, 8, 4, 3, 21, 38, 38, 38, 26720 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, 8, 6, 3, 22, 39, 39, 39, 40080 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, 8, 10, 3, 23, 40, 40, 40, 53440 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, 8, 14, 3, 24, 41, 41, 41, 80160 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, 8, 20, 3, 25, 42, 42, 42, 106880 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, 8, 23, 3, 26, 43, 43, 43, 120240 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, 8, 23, 3, 27, 44, 45, 45, 133600 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, 8, 25, 3, 27, 44, 45, 45, 148400 }, }, @@ -319,28 +313,28 @@ static struct ath_rate_table ar5416_11a_ratetable = { 8, {0}, { - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), 0, 2, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, (0x80|24), 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, (0x80|48), 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 23, 3, 7, 0 }, }, @@ -353,40 +347,40 @@ static struct ath_rate_table ar5416_11g_ratetable = { 12, {0}, { - { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, 0, 0, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, 2, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, 3, 3, 2, 3, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 4, 2, 1, 4, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 4, 3, 1, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, 6, 4, 1, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 6, 6, 2, 7, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, 8, 10, 3, 8, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 8, 14, 3, 9, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 8, 19, 3, 10, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 8, 23, 3, 11, 0 }, }, @@ -399,16 +393,16 @@ static struct ath_rate_table ar5416_11b_ratetable = { 4, {0}, { - { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, (0x80|2), 0, 0, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1800, 0x1a, 0x04, (0x80|4), 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4300, 0x19, 0x04, (0x80|11), 1, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 7100, 0x18, 0x04, (0x80|22), 1, 4, 100, 3, 0 }, }, @@ -417,9 +411,6 @@ static struct ath_rate_table ar5416_11b_ratetable = { 0, /* Phy rates allowed initially */ }; -/* - * Return the median of three numbers - */ static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -440,7 +431,7 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, - struct ath_rate_node *ath_rc_priv) + struct ath_rate_priv *ath_rc_priv) { u8 i, j, idx, idx_next; @@ -458,34 +449,31 @@ static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, } } -/* Access functions for valid_txrate_mask */ - -static void ath_rc_init_valid_txmask(struct ath_rate_node *ath_rc_priv) +static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) { u8 i; for (i = 0; i < ath_rc_priv->rate_table_size; i++) - ath_rc_priv->valid_rate_index[i] = FALSE; + ath_rc_priv->valid_rate_index[i] = 0; } -static inline void ath_rc_set_valid_txmask(struct ath_rate_node *ath_rc_priv, +static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index, int valid_tx_rate) { ASSERT(index <= ath_rc_priv->rate_table_size); - ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE; + ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; } -static inline int ath_rc_isvalid_txmask(struct ath_rate_node *ath_rc_priv, +static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index) { ASSERT(index <= ath_rc_priv->rate_table_size); return ath_rc_priv->valid_rate_index[index]; } -/* Iterators for valid_txrate_mask */ static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_node *ath_rc_priv, + struct ath_rate_priv *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { @@ -494,13 +482,13 @@ ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { *next_idx = ath_rc_priv->valid_rate_index[i+1]; - return TRUE; + return 1; } } /* No more valid rates */ *next_idx = 0; - return FALSE; + return 0; } /* Return true only for single stream */ @@ -508,22 +496,22 @@ ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) { if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG)) - return FALSE; + return 0; if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return FALSE; + return 0; if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return FALSE; + return 0; if (!ignore_cw && WLAN_RC_PHY_HT(phy)) if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return FALSE; + return 0; if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) - return FALSE; - return TRUE; + return 0; + return 1; } static inline int ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_node *ath_rc_priv, + struct ath_rate_priv *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { int8_t i; @@ -531,17 +519,14 @@ ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { *next_idx = ath_rc_priv->valid_rate_index[i-1]; - return TRUE; + return 1; } } - return FALSE; + return 0; } -/* - * Initialize the Valid Rate Index from valid entries in Rate Table - */ static u8 -ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, +ath_rc_sib_init_validrates(struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, u32 capflag) { @@ -552,34 +537,30 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, valid = (ath_rc_priv->single_stream ? rate_table->info[i].valid_single_stream : rate_table->info[i].valid); - if (valid == TRUE) { + if (valid == 1) { u32 phy = rate_table->info[i].phy; u8 valid_rate_count = 0; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(ath_rc_priv, i, TRUE); + ath_rc_set_valid_txmask(ath_rc_priv, i, 1); hi = A_MAX(hi, i); } } return hi; } -/* - * Initialize the Valid Rate Index from Rate Set - */ static u8 -ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, +ath_rc_sib_setvalid_rates(struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, struct ath_rateset *rateset, u32 capflag) { - /* XXX: Clean me up and make identation friendly */ u8 i, j, hi = 0; /* Use intersection of working rates and valid rates */ @@ -592,10 +573,8 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, /* We allow a rate only if its valid and the * capflag matches one of the validity - * (TRUE/TRUE_20/TRUE_40) flags */ + * (VALID/VALID_20/VALID_40) flags */ - /* XXX: catch the negative of this branch - * first and then continue */ if (((rateset->rs_rates[i] & 0x7F) == (rate_table->info[j].dot11rate & 0x7F)) && ((valid & WLAN_RC_CAP_MODE(capflag)) == @@ -604,7 +583,7 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, u8 valid_rate_count = 0; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; valid_rate_count = @@ -613,7 +592,7 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, ath_rc_priv->valid_phy_rateidx[phy] [valid_rate_count] = j; ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(ath_rc_priv, j, TRUE); + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); hi = A_MAX(hi, j); } } @@ -622,7 +601,7 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, } static u8 -ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, +ath_rc_sib_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, u8 *mcs_set, u32 capflag) { @@ -643,13 +622,13 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; ath_rc_priv->valid_phy_rateidx[phy] [ath_rc_priv->valid_phy_ratecnt[phy]] = j; ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(ath_rc_priv, j, TRUE); + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); hi = A_MAX(hi, j); } } @@ -676,7 +655,7 @@ u8 ath_rate_findrateix(struct ath_softc *sc, } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, + struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, int probe_allowed, int *is_probing, int is_retry) @@ -685,7 +664,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, u8 rate, next_rate, best_rate, maxindex, minindex; int8_t rssi_last, rssi_reduce = 0, index = 0; - *is_probing = FALSE; + *is_probing = 0; rssi_last = median(ath_rc_priv->rssi_last, ath_rc_priv->rssi_last_prev, @@ -789,16 +768,10 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, ath_rc_priv->probe_rate = rate; ath_rc_priv->probe_time = now_msec; ath_rc_priv->hw_maxretry_pktcnt = 0; - *is_probing = TRUE; + *is_probing = 1; } } - /* - * Make sure rate is not higher than the allowed maximum. - * We should also enforce the min, but I suspect the min is - * normally 1 rather than 0 because of the rate 9 vs 6 issue - * in the old code. - */ if (rate > (ath_rc_priv->rate_table_size - 1)) rate = ath_rc_priv->rate_table_size - 1; @@ -829,7 +802,7 @@ static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , } static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, + struct ath_rate_priv *ath_rc_priv, struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) @@ -858,8 +831,8 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, } static void ath_rc_ratefind(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, int num_rates, unsigned int rcflag, + struct ath_rate_priv *ath_rc_priv, + int num_tries, int num_rates, struct ieee80211_tx_info *tx_info, int *is_probe, int is_retry) { @@ -868,30 +841,29 @@ static void ath_rc_ratefind(struct ath_softc *sc, struct ieee80211_tx_rate *rates = tx_info->control.rates; rate_table = sc->hw_rate_table[sc->sc_curmode]; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1, is_probe, is_retry); nrix = rix; - if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) { + if (*is_probe) { /* set one try for probe rates. For the * probes don't enable rts */ ath_rc_rate_set_series(rate_table, - &rates[i++], 1, nrix, FALSE); + &rates[i++], 1, nrix, 0); try_per_rate = (num_tries/num_rates); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ nrix = ath_rc_rate_getidx(sc, - ath_rc_priv, rate_table, nrix, 1, FALSE); + ath_rc_priv, rate_table, nrix, 1, 0); ath_rc_rate_set_series(rate_table, &rates[i++], try_per_rate, nrix, 0); } else { try_per_rate = (num_tries/num_rates); /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, - &rates[i++], try_per_rate, nrix, FALSE); + &rates[i++], try_per_rate, nrix, 0); } /* Fill in the other rates for multirate retry */ @@ -901,14 +873,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; + min_rate = (((i + 1) == num_rates) && 0); nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, - &rates[i], try_num, nrix, TRUE); + &rates[i], try_num, nrix, 1); } /* @@ -940,32 +911,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, } } -/* - * Return the Tx rate series. - */ -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 ieee80211_tx_info *tx_info, - int *is_probe, - int is_retry) -{ - if (!num_rates || !num_tries) - return; - - ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates, - rcflag, tx_info, is_probe, is_retry); -} - static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *info_priv, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, int tx_rate, int xretries, int retries) { u32 now_msec = jiffies_to_msecs(jiffies); - int state_change = FALSE, rate, count; + int state_change = 0, rate, count; u8 last_per; struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; static u32 nretry_to_per_lookup[10] = { @@ -991,9 +943,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* To compensate for some imbalance between ctrl and ext. channel */ if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - info_priv->tx.ts_rssi = - info_priv->tx.ts_rssi < 3 ? 0 : - info_priv->tx.ts_rssi - 3; + tx_info_priv->tx.ts_rssi = + tx_info_priv->tx.ts_rssi < 3 ? 0 : + tx_info_priv->tx.ts_rssi - 3; last_per = ath_rc_priv->state[tx_rate].per; @@ -1026,7 +978,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; - if (info_priv->n_bad_frames) { + if (tx_info_priv->n_bad_frames) { /* 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), @@ -1039,14 +991,14 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the above PER. The expression below is a * simplified version of the sum of these two terms. */ - if (info_priv->n_frames > 0) + if (tx_info_priv->n_frames > 0) ath_rc_priv->state[tx_rate].per = (u8) (ath_rc_priv->state[tx_rate].per - (ath_rc_priv->state[tx_rate].per >> 3) + - ((100*(retries*info_priv->n_frames + - info_priv->n_bad_frames) / - (info_priv->n_frames * + ((100*(retries*tx_info_priv->n_frames + + tx_info_priv->n_bad_frames) / + (tx_info_priv->n_frames * (retries+1))) >> 3)); } else { /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ @@ -1059,7 +1011,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; - ath_rc_priv->rssi_last = info_priv->tx.ts_rssi; + ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; ath_rc_priv->rssi_time = now_msec; /* @@ -1068,8 +1020,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, */ if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { - if (retries > 0 || 2 * info_priv->n_bad_frames > - info_priv->n_frames) { + if (retries > 0 || 2 * tx_info_priv->n_bad_frames > + tx_info_priv->n_frames) { /* * Since we probed with just a single attempt, * any retries means the probe failed. Also, @@ -1121,7 +1073,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->hw_maxretry_pktcnt++; } - if (info_priv->tx.ts_rssi >= + if (tx_info_priv->tx.ts_rssi >= rate_table->info[tx_rate].rssi_ack_validmin) { /* Average the rssi */ if (tx_rate != ath_rc_priv->rssi_sum_rate) { @@ -1130,7 +1082,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->rssi_sum_cnt = 0; } - ath_rc_priv->rssi_sum += info_priv->tx.ts_rssi; + ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; ath_rc_priv->rssi_sum_cnt++; if (ath_rc_priv->rssi_sum_cnt > 4) { @@ -1154,7 +1106,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, rssi_thres--; } - state_change = TRUE; + state_change = 1; } } } @@ -1282,17 +1234,12 @@ static void ath_rc_update_ht(struct ath_softc *sc, } } -/* - * This routine is called in rate control callback tx_status() to give - * the status of previous frames. - */ -static void ath_rc_update(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ieee80211_tx_info *tx_info, int final_ts_idx, - int xretries, int long_retry) +static void ath_rc_tx_status(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_tx_info *tx_info, + int final_ts_idx, int xretries, int long_retry) { - struct ath_tx_info_priv *info_priv = - (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); struct ath_rate_table *rate_table; struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; @@ -1329,7 +1276,7 @@ static void ath_rc_update(struct ath_softc *sc, rix = rate_table->info[ rates[series].idx].base_index; ath_rc_update_ht(sc, ath_rc_priv, - info_priv, rix, + tx_info_priv, rix, xretries ? 1 : 2, rates[series].count); } @@ -1361,55 +1308,12 @@ static void ath_rc_update(struct ath_softc *sc, else rix = rate_table->info[rates[series].idx].base_index; - ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix, + ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, xretries, long_retry); } -/* - * Process a tx descriptor for a completed transmit (success or failure). - */ -static void ath_rate_tx_complete(struct ath_softc *sc, - struct ath_node *an, - struct ath_rate_node *rc_priv, - struct ieee80211_tx_info *tx_info) -{ - struct ath_tx_info_priv *info_priv = - (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; - int final_ts_idx = info_priv->tx.ts_rateindex; - int tx_status = 0, is_underrun = 0; - - if (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); - } - - /* - * If underrun error is seen assume it as an excessive retry only - * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY - * times. This affects how ratectrl updates PER for the failed rate. - */ - if (info_priv->tx.ts_flags & - (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->ah_txTrigLevel) >= rc_priv->tx_triglevel_max)) { - tx_status = 1; - is_underrun = 1; - } - - if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || - (info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) - tx_status = 1; - - ath_rc_update(sc, rc_priv, tx_info, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : - info_priv->tx.ts_longretry); -} - static void ath_rc_init(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, + struct ath_rate_priv *ath_rc_priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta) { @@ -1427,13 +1331,14 @@ static void ath_rc_init(struct ath_softc *sc, rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; } /* Initial rate table size. Will change depending * on the working rate set */ - ath_rc_priv->rate_table_size = MAX_TX_RATE_TBL; + ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; /* Initialize thresholds according to the global rate table */ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { @@ -1474,7 +1379,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->rate_table_size = hi + 1; ath_rc_priv->rate_max_phy = 0; - ASSERT(ath_rc_priv->rate_table_size <= MAX_TX_RATE_TBL); + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { @@ -1482,21 +1387,16 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->valid_phy_rateidx[i][j]; } - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE) + if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) || !ath_rc_priv->valid_phy_ratecnt[i]) continue; ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; } - ASSERT(ath_rc_priv->rate_table_size <= MAX_TX_RATE_TBL); - ASSERT(k <= MAX_TX_RATE_TBL); + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + ASSERT(k <= RATE_TABLE_SIZE); ath_rc_priv->max_valid_rate = k; - /* - * Some third party vendors don't send the supported rate series in - * order. So sorting to make sure its in order, otherwise our RateFind - * Algo will select wrong rates - */ ath_rc_sort_validrates(rate_table, ath_rc_priv); ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; } @@ -1507,24 +1407,53 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct ath_softc *sc = priv; - struct ath_tx_info_priv *tx_info_priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_tx_info_priv *tx_info_priv = NULL; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; + int final_ts_idx, tx_status = 0, is_underrun = 0; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; - + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); an = (struct ath_node *)sta->drv_priv; + final_ts_idx = tx_info_priv->tx.ts_rateindex; - if (tx_info_priv == NULL) - return; + if (!an || !priv_sta || !ieee80211_is_data(fc)) + goto exit; - if (an && priv_sta && ieee80211_is_data(fc)) - ath_rate_tx_complete(sc, an, priv_sta, tx_info); + if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) + goto exit; + if (tx_info_priv->tx.ts_rssi > 0) { + ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, + tx_info_priv->tx.ts_rssi); + } + + /* + * If underrun error is seen assume it as an excessive retry only + * if prefetch trigger level have reached the max (0x3f for 5416) + * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY + * times. This affects how ratectrl updates PER for the failed rate. + */ + if (tx_info_priv->tx.ts_flags & + (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && + ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) { + tx_status = 1; + is_underrun = 1; + } + + if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || + (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) + tx_status = 1; + + ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, + (is_underrun) ? ATH_11N_TXMAXTRY : + tx_info_priv->tx.ts_longretry); + +exit: kfree(tx_info_priv); } @@ -1536,12 +1465,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; - struct ath_rate_node *ath_rc_priv = priv_sta; - struct ath_node *an; + struct ath_rate_priv *ath_rc_priv = priv_sta; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe = FALSE; + int is_probe = 0; __le16 fc = hdr->frame_control; - u8 *qc, tid; /* lowest rate for management and multicast/broadcast frames */ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { @@ -1552,16 +1479,15 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, } /* Find tx rate for unicast frames */ - ath_rate_findrate(sc, ath_rc_priv, - ATH_11N_TXMAXTRY, 4, - ATH_RC_PROBE_ALLOWED, - tx_info, - &is_probe, - false); + ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, + tx_info, &is_probe, false); /* Check if aggregation has to be enabled for this tid */ if (hw->conf.ht.enabled) { if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath_node *an; + qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; an = (struct ath_node *)sta->drv_priv; @@ -1576,7 +1502,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { struct ath_softc *sc = priv; - struct ath_rate_node *ath_rc_priv = priv_sta; + struct ath_rate_priv *ath_rc_priv = priv_sta; int i, j = 0; for (i = 0; i < sband->n_bitrates; i++) { @@ -1614,9 +1540,9 @@ static void ath_rate_free(void *priv) static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct ath_softc *sc = priv; - struct ath_rate_node *rate_priv; + struct ath_rate_priv *rate_priv; - rate_priv = kzalloc(sizeof(struct ath_rate_node), gfp); + rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to allocate private rc structure\n", @@ -1633,7 +1559,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) { - struct ath_rate_node *rate_priv = priv_sta; + struct ath_rate_priv *rate_priv = priv_sta; kfree(rate_priv); } diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index c1e370c..dff4b7a 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -20,73 +20,19 @@ #define RC_H #include "ath9k.h" -/* - * Interface definitions for transmit rate control modules for the - * Atheros driver. - * - * A rate control module is responsible for choosing the transmit rate - * for each data frame. Management+control frames are always sent at - * a fixed rate. - * - * Only one module may be present at a time; the driver references - * rate control interfaces by symbol name. If multiple modules are - * to be supported we'll need to switch to a registration-based scheme - * as is currently done, for example, for authentication modules. - * - * An instance of the rate control module is attached to each device - * at attach time and detached when the device is destroyed. The module - * may associate data with each device and each node (station). Both - * sets of storage are opaque except for the size of the per-node storage - * which must be provided when the module is attached. - * - * The rate control module is notified for each state transition and - * station association/reassociation. Otherwise it is queried for a - * rate for each outgoing frame and provided status from each transmitted - * frame. Any ancillary processing is the responsibility of the module - * (e.g. if periodic processing is required then the module should setup - * it's own timer). - * - * In addition to the transmit rate for each frame the module must also - * indicate the number of attempts to make at the specified rate. If this - * number is != ATH_TXMAXTRY then an additional callback is made to setup - * additional transmit state. The rate control code is assumed to write - * this additional data directly to the transmit descriptor. - */ struct ath_softc; -#define TRUE 1 -#define FALSE 0 - -#define ATH_RATE_MAX 30 - -#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 -#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS -#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI -#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS -#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI - -#define WLAN_PHY_OFDM PHY_OFDM -#define WLAN_PHY_CCK PHY_CCK +#define ATH_RATE_MAX 30 +#define RATE_TABLE_SIZE 64 +#define MAX_TX_RATE_PHY 48 -#define TRUE_20 0x2 -#define TRUE_40 0x4 -#define TRUE_2040 (TRUE_20|TRUE_40) -#define TRUE_ALL (TRUE_2040|TRUE) - -enum { - WLAN_RC_PHY_HT_20_SS = 4, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_MAX -}; +#define INVALID 0x0 +#define VALID 0x1 +#define VALID_20 0x2 +#define VALID_40 0x4 +#define VALID_2040 (VALID_20|VALID_40) +#define VALID_ALL (VALID_2040|VALID) #define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \ @@ -103,26 +49,22 @@ enum { #define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) -/* Returns the capflag mode */ #define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - (capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE)) + (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID)) /* Return TRUE if flag supports HT20 && client supports HT20 or * return TRUE if flag supports HT40 && client supports HT40. * This is used becos some rates overlap between HT20/HT40. */ - -#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \ - & WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \ - (capflag & WLAN_RC_40_FLAG))) +#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ + (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \ + ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG))) #define WLAN_RC_DS_FLAG (0x01) #define WLAN_RC_40_FLAG (0x02) #define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_HT_FLAG (0x08) -#define RATE_TABLE_SIZE 64 - /** * struct ath_rate_table - Rate Control table * @valid: valid for use in rate control @@ -139,7 +81,7 @@ enum { * @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() + * @initial_ratemax: initial ratemax value */ struct ath_rate_table { int rate_cnt; @@ -169,15 +111,6 @@ struct ath_rate_table { u8 initial_ratemax; }; -#define ATH_RC_PROBE_ALLOWED 0x00000001 -#define ATH_RC_MINRATE_LASTRATE 0x00000002 - -/* - * State structures for new rate adaptation code - */ -#define MAX_TX_RATE_TBL 64 -#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 (%) */ @@ -189,7 +122,7 @@ struct ath_rateset { }; /** - * struct ath_rate_node - Rate Control priv data + * struct ath_rate_priv - Rate Control priv data * @state: RC state * @rssi_last: last ACK rssi * @rssi_last_lookup: last ACK rssi used for lookup @@ -214,9 +147,7 @@ struct ath_rateset { * @neg_rates: Negotatied rates * @neg_ht_rates: Negotiated HT rates */ - -/* per-node state */ -struct ath_rate_node { +struct ath_rate_priv { int8_t rssi_last; int8_t rssi_last_lookup; int8_t rssi_last_prev; @@ -228,11 +159,11 @@ struct ath_rate_node { u8 probe_rate; u8 hw_maxretry_pktcnt; u8 max_valid_rate; - u8 valid_rate_index[MAX_TX_RATE_TBL]; + u8 valid_rate_index[RATE_TABLE_SIZE]; u8 ht_cap; u8 single_stream; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rc_phy_mode; u8 rate_max_phy; u32 rssi_time; @@ -242,7 +173,7 @@ struct ath_rate_node { u32 probe_interval; u32 prev_data_rix; u32 tx_triglevel_max; - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; + struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; @@ -254,6 +185,9 @@ struct ath_tx_info_priv { int n_bad_frames; }; +#define ATH_TX_INFO_PRIV(tx_info) \ + ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) + void ath_rate_attach(struct ath_softc *sc); u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index b2d0cca..93317ce 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -536,7 +536,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * just CTS. Note that this is only done for OFDM/HT unicast frames. */ if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK) - && (rt->info[rix].phy == WLAN_PHY_OFDM || + && (rt->info[rix].phy == WLAN_RC_PHY_OFDM || WLAN_RC_PHY_HT(rt->info[rix].phy))) { if (sc->sc_protmode == PROT_M_RTSCTS) flags = ATH9K_TXDESC_RTSENA; -- cgit v1.1 From 2c5a744d43a6a08666930906742fbe704739ba6f Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:08:33 +0530 Subject: ath9k: Use helpers Break down huge functions, use helper functions or macros instead. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 386 ++++++++++++++++++++-------------------- drivers/net/wireless/ath9k/rc.h | 5 + 2 files changed, 194 insertions(+), 197 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 51f51af..e118824 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -153,11 +153,6 @@ static struct ath_rate_table ar5416_11na_ratetable = { WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; -/* VALID_ALL - valid for 20/40/Legacy, - * VALID - Legacy only, - * VALID_20 - HT 20 only, - * VALID_40 - HT 40 only */ - /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ @@ -471,11 +466,10 @@ static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, return ath_rc_priv->valid_rate_index[index]; } -static inline int -ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) +static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, + u8 *next_idx) { u8 i; @@ -488,6 +482,7 @@ ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, /* No more valid rates */ *next_idx = 0; + return 0; } @@ -522,13 +517,13 @@ ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, return 1; } } + return 0; } -static u8 -ath_rc_sib_init_validrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - u32 capflag) +static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u32 capflag) { u8 i, hi = 0; u32 valid; @@ -552,14 +547,14 @@ ath_rc_sib_init_validrates(struct ath_rate_priv *ath_rc_priv, hi = A_MAX(hi, i); } } + return hi; } -static u8 -ath_rc_sib_setvalid_rates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - struct ath_rateset *rateset, - u32 capflag) +static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + struct ath_rateset *rateset, + u32 capflag) { u8 i, j, hi = 0; @@ -570,17 +565,17 @@ ath_rc_sib_setvalid_rates(struct ath_rate_priv *ath_rc_priv, u32 valid = (ath_rc_priv->single_stream ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; /* We allow a rate only if its valid and the * capflag matches one of the validity * (VALID/VALID_20/VALID_40) flags */ - if (((rateset->rs_rates[i] & 0x7F) == - (rate_table->info[j].dot11rate & 0x7F)) && - ((valid & WLAN_RC_CAP_MODE(capflag)) == - WLAN_RC_CAP_MODE(capflag)) && - !WLAN_RC_PHY_HT(phy)) { - + if (((rate & 0x7F) == (dot11rate & 0x7F)) && + ((valid & WLAN_RC_CAP_MODE(capflag)) == + WLAN_RC_CAP_MODE(capflag)) && + !WLAN_RC_PHY_HT(phy)) { u8 valid_rate_count = 0; if (!ath_rc_valid_phyrate(phy, capflag, 0)) @@ -597,27 +592,29 @@ ath_rc_sib_setvalid_rates(struct ath_rate_priv *ath_rc_priv, } } } + return hi; } -static u8 -ath_rc_sib_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, - u8 *mcs_set, u32 capflag) +static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u8 *mcs_set, u32 capflag) { + struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; + u8 i, j, hi = 0; /* Use intersection of working rates and valid rates */ - for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) { + for (i = 0; i < rateset->rs_nrates; i++) { 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); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; - if (((((struct ath_rateset *) - mcs_set)->rs_rates[i] & 0x7F) != - (rate_table->info[j].dot11rate & 0x7F)) || + if (((rate & 0x7F) != (dot11rate & 0x7F)) || !WLAN_RC_PHY_HT(phy) || !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; @@ -632,26 +629,8 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, hi = A_MAX(hi, j); } } - return hi; -} - -u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11rate) -{ - struct ath_rate_table *ratetable; - int i; - - ratetable = sc->hw_rate_table[sc->sc_curmode]; - - if (WARN_ON(!ratetable)) - return 0; - - for (i = 0; i < ratetable->rate_cnt; i++) { - if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f)) - return i; - } - return 0; + return hi; } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, @@ -784,9 +763,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , struct ieee80211_tx_rate *rate, - u8 tries, - u8 rix, - int rtsctsenable) + u8 tries, u8 rix, int rtsctsenable) { rate->count = tries; rate->idx = rix; @@ -911,15 +888,16 @@ static void ath_rc_ratefind(struct ath_softc *sc, } } -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ath_tx_info_priv *tx_info_priv, - int tx_rate, int xretries, int retries) +static bool ath_rc_update_per(struct ath_softc *sc, + struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries, + u32 now_msec) { - u32 now_msec = jiffies_to_msecs(jiffies); - int state_change = 0, rate, count; + bool state_change = false; + int count; u8 last_per; - struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; static u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, 100 * 1 / 4, @@ -933,24 +911,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, 100 * 9 / 10 }; - if (!ath_rc_priv) - return; - - ASSERT(tx_rate >= 0); - if (tx_rate < 0) - return; - - /* To compensate for some imbalance between ctrl and ext. channel */ - - if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - tx_info_priv->tx.ts_rssi = - tx_info_priv->tx.ts_rssi < 3 ? 0 : - tx_info_priv->tx.ts_rssi - 3; - last_per = ath_rc_priv->state[tx_rate].per; if (xretries) { - /* Update the PER. */ if (xretries == 1) { ath_rc_priv->state[tx_rate].per += 30; if (ath_rc_priv->state[tx_rate].per > 100) @@ -960,11 +923,10 @@ static void ath_rc_update_ht(struct ath_softc *sc, count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; + /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ ath_rc_priv->state[tx_rate].per = - (u8)(ath_rc_priv->state[tx_rate].per - - (ath_rc_priv->state[tx_rate].per >> 3) + - ((100) >> 3)); + (u8)(last_per - (last_per >> 3) + (100 >> 3)); } /* xretries == 1 or 2 */ @@ -972,12 +934,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (ath_rc_priv->probe_rate == tx_rate) ath_rc_priv->probe_rate = 0; - } else { /* xretries == 0 */ - /* Update the PER. */ - /* Make sure it doesn't index out of array's bounds. */ + } else { /* xretries == 0 */ count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; + if (tx_info_priv->n_bad_frames) { /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER @@ -991,22 +952,21 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the above PER. The expression below is a * simplified version of the sum of these two terms. */ - if (tx_info_priv->n_frames > 0) - ath_rc_priv->state[tx_rate].per - = (u8) - (ath_rc_priv->state[tx_rate].per - - (ath_rc_priv->state[tx_rate].per >> 3) + - ((100*(retries*tx_info_priv->n_frames + - tx_info_priv->n_bad_frames) / - (tx_info_priv->n_frames * - (retries+1))) >> 3)); + if (tx_info_priv->n_frames > 0) { + int n_frames, n_bad_frames; + u8 cur_per, new_per; + + n_bad_frames = retries * tx_info_priv->n_frames + + tx_info_priv->n_bad_frames; + n_frames = tx_info_priv->n_frames * (retries + 1); + cur_per = (100 * n_bad_frames / n_frames) >> 3; + new_per = (u8)(last_per - (last_per >> 3) + cur_per); + ath_rc_priv->state[tx_rate].per = new_per; + } } else { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - - ath_rc_priv->state[tx_rate].per = (u8) - (ath_rc_priv->state[tx_rate].per - - (ath_rc_priv->state[tx_rate].per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + + (nretry_to_per_lookup[retries] >> 3)); } ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; @@ -1018,7 +978,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, * If we got at most one retry then increase the max rate if * this was a probe. Otherwise, ignore the probe. */ - if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { if (retries > 0 || 2 * tx_info_priv->n_bad_frames > tx_info_priv->n_frames) { @@ -1033,7 +992,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, } else { u8 probe_rate = 0; - ath_rc_priv->rate_max_phy = ath_rc_priv->probe_rate; + ath_rc_priv->rate_max_phy = + ath_rc_priv->probe_rate; probe_rate = ath_rc_priv->probe_rate; if (ath_rc_priv->state[probe_rate].per > 30) @@ -1047,8 +1007,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, * to move up faster if the probes are * succesful. */ - ath_rc_priv->probe_time = now_msec - - rate_table->probe_interval / 2; + ath_rc_priv->probe_time = + now_msec - rate_table->probe_interval / 2; } } @@ -1064,6 +1024,10 @@ static void ath_rc_update_ht(struct ath_softc *sc, */ ath_rc_priv->hw_maxretry_pktcnt = 0; } else { + int32_t rssi_ackAvg; + int8_t rssi_thres; + int8_t rssi_ack_vmin; + /* * It worked with no retries. First ignore bogus (small) * rssi_ack values. @@ -1073,46 +1037,82 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->hw_maxretry_pktcnt++; } - if (tx_info_priv->tx.ts_rssi >= - rate_table->info[tx_rate].rssi_ack_validmin) { - /* Average the rssi */ - if (tx_rate != ath_rc_priv->rssi_sum_rate) { - ath_rc_priv->rssi_sum_rate = tx_rate; - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - } + if (tx_info_priv->tx.ts_rssi < + rate_table->info[tx_rate].rssi_ack_validmin) + goto exit; - ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_sum_cnt++; - - if (ath_rc_priv->rssi_sum_cnt > 4) { - int32_t rssi_ackAvg = - (ath_rc_priv->rssi_sum + 2) / 4; - int8_t rssi_thres = - ath_rc_priv->state[tx_rate]. - rssi_thres; - int8_t rssi_ack_vmin = - rate_table->info[tx_rate]. - rssi_ack_validmin; - - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - - /* Now reduce the current - * rssi threshold. */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - ath_rc_priv->state[tx_rate]. - rssi_thres--; - } - - state_change = 1; - } + /* Average the rssi */ + if (tx_rate != ath_rc_priv->rssi_sum_rate) { + ath_rc_priv->rssi_sum_rate = tx_rate; + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; + } + + ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_sum_cnt++; + + if (ath_rc_priv->rssi_sum_cnt < 4) + goto exit; + + rssi_ackAvg = + (ath_rc_priv->rssi_sum + 2) / 4; + rssi_thres = + ath_rc_priv->state[tx_rate].rssi_thres; + rssi_ack_vmin = + rate_table->info[tx_rate].rssi_ack_validmin; + + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; + + /* Now reduce the current rssi threshold */ + if ((rssi_ackAvg < rssi_thres + 2) && + (rssi_thres > rssi_ack_vmin)) { + ath_rc_priv->state[tx_rate].rssi_thres--; } + + state_change = true; } } +exit: + return state_change; +} + +/* Update PER, RSSI and whatever else that the code thinks it is doing. + If you can make sense of all this, you really need to go out more. */ - /* For all cases */ +static void ath_rc_update_ht(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries) +{ +#define CHK_RSSI(rate) \ + ((ath_rc_priv->state[(rate)].rssi_thres + \ + rate_table->info[(rate)].rssi_ack_deltamin) > \ + ath_rc_priv->state[(rate)+1].rssi_thres) + + u32 now_msec = jiffies_to_msecs(jiffies); + int rate; + u8 last_per; + bool state_change = false; + struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; + int size = ath_rc_priv->rate_table_size; + + if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) + return; + + /* To compensate for some imbalance between ctrl and ext. channel */ + + if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) + tx_info_priv->tx.ts_rssi = + tx_info_priv->tx.ts_rssi < 3 ? 0 : + tx_info_priv->tx.ts_rssi - 3; + + last_per = ath_rc_priv->state[tx_rate].per; + + /* Update PER first */ + state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info_priv, tx_rate, xretries, + retries, now_msec); /* * If this rate looks bad (high PER) then stop using it for @@ -1122,7 +1122,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_table->info[tx_rate].ratekbps <= rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - (u8) tx_rate, &ath_rc_priv->rate_max_phy); + (u8)tx_rate, &ath_rc_priv->rate_max_phy); /* Don't probe for a little while. */ ath_rc_priv->probe_time = now_msec; @@ -1136,20 +1136,15 @@ static void ath_rc_update_ht(struct ath_softc *sc, * made to keep the rssi thresholds monotonically * increasing between the CCK and OFDM rates.) */ - for (rate = tx_rate; rate < - ath_rc_priv->rate_table_size - 1; rate++) { + for (rate = tx_rate; rate < size - 1; rate++) { if (rate_table->info[rate+1].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; - if (ath_rc_priv->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - ath_rc_priv->state[rate+1].rssi_thres) { + if (CHK_RSSI(rate)) { ath_rc_priv->state[rate+1].rssi_thres = - ath_rc_priv->state[rate]. - rssi_thres + - rate_table->info[rate]. - rssi_ack_deltamin; + ath_rc_priv->state[rate].rssi_thres + + rate_table->info[rate].rssi_ack_deltamin; } } @@ -1159,27 +1154,20 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_table->info[tx_rate].phy) break; - if (ath_rc_priv->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - ath_rc_priv->state[rate+1].rssi_thres) { + if (CHK_RSSI(rate)) { if (ath_rc_priv->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) + rate_table->info[rate].rssi_ack_deltamin) ath_rc_priv->state[rate].rssi_thres = 0; else { ath_rc_priv->state[rate].rssi_thres = - ath_rc_priv->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + ath_rc_priv->state[rate+1].rssi_thres - + rate_table->info[rate].rssi_ack_deltamin; } if (ath_rc_priv->state[rate].rssi_thres < - rate_table->info[rate]. - rssi_ack_validmin) { + rate_table->info[rate].rssi_ack_validmin) { ath_rc_priv->state[rate].rssi_thres = - rate_table->info[rate]. - rssi_ack_validmin; + rate_table->info[rate].rssi_ack_validmin; } } } @@ -1202,8 +1190,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, } /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < ath_rc_priv->rate_table_size - 1; rate++) { - if (ath_rc_priv->state[rate+1].per < ath_rc_priv->state[rate].per) + for (rate = tx_rate; rate < size - 1; rate++) { + if (ath_rc_priv->state[rate+1].per < + ath_rc_priv->state[rate].per) ath_rc_priv->state[rate+1].per = ath_rc_priv->state[rate].per; } @@ -1213,7 +1202,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (now_msec - ath_rc_priv->rssi_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < ath_rc_priv->rate_table_size; rate++) { + for (rate = 0; rate < size; rate++) { if (ath_rc_priv->state[rate].rssi_thres > rate_table->info[rate].rssi_ack_validmin) ath_rc_priv->state[rate].rssi_thres -= 1; @@ -1225,13 +1214,33 @@ static void ath_rc_update_ht(struct ath_softc *sc, * and PER (different for CCK and OFDM). */ if (now_msec - ath_rc_priv->per_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < ath_rc_priv->rate_table_size; rate++) { + for (rate = 0; rate < size; rate++) { ath_rc_priv->state[rate].per = 7 * ath_rc_priv->state[rate].per / 8; } ath_rc_priv->per_down_time = now_msec; } + +#undef CHK_RSSI +} + +static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate) +{ + int rix; + + if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (rate->flags & IEEE80211_TX_RC_SHORT_GI)) + rix = rate_table->info[rate->idx].ht_index; + else if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rix = rate_table->info[rate->idx].sgi_index; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rix = rate_table->info[rate->idx].cw40index; + else + rix = rate_table->info[rate->idx].base_index; + + return rix; } static void ath_rc_tx_status(struct ath_softc *sc, @@ -1243,7 +1252,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, struct ath_rate_table *rate_table; struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; - u32 series = 0, rix; + u32 i = 0, rix; rate_table = sc->hw_rate_table[sc->sc_curmode]; @@ -1253,32 +1262,22 @@ static void ath_rc_tx_status(struct ath_softc *sc, */ if (final_ts_idx != 0) { /* Process intermediate rates that failed.*/ - for (series = 0; series < final_ts_idx ; series++) { - if (rates[series].count != 0 && (rates[series].idx >= 0)) { - flags = rates[series].flags; + for (i = 0; i < final_ts_idx ; i++) { + if (rates[i].count != 0 && (rates[i].idx >= 0)) { + flags = rates[i].flags; + /* If HT40 and we have switched mode from * 40 to 20 => don't update */ + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) return; - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (flags & IEEE80211_TX_RC_SHORT_GI)) - rix = rate_table->info[ - rates[series].idx].ht_index; - else if (flags & IEEE80211_TX_RC_SHORT_GI) - rix = rate_table->info[ - rates[series].idx].sgi_index; - else if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - rix = rate_table->info[ - rates[series].idx].cw40index; - else - rix = rate_table->info[ - rates[series].idx].base_index; + rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, xretries ? 1 : 2, - rates[series].count); + rates[i].count); } } } else { @@ -1292,24 +1291,17 @@ static void ath_rc_tx_status(struct ath_softc *sc, xretries = 2; } - flags = rates[series].flags; + flags = rates[i].flags; + /* If HT40 and we have switched mode from 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { return; } - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (flags & IEEE80211_TX_RC_SHORT_GI)) - rix = rate_table->info[rates[series].idx].ht_index; - else if (flags & IEEE80211_TX_RC_SHORT_GI) - rix = rate_table->info[rates[series].idx].sgi_index; - else if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - rix = rate_table->info[rates[series].idx].cw40index; - else - rix = rate_table->info[rates[series].idx].base_index; - + rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, - xretries, long_retry); + xretries, long_retry); } static void ath_rc_init(struct ath_softc *sc, @@ -1362,14 +1354,14 @@ static void ath_rc_init(struct ath_softc *sc, if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ - hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table, + hi = ath_rc_init_validrates(ath_rc_priv, rate_table, ath_rc_priv->ht_cap); } else { /* Use intersection of working rates and valid rates */ - hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table, + hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table, rateset, ath_rc_priv->ht_cap); if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { - hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv, + hthi = ath_rc_setvalid_htrates(ath_rc_priv, rate_table, ht_mcs, ath_rc_priv->ht_cap); diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index dff4b7a..297dff9 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -27,6 +27,11 @@ struct ath_softc; #define RATE_TABLE_SIZE 64 #define MAX_TX_RATE_PHY 48 +/* VALID_ALL - valid for 20/40/Legacy, + * VALID - Legacy only, + * VALID_20 - HT 20 only, + * VALID_40 - HT 40 only */ + #define INVALID 0x0 #define VALID 0x1 #define VALID_20 0x2 -- cgit v1.1 From c428839008f6638317a0db102d4e65d631c288a6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:09:30 +0530 Subject: ath9k: Move TX completion routine to xmit.c Also, use a helper function to setup RC status data when processing completed TX descriptors. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 2 - drivers/net/wireless/ath9k/main.c | 31 -------------- drivers/net/wireless/ath9k/xmit.c | 88 +++++++++++++++++++++++++-------------- 3 files changed, 56 insertions(+), 65 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 0c34820..e672556 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -453,8 +453,6 @@ void ath_tx_tasklet(struct ath_softc *sc); u32 ath_txq_depth(struct ath_softc *sc, int qnum); 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); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /**********************/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 9a79824..54d89ab 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -341,37 +341,6 @@ void ath_get_beaconconfig(struct ath_softc *sc, conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; } -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - - DPRINTF(sc, ATH_DBG_XMIT, - "%s: TX complete: skb: %p\n", __func__, skb); - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; - } - - if (tx_status->flags & ATH_TX_BAR) { - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - tx_status->flags &= ~ATH_TX_BAR; - } - - if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } - - tx_info->status.rates[0].count = tx_status->retries + 1; - - ieee80211_tx_status(hw, skb); -} - /********************************/ /* LED functions */ /********************************/ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 93317ce..4c9a03e 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -102,6 +102,37 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, ath9k_hw_txstart(ah, txq->axq_qnum); } +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + struct ath_xmit_status *tx_status) +{ + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + + DPRINTF(sc, ATH_DBG_XMIT, + "%s: TX complete: skb: %p\n", __func__, skb); + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + } + + if (tx_status->flags & ATH_TX_BAR) { + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + tx_status->flags &= ~ATH_TX_BAR; + } + + if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + tx_info->status.rates[0].count = tx_status->retries + 1; + + ieee80211_tx_status(hw, skb); +} + /* Check if it's okay to send out aggregates */ static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) @@ -913,18 +944,35 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, return; } +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { + if (bf_isdata(bf)) { + memcpy(&tx_info_priv->tx, &ds->ds_txstat, + sizeof(tx_info_priv->tx)); + tx_info_priv->n_frames = bf->bf_nframes; + tx_info_priv->n_bad_frames = nbad; + } + } +} + /* Process completed xmit descriptors from the specified queue */ -static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) +static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf, *lastbf, *bf_held = NULL; struct list_head bf_head; - struct ath_desc *ds, *tmp_ds; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; - int nacked, txok, nbad = 0, isrifs = 0; + struct ath_desc *ds; + int txok, nbad = 0; int status; DPRINTF(sc, ATH_DBG_QUEUE, @@ -932,7 +980,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); - nacked = 0; for (;;) { spin_lock_bh(&txq->axq_lock); if (list_empty(&txq->axq_q)) { @@ -1022,30 +1069,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } else { nbad = ath_tx_num_badfrms(sc, bf, txok); } - skb = bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - - tx_info_priv = - (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { - if (ds->ds_txstat.ts_status == 0) - nacked++; - - if (bf_isdata(bf)) { - if (isrifs) - tmp_ds = bf->bf_rifslast->bf_desc; - else - tmp_ds = ds; - memcpy(&tx_info_priv->tx, - &tmp_ds->ds_txstat, - sizeof(tx_info_priv->tx)); - tx_info_priv->n_frames = bf->bf_nframes; - tx_info_priv->n_bad_frames = nbad; - } - } + + ath_tx_rc_status(bf, ds, nbad); /* * Complete this transmit unit @@ -1076,7 +1101,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } - return nacked; } static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) -- cgit v1.1 From 788a3d6f3df595a6537ef537433c870d090afe02 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:09:54 +0530 Subject: ath9k: Fix bug in deciphering channel flags CHANNEL_CCK flag is set for all 2 Ghz channels, so IS_CHAN_CCK() would turn out to be true for all channles in that band. Use IS_CHAN_B() now, which checks the channel mode and not the channel flags. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 3 +-- drivers/net/wireless/ath9k/hw.c | 11 ++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 6b0e3dd..5b9bc54 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -476,12 +476,10 @@ struct ath9k_channel { (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) -#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B) #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0) #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) @@ -490,6 +488,7 @@ struct ath9k_channel { #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) /* These macros check chanmode and not channelFlags */ +#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ ((_c)->chanmode == CHANNEL_G_HT20)) #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index eb14451..10f6c08 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -86,10 +86,11 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, const struct ath9k_channel *chan) { - if (IS_CHAN_CCK(chan)) - return ATH9K_MODE_11A; + if (IS_CHAN_B(chan)) + return ATH9K_MODE_11B; if (IS_CHAN_G(chan)) return ATH9K_MODE_11G; + return ATH9K_MODE_11A; } @@ -909,7 +910,7 @@ static void ath9k_hw_init_bb(struct ath_hal *ah, u32 synthDelay; synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) + if (IS_CHAN_B(chan)) synthDelay = (4 * synthDelay) / 22; else synthDelay /= 10; @@ -1647,7 +1648,7 @@ static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, } if (!IS_CHAN_OFDM(chan) && - !IS_CHAN_CCK(chan) && + !IS_CHAN_B(chan) && !IS_CHAN_HT20(chan) && !IS_CHAN_HT40(chan)) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, @@ -1711,7 +1712,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, } synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) + if (IS_CHAN_B(chan)) synthDelay = (4 * synthDelay) / 22; else synthDelay /= 10; -- cgit v1.1 From daa9deb359252496796fa2b7420012e252b327b6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:10:22 +0530 Subject: ath9k: Update TX trigger level on a FIFO underrun. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index c344a81..36955e0 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -293,8 +293,10 @@ int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; if (ads->ds_txstatus1 & AR_Filtered) ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) + if (ads->ds_txstatus1 & AR_FIFOUnderrun) { ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } if (ads->ds_txstatus9 & AR_TxOpExceeded) ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; if (ads->ds_txstatus1 & AR_TxTimerExpired) -- cgit v1.1 From 8f93b8b337763a58fcdf23333ffe752db6c93bae Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Nov 2008 09:10:42 +0530 Subject: ath9k: Use straightforward PCI routines to setup the TX buffer. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 4c9a03e..50d4105 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1646,7 +1646,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, } static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, - struct sk_buff *skb, struct scatterlist *sg, + struct sk_buff *skb, struct ath_tx_control *txctl) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1711,7 +1711,6 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, /* FIXME: tx power */ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, - struct scatterlist *sg, u32 n_sg, struct ath_tx_control *txctl) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; @@ -1740,10 +1739,10 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, bf->bf_keyix, bf->bf_keytype, bf->bf_flags); ath9k_hw_filltxdesc(ah, ds, - sg_dma_len(sg), /* segment length */ - true, /* first segment */ - (n_sg == 1) ? true : false, /* last segment */ - ds); /* first descriptor */ + skb->len, /* segment length */ + true, /* first segment */ + true, /* last segment */ + ds); /* first descriptor */ bf->bf_lastfrm = bf; @@ -1783,7 +1782,6 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, struct ath_tx_control *txctl) { struct ath_buf *bf; - struct scatterlist sg; /* Check if a tx buffer is available */ @@ -1794,15 +1792,8 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, return -1; } - ath_tx_setup_buffer(sc, bf, skb, &sg, txctl); - - /* Setup S/G */ - - memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = bf->bf_dmacontext; - sg_dma_len(&sg) = skb->len; - - ath_tx_start_dma(sc, bf, &sg, 1, txctl); + ath_tx_setup_buffer(sc, bf, skb, txctl); + ath_tx_start_dma(sc, bf, txctl); return 0; } -- cgit v1.1 From 0e149cf5a1b1900484f4b808d59a5f246cd720be Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 17 Nov 2008 23:40:38 -0500 Subject: ath5k: set mac address in add_interface Configure the mac address in add_interface and clear it in remove_interface so that users can change the mac address to something other than the one in the eeprom. Also avoid setting it at attach time so that we won't ack packets until fully set up. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/attach.c | 12 +++--------- drivers/net/wireless/ath5k/base.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 51d5698..49d82d7 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; - u8 mac[ETH_ALEN]; + u8 mac[ETH_ALEN] = {}; int ret; u32 srev; @@ -317,15 +317,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } - /* Set MAC address */ - ret = ath5k_eeprom_read_mac(ah, mac); - if (ret) { - ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", - sc->pdev->device); - goto err_free; - } - + /* MAC address is cleared until add_interface */ ath5k_hw_set_lladdr(ah, mac); + /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memset(ah->ah_bssid, 0xff, ETH_ALEN); ath5k_hw_set_associd(ah, ah->ah_bssid, 0); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 7fdb59c..4bcea5a 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -707,7 +707,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - u8 mac[ETH_ALEN]; + u8 mac[ETH_ALEN] = {}; int ret; ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); @@ -777,7 +777,13 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); - ath5k_hw_get_lladdr(ah, mac); + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_queues; + } + SET_IEEE80211_PERM_ADDR(hw, mac); /* All MAC address bits matter for ACKs */ memset(sc->bssidmask, 0xff, ETH_ALEN); @@ -2765,6 +2771,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, /* Set to a reasonable value. Note that this will * be set to mac80211's value at ath5k_config(). */ sc->bintval = 1000; + ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); ret = 0; end: @@ -2777,11 +2784,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath5k_softc *sc = hw->priv; + u8 mac[ETH_ALEN] = {}; mutex_lock(&sc->lock); if (sc->vif != conf->vif) goto end; + ath5k_hw_set_lladdr(sc->ah, mac); sc->vif = NULL; end: mutex_unlock(&sc->lock); -- cgit v1.1 From ce546fd2eacdbd8dc15f3d2ffd9a95661d082919 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 19 Nov 2008 15:32:22 -0800 Subject: iwl3945 : Fix ad-hoc mode for 3945 Patch fixes the ad-hoc mode by 1) Removing redundant clear_stations_table which prevented generation of beacons. 2) Setting assoc_id to 1. It was never set so preventing tx flow in iwl3945_tx_skb. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9330dfa..69fda64 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6321,10 +6321,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) case NL80211_IFTYPE_ADHOC: - /* clear out the station table */ - iwl3945_clear_stations_table(priv); - - iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); + priv->assoc_id = 1; iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? -- cgit v1.1 From 83dde8c90522b89366e241bdbd69113f7094c249 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 19 Nov 2008 15:32:23 -0800 Subject: iwlwifi: move iwl_clear_stations_table to iwl-sta.c This patch moves iwl_clear_stations_table into iwl-sta.c Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 23 +---------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-sta.c | 23 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.h | 1 + 4 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fccd150..6aa332b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -37,6 +37,7 @@ #include "iwl-io.h" #include "iwl-rfkill.h" #include "iwl-power.h" +#include "iwl-sta.h" MODULE_DESCRIPTION("iwl core"); @@ -237,28 +238,6 @@ int iwl_hw_nic_init(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_nic_init); -/** - * iwl_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -void iwl_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (iwl_is_alive(priv) && - !test_bit(STATUS_EXIT_PENDING, &priv->status) && - iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) - IWL_ERROR("Couldn't clear the station table\n"); - - priv->num_stations = 0; - memset(priv->stations, 0, sizeof(priv->stations)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} -EXPORT_SYMBOL(iwl_clear_stations_table); void iwl_reset_qos(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 5d4e2e2..82bf263 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -182,7 +182,6 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); void iwl_hw_detect(struct iwl_priv *priv); -void iwl_clear_stations_table(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 109136a..f86a8ca2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -463,6 +463,29 @@ out: } EXPORT_SYMBOL(iwl_remove_station); +/** + * iwl_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ +void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (iwl_is_alive(priv) && + !test_bit(STATUS_EXIT_PENDING, &priv->status) && + iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) + IWL_ERROR("Couldn't clear the station table\n"); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} +EXPORT_SYMBOL(iwl_clear_stations_table); + static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 61eede5..7b98ea4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -53,6 +53,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, -- cgit v1.1 From 201706ac0b1ab6df5343119883964ec7272844b0 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 19 Nov 2008 15:32:24 -0800 Subject: iwlwifi: enable base band calibration in 5000 HW This patch adds base band calibration support. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++++++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index aeb69ee..478c5c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -475,6 +475,9 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD: index = IWL_CALIB_TX_IQ_PERD; break; + case IWL_PHY_CALIBRATE_BASE_BAND_CMD: + index = IWL_CALIB_BASE_BAND; + break; default: IWL_ERROR("Unknown calibration notification %d\n", hdr->op_code); @@ -841,8 +844,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | - BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_TX_IQ_PERD); + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD) | + BIT(IWL_CALIB_BASE_BAND); break; case CSR_HW_REV_TYPE_5150: priv->hw_params.calib_init_cfg = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1b305d8..4da988e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -695,6 +695,7 @@ enum iwl_calib { IWL_CALIB_LO, IWL_CALIB_TX_IQ, IWL_CALIB_TX_IQ_PERD, + IWL_CALIB_BASE_BAND, IWL_CALIB_MAX }; -- cgit v1.1 From 25e35a56d5f4795cf52cdd0830a91e3103396cfe Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 19 Nov 2008 15:32:25 -0800 Subject: iwlwifi: 4965 define firmware file name once Apply same idiom as in 5000 introduced by 'iwlwifi: define firmware file name once' Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9007ff2..b96f553 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -53,6 +53,7 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); * is not compatible with earlier drivers. * This number will also appear in << 8 position of 1st dword of uCode file */ #define IWL4965_UCODE_API "-2" +#define IWL4965_MODULE_FIRMWARE "iwlwifi-4965" IWL4965_UCODE_API ".ucode" /* module parameters */ @@ -2322,7 +2323,7 @@ static struct iwl_ops iwl4965_ops = { struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", - .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", + .fw_name = IWL4965_MODULE_FIRMWARE, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .eeprom_size = IWL4965_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_4965_EEPROM_VERSION, @@ -2332,7 +2333,7 @@ struct iwl_cfg iwl4965_agn_cfg = { }; /* Module firmware */ -MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE); module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -- cgit v1.1 From 31a73fe4f3284d94d52774c285e9e98a5f441d21 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 19 Nov 2008 15:32:26 -0800 Subject: iwlwifi: TX setup fix confusion between TX queue and TX DMA channel This patch configures correctly TX DMA channel. It is not the same as TX queue. Signed-off-by: Tomas Winkler Acked-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 ++++++++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 9 ++++++++- drivers/net/wireless/iwlwifi/iwl-tx.c | 5 ----- 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b96f553..60769b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -692,9 +692,9 @@ static const u16 default_queue_to_tx_fifo[] = { static int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; - int i = 0; unsigned long flags; int ret; + int i, chan; spin_lock_irqsave(&priv->lock, flags); @@ -718,6 +718,12 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, priv->scd_bc_tbls.dma >> 10); + /* Enable DMA channel */ + for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + /* Disable chain mode for all queues */ iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); @@ -748,7 +754,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) (1 << priv->hw_params.max_txq_num) - 1); /* Activate all Tx DMA/FIFO channels */ - priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 478c5c3..d73760c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -700,9 +700,9 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv) static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; - int i = 0; unsigned long flags; int ret; + int i, chan; spin_lock_irqsave(&priv->lock, flags); @@ -725,6 +725,13 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, priv->scd_bc_tbls.dma >> 10); + + /* Enable DMA channel */ + for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9f0705b..e045dfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -449,11 +449,6 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv, iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); - /* Enable DMA channel, using same id as for TFD queue */ - iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.1 From 40fc95d57caf258e20282f6526b695426d65a73a Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 19 Nov 2008 15:32:27 -0800 Subject: iwlwifi: TX update chicken bits This instructs FH to increment the retry count of a packet when it is brought from the memory to TX-FIFO to save transactions during aggregation flow. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-fh.h | 5 +++++ 3 files changed, 17 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 60769b1..ab0b4053 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -695,6 +695,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) unsigned long flags; int ret; int i, chan; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -724,6 +725,11 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + /* Disable chain mode for all queues */ iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d73760c..a738886 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -703,6 +703,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) unsigned long flags; int ret; int i, chan; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -732,6 +733,11 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index bc20acb..c3dadb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -396,6 +396,11 @@ #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) +#define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98) +/* Instruct FH to increment the retry count of a packet when + * it is brought from the memory to TX-FIFO + */ +#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) /** * struct iwl_rb_status - reseve buffer status -- cgit v1.1 From 7ac47010a444d9f4285cf1ae06780633a112489b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 20 Nov 2008 11:51:18 +0530 Subject: ath9k: Dont update rate control for every AMPDU Update the rate control only with the tx status of first AMPDU of an aggregation. This patch fixes frequent drops in throughput. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 3 ++- drivers/net/wireless/ath9k/rc.h | 1 + drivers/net/wireless/ath9k/xmit.c | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index e118824..7d1913d 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1413,7 +1413,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, an = (struct ath_node *)sta->drv_priv; final_ts_idx = tx_info_priv->tx.ts_rateindex; - if (!an || !priv_sta || !ieee80211_is_data(fc)) + if (!an || !priv_sta || !ieee80211_is_data(fc) || + !tx_info_priv->update_rc) goto exit; if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 297dff9..97c60d1 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -188,6 +188,7 @@ struct ath_tx_info_priv { struct ath_tx_status tx; int n_frames; int n_bad_frames; + bool update_rc; }; #define ATH_TX_INFO_PRIV(tx_info) \ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 50d4105..dad81a9 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -950,6 +950,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + tx_info_priv->update_rc = false; if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; @@ -960,6 +961,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) sizeof(tx_info_priv->tx)); tx_info_priv->n_frames = bf->bf_nframes; tx_info_priv->n_bad_frames = nbad; + tx_info_priv->update_rc = true; } } } -- cgit v1.1 From 1048643ea94d742bd409f343e284af430656fd6c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 20 Nov 2008 15:16:22 +0100 Subject: ath5k: Clean up eeprom parsing and add missing calibration data This patch brings the ath5k eeprom parsing code in sync with the work done on ath_info by Nick Kossifidis and integrates the missing parts based on the code of the Atheros Legacy HAL release. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 7 - drivers/net/wireless/ath5k/eeprom.c | 1194 ++++++++++++++++++++++++++++++----- drivers/net/wireless/ath5k/eeprom.h | 253 ++++++-- drivers/net/wireless/ath5k/reset.c | 2 +- 4 files changed, 1264 insertions(+), 192 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index a725bb9..5ee2dd1 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -821,13 +821,6 @@ struct ath5k_athchan_2ghz { return (false); \ } while (0) -enum ath5k_ant_setting { - AR5K_ANT_VARIABLE = 0, /* variable by programming */ - AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ - AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, -}; - /* * Hardware interrupt abstraction */ diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index a883839..1cb7edf 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath5k/eeprom.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004-2008 Reyk Floeter * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2008 Felix Fietkau * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) /* * Translate binary channel representation in EEPROM to frequency */ -static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, - unsigned int mode) +static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin, + unsigned int mode) { u16 val; @@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, return bin; if (mode == AR5K_EEPROM_MODE_11A) { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) val = (5 * bin) + 4800; else val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : (bin * 10) + 5100; } else { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) val = bin + 2300; else val = bin + 2400; @@ -88,6 +89,71 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, } /* + * Initialize eeprom & capabilities structs + */ +static int +ath5k_eeprom_init_header(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int ret; + u16 val; + + /* Initial TX thermal adjustment values */ + ee->ee_tx_clip = 4; + ee->ee_pwd_84 = ee->ee_pwd_90 = 1; + ee->ee_gain_select = 1; + + /* + * Read values from EEPROM and store them in the capability structure + */ + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + + /* Return if we have an old EEPROM */ + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) + return 0; + +#ifdef notyet + /* + * Validate the checksum of the EEPROM date. There are some + * devices with invalid EEPROMs. + */ + for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { + AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); + cksum ^= val; + } + if (cksum != AR5K_EEPROM_INFO_CKSUM) { + ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); + return -EIO; + } +#endif + + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), + ee_ant_gain); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; + } + + return 0; +} + + +/* * Read antenna infos from eeprom */ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, @@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, AR5K_EEPROM_READ(o++, val); ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; - ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f; ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; AR5K_EEPROM_READ(o++, val); @@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, u16 val; int ret; + ee->ee_n_piers[mode] = 0; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + ee->ee_ob[mode][3] = (val >> 5) & 0x7; + ee->ee_db[mode][3] = (val >> 2) & 0x7; + ee->ee_ob[mode][2] = (val << 1) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ob[mode][2] |= (val >> 15) & 0x1; + ee->ee_db[mode][2] = (val >> 12) & 0x7; + ee->ee_ob[mode][1] = (val >> 9) & 0x7; + ee->ee_db[mode][1] = (val >> 6) & 0x7; + ee->ee_ob[mode][0] = (val >> 3) & 0x7; + ee->ee_db[mode][0] = val & 0x7; + break; + case AR5K_EEPROM_MODE_11G: + case AR5K_EEPROM_MODE_11B: + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + break; + } + AR5K_EEPROM_READ(o++, val); ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; ee->ee_thr_62[mode] = val & 0xff; @@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, AR5K_EEPROM_READ(o++, val); ee->ee_i_gain[mode] |= (val << 3) & 0x38; - if (mode == AR5K_EEPROM_MODE_11G) + if (mode == AR5K_EEPROM_MODE_11G) { ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + } } if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && @@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_q_cal[mode] = (val >> 3) & 0x1f; } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && - mode == AR5K_EEPROM_MODE_11G) - ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0) + goto done; + + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) + break; + + AR5K_EEPROM_READ(o++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + break; + case AR5K_EEPROM_MODE_11B: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_b[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_b[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_b[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + break; + case AR5K_EEPROM_MODE_11G: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_g[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_g[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_g[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(o++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + break; + } + +done: /* return new offset */ *offset = o; @@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, } /* - * Initialize eeprom & capabilities structs + * Read turbo mode information on newer EEPROM versions */ -int ath5k_eeprom_init(struct ath5k_hw *ah) +static int +ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, + u32 *offset, unsigned int mode) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - unsigned int mode, i; - int ret; - u32 offset; + u32 o = *offset; u16 val; + int ret; - /* Initial TX thermal adjustment values */ - ee->ee_tx_clip = 4; - ee->ee_pwd_84 = ee->ee_pwd_90 = 1; - ee->ee_gain_select = 1; + if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) + return 0; - /* - * Read values from EEPROM and store them in the capability structure - */ - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + switch (mode){ + case AR5K_EEPROM_MODE_11A: + ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; - /* Return if we have an old EEPROM */ - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) - return 0; + ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; + ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; + + if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) + ee->ee_pd_gain_overlap = (val >> 9) & 0xf; + break; + case AR5K_EEPROM_MODE_11G: + ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f; + + ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5; + ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff; + break; + } + + /* return new offset */ + *offset = o; + + return 0; +} + + +static int +ath5k_eeprom_init_modes(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 mode_offset[3]; + unsigned int mode; + u32 offset; + int ret; -#ifdef notyet /* - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. + * Get values for all modes */ - for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { - AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); - cksum ^= val; + mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + offset = mode_offset[mode]; + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); + if (ret) + return ret; } - if (cksum != AR5K_EEPROM_INFO_CKSUM) { - ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); - return -EIO; + + /* override for older eeprom versions for better performance */ + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) { + ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15; + ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28; + ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28; } -#endif - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), - ee_ant_gain); + return 0; +} - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); - } +static inline void +ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) +{ + const static u16 intercepts3[] = + { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; + const static u16 intercepts3_2[] = + { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; + const u16 *ip; + int i; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) + ip = intercepts3_2; + else + ip = intercepts3; - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + for (i = 0; i < ARRAY_SIZE(intercepts3); i++) + *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; +} - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; +static inline int +ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, + struct ath5k_chan_pcal_info *pc, u8 *count) +{ + int o = *offset; + int i = 0; + u8 f1, f2; + int ret; + u16 val; + + while(i < max) { + AR5K_EEPROM_READ(o++, val); + + f1 = (val >> 8) & 0xff; + f2 = val & 0xff; + + if (f1) + pc[i++].freq = f1; + + if (f2) + pc[i++].freq = f2; + + if (!f1 || !f2) + break; } + *offset = o; + *count = i; - /* - * Get conformance test limit values - */ - offset = AR5K_EEPROM_CTL(ah->ah_ee_version); - ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); + return 0; +} + +static int +ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; + int i, ret; + u16 val; + u8 mask; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_5GHZ_CHAN, pcal, + &ee->ee_n_piers[AR5K_EEPROM_MODE_11A]); + } else { + mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); - for (i = 0; i < ee->ee_ctls; i++) { AR5K_EEPROM_READ(offset++, val); - ee->ee_ctl[i] = (val >> 8) & 0xff; - ee->ee_ctl[i + 1] = val & 0xff; + pcal[0].freq = (val >> 9) & mask; + pcal[1].freq = (val >> 2) & mask; + pcal[2].freq = (val << 5) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[2].freq |= (val >> 11) & 0x1f; + pcal[3].freq = (val >> 4) & mask; + pcal[4].freq = (val << 3) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[4].freq |= (val >> 13) & 0x7; + pcal[5].freq = (val >> 6) & mask; + pcal[6].freq = (val << 1) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[6].freq |= (val >> 15) & 0x1; + pcal[7].freq = (val >> 8) & mask; + pcal[8].freq = (val >> 1) & mask; + pcal[9].freq = (val << 6) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[9].freq |= (val >> 10) & 0x3f; + ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; } - /* - * Get values for 802.11a (5GHz) - */ - mode = AR5K_EEPROM_MODE_11A; + for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, AR5K_EEPROM_MODE_11A); + } - ee->ee_turbo_max_power[mode] = - AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + return 0; +} - offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); +static inline int +ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int i; + + switch(mode) { + case AR5K_EEPROM_MODE_11B: + pcal = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + pcal = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, + &ee->ee_n_piers[mode]); + for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, mode); + } - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][3] = (val >> 5) & 0x7; - ee->ee_db[mode][3] = (val >> 2) & 0x7; - ee->ee_ob[mode][2] = (val << 1) & 0x7; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_ob[mode][2] |= (val >> 15) & 0x1; - ee->ee_db[mode][2] = (val >> 12) & 0x7; - ee->ee_ob[mode][1] = (val >> 9) & 0x7; - ee->ee_db[mode][1] = (val >> 6) & 0x7; - ee->ee_ob[mode][0] = (val >> 3) & 0x7; - ee->ee_db[mode][0] = val & 0x7; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + return 0; +} - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_margin_tx_rx[mode] = val & 0x3f; + +static int +ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int offset, ret; + int i, j; + u16 val; + + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ret = ath5k_eeprom_init_11a_pcal_freq(ah, + offset + AR5K_EEPROM_GROUP1_OFFSET); + if (ret < 0) + return ret; + + offset += AR5K_EEPROM_GROUP2_OFFSET; + pcal = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header) && + !AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_b; + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2412; + pcal[1].freq = 2447; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_g; + offset += AR5K_EEPROM_GROUP4_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2312; + pcal[1].freq = 2412; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + default: + return -EINVAL; } - /* - * Get values for 802.11b (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11B; - offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + struct ath5k_chan_pcal_info_rf5111 *cdata = + &pcal[i].rf5111_info; - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + AR5K_EEPROM_READ(offset++, val); + cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M); + cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M); + cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M); - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[0] |= ((val >> 14) & 0x3); + cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M); + cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M); - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[3] |= ((val >> 12) & 0xf); + cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M); + cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M); - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M); + cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M); + cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M); AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + cdata->pwr[8] |= ((val >> 14) & 0x3); + cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M); + + ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min, + cdata->pcdac_max, cdata->pcdac); + + for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) { + cdata->pwr[j] = (u16) + (AR5K_EEPROM_POWER_STEP * cdata->pwr[j]); + } } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + return 0; +} - /* - * Get values for 802.11g (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11G; - offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); +static int +ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + u32 offset; + unsigned int i, c; + u16 val; + int ret; - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + /* + * Read 5GHz EEPROM channels + */ + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + + offset += AR5K_EEPROM_GROUP2_OFFSET; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP4_OFFSET; + else if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += AR5K_EEPROM_GROUP2_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf5112_info; - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + /* Power values in dBm * 4 + * for the lower xpd gain curve + * (0 dBm -> higher output power) */ + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_x0[c] = (val & 0xff); + chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff); + } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + /* PCDAC steps + * corresponding to the above power + * measurements */ AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + chan_pcal_info->pcdac_x0[1] = (val & 0x1f); + chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); + chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); + /* Power values in dBm * 4 + * for the higher xpd gain curve + * (18 dBm -> lower output power) */ AR5K_EEPROM_READ(offset++, val); - ee->ee_turbo_max_power[mode] = val & 0x7f; - ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + chan_pcal_info->pwr_x3[0] = (val & 0xff); + chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff); AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + chan_pcal_info->pwr_x3[2] = (val & 0xff); + + /* PCDAC steps + * corresponding to the above power + * measurements (static) */ + chan_pcal_info->pcdac_x3[0] = 20; + chan_pcal_info->pcdac_x3[1] = 35; + chan_pcal_info->pcdac_x3[2] = 63; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { + chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff); + + /* Last xpd0 power level is also channel maximum */ + gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; + } else { + chan_pcal_info->pcdac_x0[0] = 1; + gen_chan_info[i].max_pwr = ((val >> 8) & 0xff); + } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + /* Recreate pcdac_x0 table for this channel using pcdac steps */ + chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0]; + chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1]; + chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2]; + } + + return 0; +} + +static inline unsigned int +ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) +{ + static const unsigned int pdgains_size[] = { 4, 6, 9, 12 }; + unsigned int sz; + + sz = pdgains_size[ee->ee_pd_gains[mode] - 1]; + sz *= ee->ee_n_piers[mode]; + + return sz; +} + +static unsigned int +ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) +{ + u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); + + switch(mode) { + case AR5K_EEPROM_MODE_11G: + if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2; + /* fall through */ + case AR5K_EEPROM_MODE_11B: + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5; + /* fall through */ + case AR5K_EEPROM_MODE_11A: + break; + default: + break; + } + + return offset; +} + +static int +ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + unsigned int i, c; + u32 offset; + int ret; + u16 val; + u8 pd_gains = 0; + + if (ee->ee_x_gain[mode] & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; + ee->ee_pd_gains[mode] = pd_gains; + + offset = ath5k_cal_data_offset_2413(ee, mode); + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + if (pd_gains == 0) + return 0; + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf2413_info; + + /* + * Read pwr_i, pddac_i and the first + * 2 pd points (pwr, pddac) + */ AR5K_EEPROM_READ(offset++, val); - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + chan_pcal_info->pwr_i[0] = val & 0x1f; + chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; + chan_pcal_info->pwr[0][0] = + (val >> 12) & 0xf; - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[0][0] = val & 0x3f; + chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; + chan_pcal_info->pddac[0][1] = + (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[0][2] = val & 0xf; + chan_pcal_info->pddac[0][2] = + (val >> 4) & 0x3f; + + chan_pcal_info->pwr[0][3] = 0; + chan_pcal_info->pddac[0][3] = 0; + + if (pd_gains > 1) { + /* + * Pd gain 0 is not the last pd gain + * so it only has 2 pd points. + * Continue wih pd gain 1. + */ + chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; + + chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; AR5K_EEPROM_READ(offset++, val); - ee->ee_cck_ofdm_gain_delta = val & 0xff; + chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; + + chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; + chan_pcal_info->pddac[1][0] = + (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[1][1] = val & 0xf; + chan_pcal_info->pddac[1][1] = + (val >> 4) & 0x3f; + chan_pcal_info->pwr[1][2] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[1][2] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[1][2] |= + (val & 0xF) << 2; + + chan_pcal_info->pwr[1][3] = 0; + chan_pcal_info->pddac[1][3] = 0; + } else if (pd_gains == 1) { + /* + * Pd gain 0 is the last one so + * read the extra point. + */ + chan_pcal_info->pwr[0][3] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[0][3] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[0][3] |= + (val & 0xF) << 2; + } + + /* + * Proceed with the other pd_gains + * as above. + */ + if (pd_gains > 2) { + chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; + chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[2][0] = + (val >> 0) & 0xf; + chan_pcal_info->pddac[2][0] = + (val >> 4) & 0x3f; + chan_pcal_info->pwr[2][1] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[2][1] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[2][1] |= + (val & 0xF) << 2; + + chan_pcal_info->pwr[2][2] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[2][2] = + (val >> 8) & 0x3f; + + chan_pcal_info->pwr[2][3] = 0; + chan_pcal_info->pddac[2][3] = 0; + } else if (pd_gains == 2) { + chan_pcal_info->pwr[1][3] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[1][3] = + (val >> 8) & 0x3f; + } + + if (pd_gains > 3) { + chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; + + chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; + chan_pcal_info->pwr[3][0] = + (val >> 10) & 0xf; + chan_pcal_info->pddac[3][0] = + (val >> 14) & 0x3; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[3][0] |= + (val & 0xF) << 2; + chan_pcal_info->pwr[3][1] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[3][1] = + (val >> 8) & 0x3f; + + chan_pcal_info->pwr[3][2] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[3][2] |= + ((val >> 0) & 0x3) << 2; + + chan_pcal_info->pddac[3][2] = + (val >> 2) & 0x3f; + chan_pcal_info->pwr[3][3] = + (val >> 8) & 0xf; + + chan_pcal_info->pddac[3][3] = + (val >> 12) & 0xF; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[3][3] |= + ((val >> 0) & 0x3) << 4; + } else if (pd_gains == 3) { + chan_pcal_info->pwr[2][3] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[2][3] |= + ((val >> 0) & 0x3) << 2; + + chan_pcal_info->pddac[2][3] = + (val >> 2) & 0x3f; + } + + for (c = 0; c < pd_gains; c++) { + /* Recreate pwr table for this channel using pwr steps */ + chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; + chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; + chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; + chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; + if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) + chan_pcal_info->pwr[c][3] = 0; + + /* Recreate pddac table for this channel using pddac steps */ + chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; + chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; + chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; + chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; + if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) + chan_pcal_info->pddac[c][3] = 0; } } - /* - * Read 5GHz EEPROM channels - */ + return 0; +} + +/* + * Read per rate target power (this is the maximum tx power + * supported by the card). This info is used when setting + * tx power, no matter the channel. + * + * This also works for v5 EEPROMs. + */ +static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_rate_pcal_info *rate_pcal_info; + u16 *rate_target_pwr_num; + u32 offset; + u16 val; + int ret, i; + + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); + rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_a; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; + break; + case AR5K_EEPROM_MODE_11B: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_b; + ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */ + break; + case AR5K_EEPROM_MODE_11G: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_g; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN; + break; + default: + return -EINVAL; + } + + /* Different freq mask for older eeproms (<= v3.2) */ + if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7); + rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f); + rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f); + } + } else { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf; + rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f); + rate_pcal_info[i].target_power_54 = (val & 0x3f); + } + } + + return 0; +} + +static int +ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int (*read_pcal)(struct ath5k_hw *hw, int mode); + int mode; + int err; + + if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1)) + read_pcal = ath5k_eeprom_read_pcal_info_5112; + else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2)) + read_pcal = ath5k_eeprom_read_pcal_info_2413; + else + read_pcal = ath5k_eeprom_read_pcal_info_5111; + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + err = read_pcal(ah, mode); + if (err) + return err; + + err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode); + if (err < 0) + return err; + } + + return 0; +} + +/* Read conformance test limits */ +static int +ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_edge_power *rep; + unsigned int fmask, pmask; + unsigned int ctl_mode; + int ret, i, j; + u32 offset; + u16 val; + + pmask = AR5K_EEPROM_POWER_M; + fmask = AR5K_EEPROM_FREQ_M(ee->ee_version); + offset = AR5K_EEPROM_CTL(ee->ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version); + for (i = 0; i < ee->ee_ctls; i += 2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctl[i + 1] = val & 0xff; + } + + offset = AR5K_EEPROM_GROUP8_OFFSET; + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) + offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) - + AR5K_EEPROM_GROUP5_OFFSET; + else + offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); + + rep = ee->ee_ctl_pwr; + for(i = 0; i < ee->ee_ctls; i++) { + switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { + case AR5K_CTL_11A: + case AR5K_CTL_TURBO: + ctl_mode = AR5K_EEPROM_MODE_11A; + break; + default: + ctl_mode = AR5K_EEPROM_MODE_11G; + break; + } + if (ee->ee_ctl[i] == 0) { + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) + offset += 8; + else + offset += 7; + rep += AR5K_EEPROM_N_EDGES; + continue; + } + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].freq = (val >> 8) & fmask; + rep[j + 1].freq = val & fmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].edge = (val >> 8) & pmask; + rep[j].flag = (val >> 14) & 1; + rep[j + 1].edge = val & pmask; + rep[j + 1].flag = (val >> 6) & 1; + } + } else { + AR5K_EEPROM_READ(offset++, val); + rep[0].freq = (val >> 9) & fmask; + rep[1].freq = (val >> 2) & fmask; + rep[2].freq = (val << 5) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[2].freq |= (val >> 11) & 0x1f; + rep[3].freq = (val >> 4) & fmask; + rep[4].freq = (val << 3) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].freq |= (val >> 13) & 0x7; + rep[5].freq = (val >> 6) & fmask; + rep[6].freq = (val << 1) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].freq |= (val >> 15) & 0x1; + rep[7].freq = (val >> 8) & fmask; + + rep[0].edge = (val >> 2) & pmask; + rep[1].edge = (val << 4) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[1].edge |= (val >> 12) & 0xf; + rep[2].edge = (val >> 6) & pmask; + rep[3].edge = val & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].edge = (val >> 10) & pmask; + rep[5].edge = (val >> 4) & pmask; + rep[6].edge = (val << 2) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].edge |= (val >> 14) & 0x3; + rep[7].edge = (val >> 8) & pmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) { + rep[j].freq = ath5k_eeprom_bin2freq(ee, + rep[j].freq, ctl_mode); + } + rep += AR5K_EEPROM_N_EDGES; + } return 0; } + +/* + * Initialize eeprom power tables + */ +int +ath5k_eeprom_init(struct ath5k_hw *ah) +{ + int err; + + err = ath5k_eeprom_init_header(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_init_modes(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_pcal_info(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_ctl_info(ah); + if (err < 0) + return err; + + return 0; +} /* * Read the MAC address from eeprom */ diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h index a468ecf..09eb7d0 100644 --- a/drivers/net/wireless/ath5k/eeprom.h +++ b/drivers/net/wireless/ath5k/eeprom.h @@ -25,24 +25,8 @@ #define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ -#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ -#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ -#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 -#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ -#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 -#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ -#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 -#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ -#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 -#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ -#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 -#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ -#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 -#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ -#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) #define AR5K_EEPROM_INFO_CKSUM 0xffff @@ -53,15 +37,19 @@ #define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ #define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ #define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ +#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ #define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ #define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ -#define AR5K_EEPROM_VERSION_4_3 0x4003 +#define AR5K_EEPROM_VERSION_4_3 0x4003 /* power calibration changes */ #define AR5K_EEPROM_VERSION_4_4 0x4004 #define AR5K_EEPROM_VERSION_4_5 0x4005 #define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ -#define AR5K_EEPROM_VERSION_4_7 0x4007 +#define AR5K_EEPROM_VERSION_4_7 0x3007 /* 4007 ? */ +#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */ +#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */ +#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */ +#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */ #define AR5K_EEPROM_MODE_11A 0 #define AR5K_EEPROM_MODE_11B 1 @@ -74,8 +62,8 @@ #define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ #define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ #define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) -#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ #define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ #define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c #define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 @@ -87,27 +75,95 @@ (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) #define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) -#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) -#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((s8)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff)) + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4) +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1) +#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) + +#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) +#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1) + +#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6) +#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff) +#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7) +#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f) +#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8) +#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff) +#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) +#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) + +#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9) +#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) +#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) +#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) +#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) +#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) +#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) + +#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10) +#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8) +#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8) +#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) +#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) +#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1) +#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1) /* calibration settings */ #define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) #define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) #define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) #define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ +#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */ +#define AR5K_EEPROM_GROUP1_OFFSET 0x0 +#define AR5K_EEPROM_GROUP2_OFFSET 0x5 +#define AR5K_EEPROM_GROUP3_OFFSET 0x37 +#define AR5K_EEPROM_GROUP4_OFFSET 0x46 +#define AR5K_EEPROM_GROUP5_OFFSET 0x55 +#define AR5K_EEPROM_GROUP6_OFFSET 0x65 +#define AR5K_EEPROM_GROUP7_OFFSET 0x69 +#define AR5K_EEPROM_GROUP8_OFFSET 0x6f + +#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP5_OFFSET, 0x0000) +#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP6_OFFSET, 0x0010) +#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP7_OFFSET, 0x0014) /* [3.1 - 3.3] */ #define AR5K_EEPROM_OBDB0_2GHZ 0x00ec #define AR5K_EEPROM_OBDB1_2GHZ 0x00ed -/* Misc values available since EEPROM 4.0 */ -#define AR5K_EEPROM_MISC0 0x00c4 -#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) -#define AR5K_EEPROM_MISC1 0x00c5 -#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) - +#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ +#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ +#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 +#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ +#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 +#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ +#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 +#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ +#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 +#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ +#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 +#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ +#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 +#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ +#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 /* Some EEPROM defines */ #define AR5K_EEPROM_EEP_SCALE 100 @@ -115,8 +171,11 @@ #define AR5K_EEPROM_N_MODES 3 #define AR5K_EEPROM_N_5GHZ_CHAN 10 #define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4 #define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PWR_POINTS_5111 11 #define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_PHASE_CAL 5 #define AR5K_EEPROM_N_TEST_FREQ 8 #define AR5K_EEPROM_N_EDGES 8 #define AR5K_EEPROM_N_INTERCEPTS 11 @@ -136,6 +195,8 @@ #define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 #define AR5K_EEPROM_N_XPD0_POINTS 4 #define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_PD_GAINS 4 +#define AR5K_EEPROM_N_PD_POINTS 5 #define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 #define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 #define AR5K_EEPROM_POWER_M 0x3f @@ -158,8 +219,99 @@ #define AR5K_EEPROM_READ_HDR(_o, _v) \ AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ -/* Struct to hold EEPROM calibration data */ +enum ath5k_ant_setting { + AR5K_ANT_VARIABLE = 0, /* variable by programming */ + AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ + AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ + AR5K_ANT_MAX = 3, +}; + +enum ath5k_ctl_mode { + AR5K_CTL_11A = 0, + AR5K_CTL_11B = 1, + AR5K_CTL_11G = 2, + AR5K_CTL_TURBO = 3, + AR5K_CTL_108G = 4, + AR5K_CTL_2GHT20 = 5, + AR5K_CTL_5GHT20 = 6, + AR5K_CTL_2GHT40 = 7, + AR5K_CTL_5GHT40 = 8, + AR5K_CTL_MODE_M = 15, +}; + +/* Per channel calibration data, used for power table setup */ +struct ath5k_chan_pcal_info_rf5111 { + /* Power levels in half dbm units + * for one power curve. */ + u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* PCDAC table steps + * for the above values */ + u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* Starting PCDAC step */ + u8 pcdac_min; + /* Final PCDAC step */ + u8 pcdac_max; +}; + +struct ath5k_chan_pcal_info_rf5112 { + /* Power levels in quarter dBm units + * for lower (0) and higher (3) + * level curves */ + s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; + s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; + /* PCDAC table steps + * for the above values */ + u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; + u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; +}; + +struct ath5k_chan_pcal_info_rf2413 { + /* Starting pwr/pddac values */ + s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; + u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; + /* (pwr,pddac) points */ + s8 pwr[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; + u8 pddac[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; +}; + +struct ath5k_chan_pcal_info { + /* Frequency */ + u16 freq; + /* Max available power */ + s8 max_pwr; + union { + struct ath5k_chan_pcal_info_rf5111 rf5111_info; + struct ath5k_chan_pcal_info_rf5112 rf5112_info; + struct ath5k_chan_pcal_info_rf2413 rf2413_info; + }; +}; + +/* Per rate calibration data for each mode, used for power table setup */ +struct ath5k_rate_pcal_info { + u16 freq; /* Frequency */ + /* Power level for 6-24Mbit/s rates */ + u16 target_power_6to24; + /* Power level for 36Mbit rate */ + u16 target_power_36; + /* Power level for 48Mbit rate */ + u16 target_power_48; + /* Power level for 54Mbit rate */ + u16 target_power_54; +}; + +/* Power edges for conformance test limits */ +struct ath5k_edge_power { + u16 freq; + u16 edge; /* in half dBm */ + bool flag; +}; + +/* EEPROM calibration data */ struct ath5k_eeprom_info { + + /* Header information */ u16 ee_magic; u16 ee_protect; u16 ee_regdomain; @@ -168,6 +320,11 @@ struct ath5k_eeprom_info { u16 ee_ant_gain; u16 ee_misc0; u16 ee_misc1; + u16 ee_misc2; + u16 ee_misc3; + u16 ee_misc4; + u16 ee_misc5; + u16 ee_misc6; u16 ee_cck_ofdm_gain_delta; u16 ee_cck_ofdm_power_delta; u16 ee_scaled_cck_delta; @@ -185,7 +342,7 @@ struct ath5k_eeprom_info { u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; u16 ee_xr_power[AR5K_EEPROM_N_MODES]; u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; - u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx[AR5K_EEPROM_N_MODES]; u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; @@ -198,18 +355,40 @@ struct ath5k_eeprom_info { u16 ee_x_gain[AR5K_EEPROM_N_MODES]; u16 ee_i_gain[AR5K_EEPROM_N_MODES]; u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES]; - /* Unused */ + /* Power calibration data */ u16 ee_false_detect[AR5K_EEPROM_N_MODES]; - u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; - u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ + + /* Number of pd gain curves per mode (RF2413) */ + u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; + + u8 ee_n_piers[AR5K_EEPROM_N_MODES]; + struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN]; + + /* Per rate target power levels */ + u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; + struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN]; /* Conformance test limits (Unused) */ u16 ee_ctls; u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; + struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS]; /* Noise Floor Calibration settings */ s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; + s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pd_gain_overlap; + + u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; + diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 5003263..dc2d7d8 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, 0xffffc07f); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, - (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, + (ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000, 0xfffc0fff); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | -- cgit v1.1 From cb71d9bafb37adab50ddce53bb119a84b4966c06 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 21 Nov 2008 17:41:33 -0800 Subject: ath9k: Handle -ENOMEM on RX gracefully We would get an oops on RX on -ENOMEM by passing NULL to the hardware on ath_rx_buf_link(). The oops would look something like this: ath_rx_tasklet+0x515/0x53b ath9k_tasklet+0x48 tasklet_action __do_softirq irq_exit do_IRQ RIP: ath_rx_buf_link+0x3a We correct this by handling the requeue directly on the ath_rx_tasklet() and trying to allocate an skb *prior* to sending up the last hardware processed skb. If we run out of memory this gauranteees we have skbs to work with while it simply drops new received frames. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/recv.c | 57 ++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 20f8377..6eae254 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -81,29 +81,6 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) return skb; } -static void ath_rx_requeue(struct ath_softc *sc, struct ath_buf *bf) -{ - struct sk_buff *skb; - - ASSERT(bf != NULL); - - if (bf->bf_mpdu == NULL) { - skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); - if (skb != NULL) { - bf->bf_mpdu = skb; - 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; - - } - } - - list_move_tail(&bf->list, &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf); -} - - static int ath_rate2idx(struct ath_softc *sc, int rate) { int i = 0, cur_band, n_rates; @@ -445,7 +422,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_buf *bf; struct ath_desc *ds; - struct sk_buff *skb = NULL; + struct sk_buff *skb = NULL, *requeue_skb; struct ieee80211_rx_status rx_status; struct ath_hal *ah = sc->sc_ah; struct ieee80211_hdr *hdr; @@ -522,17 +499,28 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * chain it back at the queue without processing it. */ if (flush) - goto rx_next; + goto requeue; if (!ds->ds_rxstat.rs_datalen) - goto rx_next; + goto requeue; /* The status portion of the descriptor could get corrupted. */ if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen) - goto rx_next; + goto requeue; if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) - goto rx_next; + goto requeue; + + /* Ensure we always have an skb to requeue once we are done + * processing the current buffer's skb */ + requeue_skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); + + /* If there is no memory we ignore the current RX'd frame, + * tell hardware it can give us a new frame using the old + * skb and put it at the tail of the sc->sc_rxbuf list for + * processing. */ + if (!requeue_skb) + goto requeue; /* Sync and unmap the frame */ pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, @@ -569,7 +557,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Send the frame to mac80211 */ __ieee80211_rx(sc->hw, skb, &rx_status); - bf->bf_mpdu = NULL; + + /* We will now give hardware our shiny new allocated skb */ + bf->bf_mpdu = requeue_skb; + bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data, + sc->sc_rxbufsize, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; /* * change the default rx antenna if rx diversity chooses the @@ -581,8 +575,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) } else { sc->sc_rxotherant = 0; } -rx_next: - ath_rx_requeue(sc, bf); +requeue: + list_move_tail(&bf->list, &sc->sc_rxbuf); + ath_rx_buf_link(sc, bf); } while (1); spin_unlock_bh(&sc->sc_rxbuflock); -- cgit v1.1 From 7473431297761fa644a128a497b91e299676f501 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 22 Nov 2008 10:37:25 +0000 Subject: orinoco: Separate fw caching from download This refactorring will make it easier to share logic with Symbol firmware. Signed-off by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco.c | 53 ++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index 7ec038a..492f419 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -431,9 +431,9 @@ struct fw_info { }; const static struct fw_info orinoco_fw[] = { - { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } + { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, + { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } }; /* Structure used to access fields in FW @@ -487,18 +487,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, if (err) goto free; - if (priv->cached_fw) - fw_entry = priv->cached_fw; - else { + if (!priv->cached_fw) { err = request_firmware(&fw_entry, firmware, priv->dev); + if (err) { printk(KERN_ERR "%s: Cannot find firmware %s\n", dev->name, firmware); err = -ENOENT; goto free; } - priv->cached_fw = fw_entry; - } + } else + fw_entry = priv->cached_fw; hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -540,11 +539,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, hermes_present(hw)); abort: - /* In case of error, assume firmware was bogus and release it */ - if (err) { - priv->cached_fw = NULL; + /* If we requested the firmware, release it. */ + if (!priv->cached_fw) release_firmware(fw_entry); - } free: kfree(pda); @@ -708,6 +705,30 @@ static int orinoco_download(struct orinoco_private *priv) return err; } +static void orinoco_cache_fw(struct orinoco_private *priv, int ap) +{ + const struct firmware *fw_entry = NULL; + const char *fw; + + if (ap) + fw = orinoco_fw[priv->firmware_type].ap_fw; + else + fw = orinoco_fw[priv->firmware_type].sta_fw; + + if (fw) { + if (request_firmware(&fw_entry, fw, priv->dev) == 0) + priv->cached_fw = fw_entry; + } +} + +static void orinoco_uncache_fw(struct orinoco_private *priv) +{ + if (priv->cached_fw) + release_firmware(priv->cached_fw); + + priv->cached_fw = NULL; +} + /********************************************************************/ /* Device methods */ /********************************************************************/ @@ -3304,6 +3325,8 @@ static int orinoco_init(struct net_device *dev) } if (priv->do_fw_download) { + orinoco_cache_fw(priv, 0); + err = orinoco_download(priv); if (err) priv->do_fw_download = 0; @@ -3553,9 +3576,9 @@ void free_orinocodev(struct net_device *dev) * when we call tasklet_kill it will run one final time, * emptying the list */ tasklet_kill(&priv->rx_tasklet); - if (priv->cached_fw) - release_firmware(priv->cached_fw); - priv->cached_fw = NULL; + + orinoco_uncache_fw(priv); + priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); -- cgit v1.1 From 2cea7b261942009e90befbe41d998e2931547026 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 22 Nov 2008 10:37:26 +0000 Subject: orinoco: Cache Symbol firmware Signed-off by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco.c | 46 +++++++++++++++++++++++----------- drivers/net/wireless/orinoco/orinoco.h | 3 ++- 2 files changed, 34 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index 492f419..09eec7f 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -645,34 +645,41 @@ symbol_dl_firmware(struct orinoco_private *priv, int ret; const struct firmware *fw_entry; - if (request_firmware(&fw_entry, fw->pri_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->pri_fw); - return -ENOENT; - } + if (!priv->cached_pri_fw) { + if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->pri_fw); + return -ENOENT; + } + } else + fw_entry = priv->cached_pri_fw; /* Load primary firmware */ ret = symbol_dl_image(priv, fw, fw_entry->data, fw_entry->data + fw_entry->size, 0); - release_firmware(fw_entry); + + if (!priv->cached_pri_fw) + release_firmware(fw_entry); if (ret) { printk(KERN_ERR "%s: Primary firmware download failed\n", dev->name); return ret; } - if (request_firmware(&fw_entry, fw->sta_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->sta_fw); - return -ENOENT; - } + if (!priv->cached_fw) { + if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->sta_fw); + return -ENOENT; + } + } else + fw_entry = priv->cached_fw; /* Load secondary firmware */ ret = symbol_dl_image(priv, fw, fw_entry->data, fw_entry->data + fw_entry->size, 1); - release_firmware(fw_entry); + if (!priv->cached_fw) + release_firmware(fw_entry); if (ret) { printk(KERN_ERR "%s: Secondary firmware download failed\n", dev->name); @@ -708,13 +715,20 @@ static int orinoco_download(struct orinoco_private *priv) static void orinoco_cache_fw(struct orinoco_private *priv, int ap) { const struct firmware *fw_entry = NULL; + const char *pri_fw; const char *fw; + pri_fw = orinoco_fw[priv->firmware_type].pri_fw; if (ap) fw = orinoco_fw[priv->firmware_type].ap_fw; else fw = orinoco_fw[priv->firmware_type].sta_fw; + if (pri_fw) { + if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) + priv->cached_pri_fw = fw_entry; + } + if (fw) { if (request_firmware(&fw_entry, fw, priv->dev) == 0) priv->cached_fw = fw_entry; @@ -723,9 +737,12 @@ static void orinoco_cache_fw(struct orinoco_private *priv, int ap) static void orinoco_uncache_fw(struct orinoco_private *priv) { + if (priv->cached_pri_fw) + release_firmware(priv->cached_pri_fw); if (priv->cached_fw) release_firmware(priv->cached_fw); + priv->cached_pri_fw = NULL; priv->cached_fw = NULL; } @@ -3563,6 +3580,7 @@ struct net_device netif_carrier_off(dev); priv->last_linkstatus = 0xffff; + priv->cached_pri_fw = NULL; priv->cached_fw = NULL; return dev; diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 8c29538..f6eaea9 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -167,7 +167,8 @@ struct orinoco_private { unsigned int tkip_cm_active:1; unsigned int key_mgmt:3; - /* Cached in memory firmware to use in ->resume */ + /* Cached in memory firmware to use during ->resume. */ + const struct firmware *cached_pri_fw; const struct firmware *cached_fw; }; -- cgit v1.1 From ac7cafd72261857278dff9f737e600b30088653b Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 22 Nov 2008 10:37:27 +0000 Subject: orinoco: Resume spectrum_cs in the same way as orinoco_cs Retrieval of external firmware has been resolved, and should work with the standard orinoco resume algorithm. This fixes an issue where priv->hw_unavailable indicates the card is ready when firmware has not been loaded. Signed-off by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/spectrum_cs.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 0bae3dc..a276476 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -450,10 +450,29 @@ spectrum_cs_resume(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); priv->hw_unavailable--; - schedule_work(&priv->reset_work); + + if (priv->open && !priv->hw_unavailable) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); return 0; } -- cgit v1.1 From 39d1ffee57c7ce02c90ec8e9272df8aa8ddf600f Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 22 Nov 2008 10:37:28 +0000 Subject: orinoco: Provide option to avoid unnecessary fw caching Make firmware caching on startup optional, and make it default. When the option is not selected and PM_SLEEP is configured, then cache firmware in the suspend pm_notifier. This configuration saves about 64k RAM in normal use, but can lead to a situation where the driver is configured to use a different firmware. Signed-off by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 15 +++++++++ drivers/net/wireless/orinoco/orinoco.c | 57 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/orinoco/orinoco.h | 3 ++ 3 files changed, 75 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7ea916b..ea543fc 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -214,6 +214,21 @@ config HERMES configure your card and that /etc/pcmcia/wireless.opts works : +config HERMES_CACHE_FW_ON_INIT + bool "Cache Hermes firmware on driver initialisation" + depends on HERMES + default y + ---help--- + Say Y to cache any firmware required by the Hermes drivers + on startup. The firmware will remain cached until the + driver is unloaded. The cache uses 64K of RAM. + + Otherwise load the firmware from userspace as required. In + this case the driver should be unloaded and restarted + whenever the firmware is changed. + + If you are not sure, say Y. + config APPLE_AIRPORT tristate "Apple Airport support (built-in)" depends on PPC_PMAC && HERMES diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index 09eec7f..171bfa0 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -712,6 +713,7 @@ static int orinoco_download(struct orinoco_private *priv) return err; } +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) static void orinoco_cache_fw(struct orinoco_private *priv, int ap) { const struct firmware *fw_entry = NULL; @@ -745,6 +747,10 @@ static void orinoco_uncache_fw(struct orinoco_private *priv) priv->cached_pri_fw = NULL; priv->cached_fw = NULL; } +#else +#define orinoco_cache_fw(priv, ap) +#define orinoco_uncache_fw(priv) +#endif /********************************************************************/ /* Device methods */ @@ -3100,6 +3106,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id) } /********************************************************************/ +/* Power management */ +/********************************************************************/ +#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT) +static int orinoco_pm_notifier(struct notifier_block *notifier, + unsigned long pm_event, + void *unused) +{ + struct orinoco_private *priv = container_of(notifier, + struct orinoco_private, + pm_notifier); + + /* All we need to do is cache the firmware before suspend, and + * release it when we come out. + * + * Only need to do this if we're downloading firmware. */ + if (!priv->do_fw_download) + return NOTIFY_DONE; + + switch (pm_event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + orinoco_cache_fw(priv, 0); + break; + + case PM_POST_RESTORE: + /* Restore from hibernation failed. We need to clean + * up in exactly the same way, so fall through. */ + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + orinoco_uncache_fw(priv); + break; + + case PM_RESTORE_PREPARE: + default: + break; + } + + return NOTIFY_DONE; +} +#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */ +#define orinoco_pm_notifier NULL +#endif + +/********************************************************************/ /* Initialization */ /********************************************************************/ @@ -3342,7 +3392,9 @@ static int orinoco_init(struct net_device *dev) } if (priv->do_fw_download) { +#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT orinoco_cache_fw(priv, 0); +#endif err = orinoco_download(priv); if (err) @@ -3583,6 +3635,10 @@ struct net_device priv->cached_pri_fw = NULL; priv->cached_fw = NULL; + /* Register PM notifiers */ + priv->pm_notifier.notifier_call = orinoco_pm_notifier; + register_pm_notifier(&priv->pm_notifier); + return dev; } @@ -3595,6 +3651,7 @@ void free_orinocodev(struct net_device *dev) * emptying the list */ tasklet_kill(&priv->rx_tasklet); + unregister_pm_notifier(&priv->pm_notifier); orinoco_uncache_fw(priv); priv->wpa_ie_len = 0; diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index f6eaea9..00750c8 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -10,6 +10,7 @@ #define DRIVER_VERSION "0.15" #include +#include #include #include #include @@ -170,6 +171,8 @@ struct orinoco_private { /* Cached in memory firmware to use during ->resume. */ const struct firmware *cached_pri_fw; const struct firmware *cached_fw; + + struct notifier_block pm_notifier; }; #ifdef ORINOCO_DEBUG -- cgit v1.1 From ff37e337beb838d4c2540fa93b2c4c632ee17750 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 24 Nov 2008 12:07:55 +0530 Subject: ath9k: Code scrub Merge core.c and base.c Remove Antenna Diversity (unused now). Remove unused chainmask handling code. Comment, indentation scrub. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/Makefile | 3 +- drivers/net/wireless/ath9k/beacon.c | 80 +- drivers/net/wireless/ath9k/core.c | 1610 ----------------------------------- drivers/net/wireless/ath9k/core.h | 155 +--- drivers/net/wireless/ath9k/main.c | 1195 +++++++++++++++++++++++++- drivers/net/wireless/ath9k/rc.c | 9 +- drivers/net/wireless/ath9k/recv.c | 22 + drivers/net/wireless/ath9k/xmit.c | 22 +- 8 files changed, 1231 insertions(+), 1865 deletions(-) delete mode 100644 drivers/net/wireless/ath9k/core.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index c58cfde..c741e8d 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -9,7 +9,6 @@ ath9k-y += hw.o \ main.o \ recv.o \ xmit.o \ - rc.o \ - core.o + rc.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index dcf2383..377d2df 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -14,13 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - /* Implementation of beacon processing. */ - #include "core.h" /* - * Configure parameters for the beacon queue - * * This function will modify certain transmit queue properties depending on * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max @@ -54,9 +50,15 @@ static int ath_beaconq_config(struct ath_softc *sc) } } +static 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_reset(sc, false); +} + /* - * Setup the beacon frame for transmit. - * * Associates the beacon frame buffer with a transmit descriptor. Will set * up all required antenna switch parameters, rate codes, and channel flags. * Beacons are always sent out at the lowest rate, and are not retried. @@ -138,14 +140,7 @@ static void ath_beacon_setup(struct ath_softc *sc, ctsrate, ctsduration, series, 4, 0); } -/* - * Generate beacon frame and queue cab data for a vap. - * - * Updates the contents of the beacon frame. It is assumed that the buffer for - * the beacon frame has been allocated in the ATH object, and simply needs to - * be filled for this cycle. Also, any CAB (crap after beacon?) traffic will - * be added to the beacon frame at this point. -*/ +/* Generate beacon frame and queue cab data for a vap */ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) { struct ath_buf *bf; @@ -275,14 +270,6 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc); } -/* - * Setup a h/w transmit queue for beacons. - * - * This function allocates an information structure (struct ath9k_txq_info) - * on the stack, sets some specific parameters (zero out channel width - * min/max, and enable aifs). The info structure does not need to be - * persistant. -*/ int ath_beaconq_setup(struct ath_hal *ah) { struct ath9k_tx_queue_info qi; @@ -295,14 +282,6 @@ int ath_beaconq_setup(struct ath_hal *ah) return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } - -/* - * Allocate and setup an initial beacon frame. - * - * Allocate a beacon state variable for a specific VAP instance created on - * the ATH interface. This routine also calculates the beacon "slot" for - * staggared beacons in the mBSSID case. -*/ int ath_beacon_alloc(struct ath_softc *sc, int if_id) { struct ieee80211_vif *vif; @@ -321,7 +300,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) if (!avp->av_bcbuf) { /* Allocate beacon state for hostap/ibss. We know * a buffer is available. */ - avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, struct ath_buf, list); list_del(&avp->av_bcbuf->list); @@ -427,12 +405,6 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) return 0; } -/* - * Reclaim beacon resources and return buffer to the pool. - * - * Checks the VAP to put the beacon frame buffer back to the ATH object - * queue, and de-allocates any skbs that were sent as CAB traffic. -*/ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) { if (avp->av_bcbuf != NULL) { @@ -458,13 +430,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) } } -/* - * Tasklet for Sending Beacons - * - * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame - * contents are done as needed and the slot time is also adjusted based on - * current state. -*/ void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -481,9 +446,7 @@ void ath9k_beacon_tasklet(unsigned long data) if (sc->sc_flags & SC_OP_NO_RESET) { show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, - &rx_clear, - &rx_frame, - &tx_frame); + &rx_clear, &rx_frame, &tx_frame); } /* @@ -605,9 +568,10 @@ void ath9k_beacon_tasklet(unsigned long data) if (sc->sc_updateslot == UPDATE) { sc->sc_updateslot = COMMIT; /* commit next beacon */ sc->sc_slotupdate = slot; - } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) - ath_setslottime(sc); /* commit change to hardware */ - + } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) { + ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime); + sc->sc_updateslot = OK; + } if (bfaddr != 0) { /* * Stop any current dma and put the new frame(s) on the queue. @@ -630,20 +594,6 @@ void ath9k_beacon_tasklet(unsigned long data) } /* - * Tasklet for Beacon Stuck processing - * - * Processing for Beacon Stuck. - * Basically resets the chip. -*/ -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_reset(sc, false); -} - -/* * Configure the beacon and sleep timers. * * When operating as an AP this resets the TSF and sets @@ -886,8 +836,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) } } -/* Function to collect beacon rssi data and resync beacon if necessary */ - void ath_beacon_sync(struct ath_softc *sc, int if_id) { /* diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c deleted file mode 100644 index fb6a013..0000000 --- a/drivers/net/wireless/ath9k/core.c +++ /dev/null @@ -1,1610 +0,0 @@ -/* - * Copyright (c) 2008, Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "core.h" -#include "regd.h" - -static u32 ath_chainmask_sel_up_rssi_thres = - ATH_CHAINMASK_SEL_UP_RSSI_THRES; -static u32 ath_chainmask_sel_down_rssi_thres = - ATH_CHAINMASK_SEL_DOWN_RSSI_THRES; -static u32 ath_chainmask_sel_period = - ATH_CHAINMASK_SEL_TIMEOUT; - -/* return bus cachesize in 4B word units */ - -static void bus_read_cachesize(struct ath_softc *sc, int *csz) -{ - u8 u8tmp; - - pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); - *csz = (int)u8tmp; - - /* - * This check was put in to avoid "unplesant" consequences if - * the bootrom has not fully initialized all PCI devices. - * Sometimes the cache line size register is not set - */ - - if (*csz == 0) - *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ -} - -static u8 parse_mpdudensity(u8 mpdudensity) -{ - /* - * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": - * 0 for no restriction - * 1 for 1/4 us - * 2 for 1/2 us - * 3 for 1 us - * 4 for 2 us - * 5 for 4 us - * 6 for 8 us - * 7 for 16 us - */ - switch (mpdudensity) { - case 0: - return 0; - case 1: - case 2: - case 3: - /* Our lower layer calculations limit our precision to - 1 microsecond */ - return 1; - case 4: - return 2; - case 5: - return 4; - case 6: - return 8; - case 7: - return 16; - default: - return 0; - } -} - -/* - * Set current operating mode -*/ -static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) -{ - sc->sc_curmode = mode; - /* - * All protection frames are transmited at 2Mb/s for - * 11g, otherwise at 1Mb/s. - * XXX select protection rate index from rate table. - */ - sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); -} - -/* - * Set up rate table (legacy rates) - */ -static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) -{ - struct ath_rate_table *rate_table = NULL; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; - int i, maxrates; - - switch (band) { - case IEEE80211_BAND_2GHZ: - rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; - break; - case IEEE80211_BAND_5GHZ: - rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; - break; - default: - break; - } - - if (rate_table == NULL) - return; - - sband = &sc->sbands[band]; - rate = sc->rates[band]; - - if (rate_table->rate_cnt > ATH_RATE_MAX) - maxrates = ATH_RATE_MAX; - else - maxrates = rate_table->rate_cnt; - - for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rate_table->info[i].ratekbps / 100; - rate[i].hw_value = rate_table->info[i].ratecode; - sband->n_bitrates++; - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Rate: %2dMbps, ratecode: %2d\n", - __func__, - rate[i].bitrate / 10, - rate[i].hw_value); - } -} - -/* - * Set up channel list - */ -static int ath_setup_channels(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int nchan, i, a = 0, b = 0; - u8 regclassids[ATH_REGCLASSIDS_MAX]; - u32 nregclass = 0; - struct ieee80211_supported_band *band_2ghz; - struct ieee80211_supported_band *band_5ghz; - struct ieee80211_channel *chan_2ghz; - struct ieee80211_channel *chan_5ghz; - struct ath9k_channel *c; - - /* Fill in ah->ah_channels */ - if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, - regclassids, ATH_REGCLASSIDS_MAX, - &nregclass, CTRY_DEFAULT, false, 1)) { - u32 rd = ah->ah_currentRD; - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to collect channel list; " - "regdomain likely %u country code %u\n", - __func__, rd, CTRY_DEFAULT); - return -EINVAL; - } - - band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; - band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; - chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; - chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; - - for (i = 0; i < nchan; i++) { - c = &ah->ah_channels[i]; - if (IS_CHAN_2GHZ(c)) { - chan_2ghz[a].band = IEEE80211_BAND_2GHZ; - chan_2ghz[a].center_freq = c->channel; - chan_2ghz[a].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - band_2ghz->n_channels = ++a; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 2MHz channel: %d, " - "channelFlags: 0x%x\n", - __func__, c->channel, c->channelFlags); - } else if (IS_CHAN_5GHZ(c)) { - chan_5ghz[b].band = IEEE80211_BAND_5GHZ; - chan_5ghz[b].center_freq = c->channel; - chan_5ghz[b].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - band_5ghz->n_channels = ++b; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 5MHz channel: %d, " - "channelFlags: 0x%x\n", - __func__, c->channel, c->channelFlags); - } - } - - return 0; -} - -/* - * Determine mode from channel flags - * - * This routine will provide the enumerated WIRELESSS_MODE value based - * on the settings of the channel flags. If no valid set of flags - * exist, the lowest mode (11b) is selected. -*/ - -static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) -{ - if (chan->chanmode == CHANNEL_A) - return ATH9K_MODE_11A; - else if (chan->chanmode == CHANNEL_G) - return ATH9K_MODE_11G; - else if (chan->chanmode == CHANNEL_B) - return ATH9K_MODE_11B; - else if (chan->chanmode == CHANNEL_A_HT20) - return ATH9K_MODE_11NA_HT20; - else if (chan->chanmode == CHANNEL_G_HT20) - return ATH9K_MODE_11NG_HT20; - else if (chan->chanmode == CHANNEL_A_HT40PLUS) - return ATH9K_MODE_11NA_HT40PLUS; - else if (chan->chanmode == CHANNEL_A_HT40MINUS) - return ATH9K_MODE_11NA_HT40MINUS; - else if (chan->chanmode == CHANNEL_G_HT40PLUS) - return ATH9K_MODE_11NG_HT40PLUS; - else if (chan->chanmode == CHANNEL_G_HT40MINUS) - return ATH9K_MODE_11NG_HT40MINUS; - - WARN_ON(1); /* should not get here */ - - return ATH9K_MODE_11B; -} - -/* - * Set the current channel - * - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff after a la ath_init. -*/ -int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) -{ - struct ath_hal *ah = sc->sc_ah; - bool fastcc = true, stopped; - - if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ - return -EIO; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", - __func__, - 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); - - 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; - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* clear pending tx frames */ - stopped = ath_stoprecv(sc); /* turn off frame recv */ - - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ - - if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) - fastcc = false; - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, hchan, - 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__, - ath9k_hw_mhz2ieee(ah, hchan->channel, - hchan->channelFlags), - hchan->channel, hchan->channelFlags, status); - spin_unlock_bh(&sc->sc_resetlock); - return -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); - - sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; - sc->sc_flags &= ~SC_OP_FULL_RESET; - - /* Re-enable rx framework */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); - return -EIO; - } - /* - * Change channels and update the h/w rate map - * if we're switching; e.g. 11a to 11b/g. - */ - ath_setcurmode(sc, ath_chan2mode(hchan)); - - ath_update_txpow(sc); /* update tx power state */ - /* - * Re-enable interrupts. - */ - ath9k_hw_set_interrupts(ah, sc->sc_imask); - } - return 0; -} - -/**********************/ -/* Chainmask Handling */ -/**********************/ - -static void ath_chainmask_sel_timertimeout(unsigned long data) -{ - struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data; - cm->switch_allowed = 1; -} - -/* Start chainmask select timer */ -static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm) -{ - cm->switch_allowed = 0; - mod_timer(&cm->timer, ath_chainmask_sel_period); -} - -/* Stop chainmask select timer */ -static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm) -{ - cm->switch_allowed = 0; - del_timer_sync(&cm->timer); -} - -static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - - memset(cm, 0, sizeof(struct ath_chainmask_sel)); - - cm->cur_tx_mask = sc->sc_tx_chainmask; - cm->cur_rx_mask = sc->sc_rx_chainmask; - cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER; - setup_timer(&cm->timer, - ath_chainmask_sel_timertimeout, (unsigned long) cm); -} - -int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - - /* - * Disable auto-swtiching in one of the following if conditions. - * sc_chainmask_auto_sel is used for internal global auto-switching - * enabled/disabled setting - */ - if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) { - cm->cur_tx_mask = sc->sc_tx_chainmask; - return cm->cur_tx_mask; - } - - if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER) - return cm->cur_tx_mask; - - if (cm->switch_allowed) { - /* Switch down from tx 3 to tx 2. */ - if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 && - ATH_RSSI_OUT(cm->tx_avgrssi) >= - ath_chainmask_sel_down_rssi_thres) { - cm->cur_tx_mask = sc->sc_tx_chainmask; - - /* Don't let another switch happen until - * this timer expires */ - ath_chainmask_sel_timerstart(cm); - } - /* Switch up from tx 2 to 3. */ - else if (cm->cur_tx_mask == sc->sc_tx_chainmask && - ATH_RSSI_OUT(cm->tx_avgrssi) <= - ath_chainmask_sel_up_rssi_thres) { - cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3; - - /* Don't let another switch happen - * until this timer expires */ - ath_chainmask_sel_timerstart(cm); - } - } - - return cm->cur_tx_mask; -} - -/* - * Update tx/rx chainmask. For legacy association, - * hard code chainmask to 1x1, for 11n association, use - * the chainmask configuration. - */ - -void ath_update_chainmask(struct ath_softc *sc, int is_ht) -{ - 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; - } else { - sc->sc_tx_chainmask = 1; - sc->sc_rx_chainmask = 1; - } - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n", - __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); -} - -/*******/ -/* ANI */ -/*******/ - -/* - * This routine performs the periodic noise floor calibration function - * that is used to adjust and optimize the chip performance. This - * takes environmental changes (location, temperature) into account. - * When the task is complete, it reschedules itself depending on the - * appropriate interval that was calculated. - */ - -static void ath_ani_calibrate(unsigned long data) -{ - struct ath_softc *sc; - struct ath_hal *ah; - bool longcal = false; - bool shortcal = false; - bool aniflag = false; - unsigned int timestamp = jiffies_to_msecs(jiffies); - u32 cal_interval; - - sc = (struct ath_softc *)data; - ah = sc->sc_ah; - - /* - * don't calibrate when we're scanning. - * we are most likely not on our home channel. - */ - if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC) - return; - - /* Long calibration runs independently of short calibration. */ - if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { - longcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", - __func__, jiffies); - sc->sc_ani.sc_longcal_timer = timestamp; - } - - /* Short calibration applies only while sc_caldone is false */ - if (!sc->sc_ani.sc_caldone) { - if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= - ATH_SHORT_CALINTERVAL) { - shortcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", - __func__, jiffies); - sc->sc_ani.sc_shortcal_timer = timestamp; - sc->sc_ani.sc_resetcal_timer = timestamp; - } - } else { - if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= - ATH_RESTART_CALINTERVAL) { - ath9k_hw_reset_calvalid(ah, ah->ah_curchan, - &sc->sc_ani.sc_caldone); - if (sc->sc_ani.sc_caldone) - sc->sc_ani.sc_resetcal_timer = timestamp; - } - } - - /* Verify whether we must check ANI */ - if ((timestamp - sc->sc_ani.sc_checkani_timer) >= - ATH_ANI_POLLINTERVAL) { - aniflag = true; - sc->sc_ani.sc_checkani_timer = timestamp; - } - - /* Skip all processing if there's nothing to do. */ - if (longcal || shortcal || aniflag) { - /* Call ANI routine if necessary */ - if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->sc_halstats, - ah->ah_curchan); - - /* Perform calibration if necessary */ - if (longcal || shortcal) { - bool iscaldone = false; - - if (ath9k_hw_calibrate(ah, ah->ah_curchan, - sc->sc_rx_chainmask, longcal, - &iscaldone)) { - if (longcal) - sc->sc_ani.sc_noise_floor = - ath9k_hw_getchan_noise(ah, - ah->ah_curchan); - - DPRINTF(sc, ATH_DBG_ANI, - "%s: calibrate chan %u/%x nf: %d\n", - __func__, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags, - sc->sc_ani.sc_noise_floor); - } else { - DPRINTF(sc, ATH_DBG_ANY, - "%s: calibrate chan %u/%x failed\n", - __func__, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags); - } - sc->sc_ani.sc_caldone = iscaldone; - } - } - - /* - * Set timer interval based on previous results. - * The interval must be the shortest necessary to satisfy ANI, - * short calibration and long calibration. - */ - - cal_interval = ATH_ANI_POLLINTERVAL; - if (!sc->sc_ani.sc_caldone) - cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); - - mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); -} - -/********/ -/* Core */ -/********/ - -int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", - __func__, sc->sc_ah->ah_opmode); - - /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(ah, 0); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - - spin_lock_bh(&sc->sc_resetlock); - 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, - initial_chan->channel, initial_chan->channelFlags); - error = -EIO; - spin_unlock_bh(&sc->sc_resetlock); - goto done; - } - spin_unlock_bh(&sc->sc_resetlock); - - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath_update_txpow(sc); - - /* - * Setup the hardware after reset: - * The receive engine is set going. - * Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); - error = -EIO; - goto done; - } - - /* Setup our intr mask. */ - sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX - | ATH9K_INT_RXEOL | ATH9K_INT_RXORN - | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; - - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->sc_imask |= ATH9K_INT_GTT; - - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - sc->sc_imask |= ATH9K_INT_CST; - - /* - * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. - */ - if (ath9k_hw_phycounters(ah) && - ((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 - * interrupt when the TIM bit is set. For hardware - * that does, if not overridden by configuration, - * enable the TIM interrupt when operating as station. - */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_ah->ah_opmode == ATH9K_M_STA) && - !sc->sc_config.swBeaconProcess) - sc->sc_imask |= ATH9K_INT_TIM; - - ath_setcurmode(sc, ath_chan2mode(initial_chan)); - - sc->sc_flags &= ~SC_OP_INVALID; - - /* Disable BMISS interrupt when we're not associated */ - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah,sc->sc_imask); - - ieee80211_wake_queues(sc->hw); -done: - return error; -} - -void ath_stop(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__); - - ieee80211_stop_queues(sc->hw); - - /* make sure h/w will not generate any interrupt - * before setting the invalid flag. */ - ath9k_hw_set_interrupts(ah, 0); - - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_draintxq(sc, false); - ath_stoprecv(sc); - ath9k_hw_phy_disable(ah); - } else - sc->sc_rxlink = NULL; - -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - ath9k_hw_configpcipowersave(sc->sc_ah, 1); - - sc->sc_flags |= SC_OP_INVALID; -} - -int ath_reset(struct ath_softc *sc, bool retry_tx) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - - ath9k_hw_set_interrupts(ah, 0); - ath_draintxq(sc, retry_tx); - ath_stoprecv(sc); - ath_flushrecv(sc); - - /* Reset chip */ - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - 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); - error = -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); - - if (ath_startrecv(sc) != 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); - - ath_update_txpow(sc); - - 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); - - /* Restart the txq */ - if (retry_tx) { - int i; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - spin_lock_bh(&sc->sc_txq[i].axq_lock); - ath_txq_schedule(sc, &sc->sc_txq[i]); - spin_unlock_bh(&sc->sc_txq[i].axq_lock); - } - } - } - - return error; -} - -/* Interrupt handler. Most of the actual processing is deferred. - * It's the caller's responsibility to ensure the chip is awake. */ - -irqreturn_t ath_isr(int irq, void *dev) -{ - struct ath_softc *sc = dev; - struct ath_hal *ah = sc->sc_ah; - enum ath9k_int status; - bool sched = false; - - do { - if (sc->sc_flags & SC_OP_INVALID) { - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - return IRQ_NONE; - } - if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ - return IRQ_NONE; - } - - /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - - status &= sc->sc_imask; /* discard unasked-for bits */ - - /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). - */ - - if (!status) - return IRQ_NONE; - - sc->sc_intrstatus = status; - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - sched = true; - } else if (status & ATH9K_INT_RXORN) { - /* need a chip reset */ - sched = true; - } else { - if (status & ATH9K_INT_SWBA) { - /* schedule a tasklet for beacon handling */ - tasklet_schedule(&sc->bcon_tasklet); - } - if (status & ATH9K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work - * at least on older hardware revs. - */ - sched = true; - } - - if (status & ATH9K_INT_TXURN) - /* bump tx trigger level */ - ath9k_hw_updatetxtriglevel(ah, true); - /* XXX: optimize this */ - if (status & ATH9K_INT_RX) - sched = true; - if (status & ATH9K_INT_TX) - sched = true; - if (status & ATH9K_INT_BMISS) - sched = true; - /* carrier sense timeout */ - if (status & ATH9K_INT_CST) - sched = true; - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_set_interrupts(ah, 0); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - ath9k_hw_procmibevent(ah, &sc->sc_halstats); - ath9k_hw_set_interrupts(ah, sc->sc_imask); - } - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->ah_caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_hw_setrxabort(ah, 0); - sched = true; - } - } - } - } while (0); - - if (sched) { - /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); - tasklet_schedule(&sc->intr_tq); - } - - return IRQ_HANDLED; -} - -/* Deferred interrupt processing */ - -static void ath9k_tasklet(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - u32 status = sc->sc_intrstatus; - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - ath_reset(sc, false); - return; - } else { - - if (status & - (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - /* XXX: fill me in */ - /* - if (status & ATH9K_INT_RXORN) { - } - if (status & ATH9K_INT_RXEOL) { - } - */ - spin_lock_bh(&sc->sc_rxflushlock); - ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->sc_rxflushlock); - } - /* XXX: optimize this */ - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); - /* XXX: fill me in */ - /* - if (status & ATH9K_INT_BMISS) { - } - if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) { - if (status & ATH9K_INT_TIM) { - } - if (status & ATH9K_INT_DTIMSYNC) { - } - } - */ - } - - /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); -} - -int ath_init(u16 devid, struct ath_softc *sc) -{ - struct ath_hal *ah = NULL; - int status; - int error = 0, i; - int csz = 0; - - /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_flags |= SC_OP_INVALID; - sc->sc_debug = DBG_DEFAULT; - - spin_lock_init(&sc->sc_resetlock); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, - (unsigned long)sc); - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - bus_read_cachesize(sc, &csz); - /* XXX assert csz is non-zero */ - sc->sc_cachelsz = csz << 2; /* convert to bytes */ - - ah = ath9k_hw_attach(devid, sc, sc->mem, &status); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to attach hardware; HAL status %u\n", - __func__, status); - error = -ENXIO; - goto bad; - } - sc->sc_ah = ah; - - /* Get the hardware key cache size. */ - sc->sc_keymax = ah->ah_caps.keycache_size; - if (sc->sc_keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s: Warning, using only %u entries in %u key cache\n", - __func__, ATH_KEYMAX, sc->sc_keymax); - sc->sc_keymax = ATH_KEYMAX; - } - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < sc->sc_keymax; i++) - ath9k_hw_keyreset(ah, (u16) i); - /* - * Mark key cache slots associated with global keys - * as in use. If we knew TKIP was not to be used we - * could leave the +32, +64, and +32+64 slots free. - * XXX only for splitmic. - */ - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - set_bit(i, sc->sc_keymap); - set_bit(i + 32, sc->sc_keymap); - set_bit(i + 64, sc->sc_keymap); - set_bit(i + 32 + 64, sc->sc_keymap); - } - - /* Collect the channel list using the default country code */ - - error = ath_setup_channels(sc); - if (error) - goto bad; - - /* default to MONITOR mode */ - sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; - - /* Setup rate tables */ - - ath_rate_attach(sc); - ath_setup_rates(sc, IEEE80211_BAND_2GHZ); - ath_setup_rates(sc, IEEE80211_BAND_5GHZ); - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that the hal handles reseting - * these queues at the needed time. - */ - sc->sc_bhalq = ath_beaconq_setup(ah); - if (sc->sc_bhalq == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup a beacon xmit queue\n", __func__); - error = -EIO; - goto bad2; - } - sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->sc_cabq == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup CAB xmit queue\n", __func__); - error = -EIO; - goto bad2; - } - - sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; - ath_cabq_update(sc); - - for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++) - sc->sc_haltype2q[i] = -1; - - /* Setup data queues */ - /* NB: ensure BK queue is the lowest priority h/w queue */ - if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BK traffic\n", - __func__); - error = -EIO; - goto bad2; - } - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BE traffic\n", - __func__); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VI traffic\n", - __func__); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VO traffic\n", - __func__); - error = -EIO; - goto bad2; - } - - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ - - sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, - 0, 1, NULL); - } - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - sc->sc_splitmic = 1; - - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, - 1, NULL); - - sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; - sc->sc_config.txpowlimit_override = 0; - - /* 11n Capabilities */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->sc_defant = ath9k_hw_getdefantenna(ah); - - ath9k_hw_getmac(ah, sc->sc_myaddr); - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { - ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); - ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); - ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); - } - - sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ - - /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++) - sc->sc_bslot[i] = ATH_IF_ID_ANY; - - /* save MISC configurations */ - sc->sc_config.swBeaconProcess = 1; - -#ifdef CONFIG_SLOW_ANT_DIV - /* range is 40 - 255, we use something in the middle */ - ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); -#endif - - /* setup channels and rates */ - - sc->sbands[IEEE80211_BAND_2GHZ].channels = - sc->channels[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = - sc->rates[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = - sc->channels[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - } - - return 0; -bad2: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); -bad: - if (ah) - ath9k_hw_detach(ah); - - return error; -} - -/*******************/ -/* Node Management */ -/*******************/ - -void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - struct ath_node *an; - - an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) - ath_tx_node_init(sc, an); - - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); - - ath_chainmask_sel_init(sc, an); - ath_chainmask_sel_timerstart(&an->an_chainmask_sel); -} - -void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - - ath_chainmask_sel_timerstop(&an->an_chainmask_sel); - - if (sc->sc_flags & SC_OP_TXAGGR) - ath_tx_node_cleanup(sc, an); -} - -/* - * Set up New Node - * - * Setup driver-specific state for a newly associated node. This routine - * really only applies if compression or XR are enabled, there is no code - * covering any other cases. -*/ - -void ath_newassoc(struct ath_softc *sc, - struct ath_node *an, int isnew, int isuapsd) -{ - int tidno; - - /* if station reassociates, tear down the aggregation state. */ - if (!isnew) { - for (tidno = 0; tidno < WME_NUM_TID; tidno++) { - if (sc->sc_flags & SC_OP_TXAGGR) - ath_tx_aggr_teardown(sc, an, tidno); - } - } -} - -/**************/ -/* Encryption */ -/**************/ - -void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) -{ - ath9k_hw_keyreset(sc->sc_ah, keyix); - if (freeslot) - clear_bit(keyix, sc->sc_keymap); -} - -int ath_keyset(struct ath_softc *sc, - u16 keyix, - struct ath9k_keyval *hk, - const u8 mac[ETH_ALEN]) -{ - bool status; - - status = ath9k_hw_set_keycache_entry(sc->sc_ah, - keyix, hk, mac, false); - - return status != false; -} - -/***********************/ -/* TX Power/Regulatory */ -/***********************/ - -/* - * Set Transmit power in HAL - * - * This routine makes the actual HAL calls to set the new transmit power - * limit. -*/ - -void ath_update_txpow(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 txpow; - - if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); - /* read back in case value is clamped */ - ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); - sc->sc_curtxpow = txpow; - } -} - -/**************************/ -/* Slow Antenna Diversity */ -/**************************/ - -void ath_slow_ant_div_init(struct ath_antdiv *antdiv, - struct ath_softc *sc, - int32_t rssitrig) -{ - int trig; - - /* antdivf_rssitrig can range from 40 - 0xff */ - trig = (rssitrig > 0xff) ? 0xff : rssitrig; - trig = (rssitrig < 40) ? 40 : rssitrig; - - antdiv->antdiv_sc = sc; - antdiv->antdivf_rssitrig = trig; -} - -void ath_slow_ant_div_start(struct ath_antdiv *antdiv, - u8 num_antcfg, - const u8 *bssid) -{ - antdiv->antdiv_num_antcfg = - num_antcfg < ATH_ANT_DIV_MAX_CFG ? - num_antcfg : ATH_ANT_DIV_MAX_CFG; - antdiv->antdiv_state = ATH_ANT_DIV_IDLE; - antdiv->antdiv_curcfg = 0; - antdiv->antdiv_bestcfg = 0; - antdiv->antdiv_laststatetsf = 0; - - memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid)); - - antdiv->antdiv_start = 1; -} - -void ath_slow_ant_div_stop(struct ath_antdiv *antdiv) -{ - antdiv->antdiv_start = 0; -} - -static int32_t ath_find_max_val(int32_t *val, - u8 num_val, u8 *max_index) -{ - u32 MaxVal = *val++; - u32 cur_index = 0; - - *max_index = 0; - while (++cur_index < num_val) { - if (*val > MaxVal) { - MaxVal = *val; - *max_index = cur_index; - } - - val++; - } - - return MaxVal; -} - -void ath_slow_ant_div(struct ath_antdiv *antdiv, - struct ieee80211_hdr *hdr, - struct ath_rx_status *rx_stats) -{ - struct ath_softc *sc = antdiv->antdiv_sc; - struct ath_hal *ah = sc->sc_ah; - u64 curtsf = 0; - u8 bestcfg, curcfg = antdiv->antdiv_curcfg; - __le16 fc = hdr->frame_control; - - if (antdiv->antdiv_start && ieee80211_is_beacon(fc) - && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) { - antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi; - antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah); - curtsf = antdiv->antdiv_lastbtsf[curcfg]; - } else { - return; - } - - switch (antdiv->antdiv_state) { - case ATH_ANT_DIV_IDLE: - if ((antdiv->antdiv_lastbrssi[curcfg] < - antdiv->antdivf_rssitrig) - && ((curtsf - antdiv->antdiv_laststatetsf) > - ATH_ANT_DIV_MIN_IDLE_US)) { - - curcfg++; - if (curcfg == antdiv->antdiv_num_antcfg) - curcfg = 0; - - if (!ath9k_hw_select_antconfig(ah, curcfg)) { - antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg; - antdiv->antdiv_curcfg = curcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_SCAN; - } - } - break; - - case ATH_ANT_DIV_SCAN: - if ((curtsf - antdiv->antdiv_laststatetsf) < - ATH_ANT_DIV_MIN_SCAN_US) - break; - - curcfg++; - if (curcfg == antdiv->antdiv_num_antcfg) - curcfg = 0; - - if (curcfg == antdiv->antdiv_bestcfg) { - ath_find_max_val(antdiv->antdiv_lastbrssi, - antdiv->antdiv_num_antcfg, &bestcfg); - if (!ath9k_hw_select_antconfig(ah, bestcfg)) { - antdiv->antdiv_bestcfg = bestcfg; - antdiv->antdiv_curcfg = bestcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_IDLE; - } - } else { - if (!ath9k_hw_select_antconfig(ah, curcfg)) { - antdiv->antdiv_curcfg = curcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_SCAN; - } - } - - break; - } -} - -/***********************/ -/* Descriptor Handling */ -/***********************/ - -/* - * Set up DMA descriptors - * - * This function will allocate both the DMA descriptor structure, and the - * buffers it contains. These are used to contain the descriptors used - * by the system. -*/ - -int ath_descdma_setup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head, - const char *name, - int nbuf, - int ndesc) -{ -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - - struct ath_desc *ds; - struct ath_buf *bf; - int i, bsize, error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n", - __func__, name, nbuf, ndesc); - - /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n", - __func__); - ASSERT((sizeof(struct ath_desc) % 4) == 0); - error = -ENOMEM; - goto fail; - } - - dd->dd_name = name; - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; - - /* - * Need additional DMA memory because we can't use - * descriptors that cross the 4K page boundary. Assume - * one skipped descriptor per 4K page. - */ - if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { - u32 ndesc_skipped = - ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); - u32 dma_len; - - while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); - dd->dd_desc_len += dma_len; - - ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; - } - - /* allocate descriptors */ - dd->dd_desc = pci_alloc_consistent(sc->pdev, - dd->dd_desc_len, - &dd->dd_desc_paddr); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } - ds = dd->dd_desc; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n", - __func__, dd->dd_name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); - - /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = kmalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - memset(bf, 0, bsize); - dd->dd_bufptr = bf; - - INIT_LIST_HEAD(head); - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->ah_caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - ASSERT((caddr_t) bf->bf_desc < - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += ndesc; - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - } - } - list_add_tail(&bf->list, head); - } - return 0; -fail2: - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS -} - -/* - * Cleanup DMA descriptors - * - * This function will free the DMA block that was allocated for the descriptor - * pool. Since this was allocated as one "chunk", it is freed in the same - * manner. -*/ - -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - /* Free memory associated with descriptors */ - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - -/*************/ -/* Utilities */ -/*************/ - -int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case 0: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO]; - break; - case 1: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI]; - break; - case 2: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; - break; - case 3: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK]; - break; - default: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; - break; - } - - return qnum; -} - -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case ATH9K_WME_AC_VO: - qnum = 0; - break; - case ATH9K_WME_AC_VI: - qnum = 1; - break; - case ATH9K_WME_AC_BE: - qnum = 2; - break; - case ATH9K_WME_AC_BK: - qnum = 3; - break; - default: - qnum = -1; - break; - } - - return qnum; -} - - -/* - * Expand time stamp to TSF - * - * Extend 15-bit time stamp from rx descriptor to - * a full 64-bit TSF using the current h/w TSF. -*/ - -u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) -{ - u64 tsf; - - tsf = ath9k_hw_gettsf64(sc->sc_ah); - if ((tsf & 0x7fff) < rstamp) - tsf -= 0x8000; - return (tsf & ~0x7fff) | rstamp; -} - -/* - * Set Default Antenna - * - * Call into the HAL to set the default antenna to use. Not really valid for - * MIMO technology. -*/ - -void ath_setdefantenna(void *context, u32 antenna) -{ - struct ath_softc *sc = (struct ath_softc *)context; - struct ath_hal *ah = sc->sc_ah; - - /* XXX block beacon interrupts */ - ath9k_hw_setantenna(ah, antenna); - sc->sc_defant = antenna; - sc->sc_rxotherant = 0; -} - -/* - * Set Slot Time - * - * This will wake up the chip if required, and set the slot time for the - * frame (maximum transmit time). Slot time is assumed to be already set - * in the ATH object member sc_slottime -*/ - -void ath_setslottime(struct ath_softc *sc) -{ - ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime); - sc->sc_updateslot = OK; -} diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index e672556..21ee0c2 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -47,10 +47,6 @@ struct ath_node; -/******************/ -/* Utility macros */ -/******************/ - /* Macro to expand scalars to 64-bit objects */ #define ito64(x) (sizeof(x) == 8) ? \ @@ -86,11 +82,6 @@ struct ath_node; #define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define ATH_RSSI_OUT(x) \ - (((x) != ATH_RSSI_DUMMY_MARKER) ? \ - (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER) -#define ATH_RSSI_IN(x) \ - (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) -#define ATH_LPF_RSSI(x, y, len) \ - ((x != ATH_RSSI_DUMMY_MARKER) ? \ - (((x) * ((len) - 1) + (y)) / (len)) : (y)) -#define ATH_RSSI_LPF(x, y) do { \ - if ((y) >= RSSI_LPF_THRESHOLD) \ - x = ATH_LPF_RSSI((x), \ - ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ - } while (0) - +#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RATE_DUMMY_MARKER 0 enum PROT_MODE { PROT_M_NONE = 0, @@ -748,12 +633,6 @@ enum PROT_MODE { PROT_M_CTSONLY }; -enum RATE_TYPE { - NORMAL_RATE = 0, - HALF_RATE, - QUARTER_RATE -}; - struct ath_ht_info { enum ath9k_ht_macmode tx_chan_width; u8 ext_chan_offset; @@ -881,27 +760,9 @@ struct ath_softc { struct ath_ani sc_ani; }; -int ath_init(u16 devid, struct ath_softc *sc); -int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); -void ath_stop(struct ath_softc *sc); -irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc, bool retry_tx); -int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); - -/*********************/ -/* Utility Functions */ -/*********************/ - -void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot); -int ath_keyset(struct ath_softc *sc, - u16 keyix, - struct ath9k_keyval *hk, - const u8 mac[ETH_ALEN]); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); -void ath_setslottime(struct ath_softc *sc); -void ath_update_txpow(struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); -u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 54d89ab..f226a4d 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -14,8 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* mac80211 and PCI callbacks */ - #include #include "core.h" #include "reg.h" @@ -40,6 +38,580 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { static void ath_detach(struct ath_softc *sc); +/* return bus cachesize in 4B word units */ + +static void bus_read_cachesize(struct ath_softc *sc, int *csz) +{ + u8 u8tmp; + + pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); + *csz = (int)u8tmp; + + /* + * This check was put in to avoid "unplesant" consequences if + * the bootrom has not fully initialized all PCI devices. + * Sometimes the cache line size register is not set + */ + + if (*csz == 0) + *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ +} + +static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) +{ + sc->sc_curmode = mode; + /* + * All protection frames are transmited at 2Mb/s for + * 11g, otherwise at 1Mb/s. + * XXX select protection rate index from rate table. + */ + sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); +} + +static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) +{ + if (chan->chanmode == CHANNEL_A) + return ATH9K_MODE_11A; + else if (chan->chanmode == CHANNEL_G) + return ATH9K_MODE_11G; + else if (chan->chanmode == CHANNEL_B) + return ATH9K_MODE_11B; + else if (chan->chanmode == CHANNEL_A_HT20) + return ATH9K_MODE_11NA_HT20; + else if (chan->chanmode == CHANNEL_G_HT20) + return ATH9K_MODE_11NG_HT20; + else if (chan->chanmode == CHANNEL_A_HT40PLUS) + return ATH9K_MODE_11NA_HT40PLUS; + else if (chan->chanmode == CHANNEL_A_HT40MINUS) + return ATH9K_MODE_11NA_HT40MINUS; + else if (chan->chanmode == CHANNEL_G_HT40PLUS) + return ATH9K_MODE_11NG_HT40PLUS; + else if (chan->chanmode == CHANNEL_G_HT40MINUS) + return ATH9K_MODE_11NG_HT40MINUS; + + WARN_ON(1); /* should not get here */ + + return ATH9K_MODE_11B; +} + +static void ath_update_txpow(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + u32 txpow; + + if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { + ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); + /* read back in case value is clamped */ + ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); + sc->sc_curtxpow = txpow; + } +} + +static u8 parse_mpdudensity(u8 mpdudensity) +{ + /* + * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": + * 0 for no restriction + * 1 for 1/4 us + * 2 for 1/2 us + * 3 for 1 us + * 4 for 2 us + * 5 for 4 us + * 6 for 8 us + * 7 for 16 us + */ + switch (mpdudensity) { + case 0: + return 0; + case 1: + case 2: + case 3: + /* Our lower layer calculations limit our precision to + 1 microsecond */ + return 1; + case 4: + return 2; + case 5: + return 4; + case 6: + return 8; + case 7: + return 16; + default: + return 0; + } +} + +static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) +{ + struct ath_rate_table *rate_table = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + int i, maxrates; + + switch (band) { + case IEEE80211_BAND_2GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; + break; + case IEEE80211_BAND_5GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; + break; + default: + break; + } + + if (rate_table == NULL) + return; + + sband = &sc->sbands[band]; + rate = sc->rates[band]; + + if (rate_table->rate_cnt > ATH_RATE_MAX) + maxrates = ATH_RATE_MAX; + else + maxrates = rate_table->rate_cnt; + + for (i = 0; i < maxrates; i++) { + rate[i].bitrate = rate_table->info[i].ratekbps / 100; + rate[i].hw_value = rate_table->info[i].ratecode; + sband->n_bitrates++; + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Rate: %2dMbps, ratecode: %2d\n", + __func__, rate[i].bitrate / 10, rate[i].hw_value); + } +} + +static int ath_setup_channels(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int nchan, i, a = 0, b = 0; + u8 regclassids[ATH_REGCLASSIDS_MAX]; + u32 nregclass = 0; + struct ieee80211_supported_band *band_2ghz; + struct ieee80211_supported_band *band_5ghz; + struct ieee80211_channel *chan_2ghz; + struct ieee80211_channel *chan_5ghz; + struct ath9k_channel *c; + + /* Fill in ah->ah_channels */ + if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, + regclassids, ATH_REGCLASSIDS_MAX, + &nregclass, CTRY_DEFAULT, false, 1)) { + u32 rd = ah->ah_currentRD; + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to collect channel list; " + "regdomain likely %u country code %u\n", + __func__, rd, CTRY_DEFAULT); + return -EINVAL; + } + + band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; + band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; + chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; + chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < nchan; i++) { + c = &ah->ah_channels[i]; + if (IS_CHAN_2GHZ(c)) { + chan_2ghz[a].band = IEEE80211_BAND_2GHZ; + chan_2ghz[a].center_freq = c->channel; + chan_2ghz[a].max_power = c->maxTxPower; + + if (c->privFlags & CHANNEL_DISALLOW_ADHOC) + chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; + if (c->channelFlags & CHANNEL_PASSIVE) + chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + band_2ghz->n_channels = ++a; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: 2MHz channel: %d, " + "channelFlags: 0x%x\n", + __func__, c->channel, c->channelFlags); + } else if (IS_CHAN_5GHZ(c)) { + chan_5ghz[b].band = IEEE80211_BAND_5GHZ; + chan_5ghz[b].center_freq = c->channel; + chan_5ghz[b].max_power = c->maxTxPower; + + if (c->privFlags & CHANNEL_DISALLOW_ADHOC) + chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; + if (c->channelFlags & CHANNEL_PASSIVE) + chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + band_5ghz->n_channels = ++b; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: 5MHz channel: %d, " + "channelFlags: 0x%x\n", + __func__, c->channel, c->channelFlags); + } + } + + return 0; +} + +/* + * Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. +*/ +static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) +{ + struct ath_hal *ah = sc->sc_ah; + bool fastcc = true, stopped; + + if (sc->sc_flags & SC_OP_INVALID) + return -EIO; + + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", + __func__, + 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); + + 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; + /* + * This is only performed if the channel settings have + * actually changed. + * + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ + ath_draintxq(sc, false); /* clear pending tx frames */ + stopped = ath_stoprecv(sc); /* turn off frame recv */ + + /* XXX: do not flush receive queue here. We don't want + * to flush data frames already in queue because of + * changing channel. */ + + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) + fastcc = false; + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, hchan, 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__, + ath9k_hw_mhz2ieee(ah, hchan->channel, + hchan->channelFlags), + hchan->channel, hchan->channelFlags, status); + spin_unlock_bh(&sc->sc_resetlock); + return -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); + + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; + + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to restart recv logic\n", __func__); + return -EIO; + } + + ath_setcurmode(sc, ath_chan2mode(hchan)); + ath_update_txpow(sc); + ath9k_hw_set_interrupts(ah, sc->sc_imask); + } + return 0; +} + +/* + * This routine performs the periodic noise floor calibration function + * that is used to adjust and optimize the chip performance. This + * takes environmental changes (location, temperature) into account. + * When the task is complete, it reschedules itself depending on the + * appropriate interval that was calculated. + */ +static void ath_ani_calibrate(unsigned long data) +{ + struct ath_softc *sc; + struct ath_hal *ah; + bool longcal = false; + bool shortcal = false; + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval; + + sc = (struct ath_softc *)data; + ah = sc->sc_ah; + + /* + * don't calibrate when we're scanning. + * we are most likely not on our home channel. + */ + if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC) + return; + + /* Long calibration runs independently of short calibration. */ + if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { + longcal = true; + DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", + __func__, jiffies); + sc->sc_ani.sc_longcal_timer = timestamp; + } + + /* Short calibration applies only while sc_caldone is false */ + if (!sc->sc_ani.sc_caldone) { + if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= + ATH_SHORT_CALINTERVAL) { + shortcal = true; + DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", + __func__, jiffies); + sc->sc_ani.sc_shortcal_timer = timestamp; + sc->sc_ani.sc_resetcal_timer = timestamp; + } + } else { + if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= + ATH_RESTART_CALINTERVAL) { + ath9k_hw_reset_calvalid(ah, ah->ah_curchan, + &sc->sc_ani.sc_caldone); + if (sc->sc_ani.sc_caldone) + sc->sc_ani.sc_resetcal_timer = timestamp; + } + } + + /* Verify whether we must check ANI */ + if ((timestamp - sc->sc_ani.sc_checkani_timer) >= + ATH_ANI_POLLINTERVAL) { + aniflag = true; + sc->sc_ani.sc_checkani_timer = timestamp; + } + + /* Skip all processing if there's nothing to do. */ + if (longcal || shortcal || aniflag) { + /* Call ANI routine if necessary */ + if (aniflag) + ath9k_hw_ani_monitor(ah, &sc->sc_halstats, + ah->ah_curchan); + + /* Perform calibration if necessary */ + if (longcal || shortcal) { + bool iscaldone = false; + + if (ath9k_hw_calibrate(ah, ah->ah_curchan, + sc->sc_rx_chainmask, longcal, + &iscaldone)) { + if (longcal) + sc->sc_ani.sc_noise_floor = + ath9k_hw_getchan_noise(ah, + ah->ah_curchan); + + DPRINTF(sc, ATH_DBG_ANI, + "%s: calibrate chan %u/%x nf: %d\n", + __func__, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, + sc->sc_ani.sc_noise_floor); + } else { + DPRINTF(sc, ATH_DBG_ANY, + "%s: calibrate chan %u/%x failed\n", + __func__, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags); + } + sc->sc_ani.sc_caldone = iscaldone; + } + } + + /* + * Set timer interval based on previous results. + * The interval must be the shortest necessary to satisfy ANI, + * short calibration and long calibration. + */ + + cal_interval = ATH_ANI_POLLINTERVAL; + if (!sc->sc_ani.sc_caldone) + cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); + + mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); +} + +/* + * Update tx/rx chainmask. For legacy association, + * hard code chainmask to 1x1, for 11n association, use + * the chainmask configuration. + */ +static void ath_update_chainmask(struct ath_softc *sc, int is_ht) +{ + 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; + } else { + sc->sc_tx_chainmask = 1; + sc->sc_rx_chainmask = 1; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n", + __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); +} + +static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) +{ + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_init(sc, an); + + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); +} + +static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_cleanup(sc, an); +} + +static void ath9k_tasklet(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + u32 status = sc->sc_intrstatus; + + if (status & ATH9K_INT_FATAL) { + /* need a chip reset */ + ath_reset(sc, false); + return; + } else { + + if (status & + (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + spin_lock_bh(&sc->sc_rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->sc_rxflushlock); + } + /* XXX: optimize this */ + if (status & ATH9K_INT_TX) + ath_tx_tasklet(sc); + } + + /* re-enable hardware interrupt */ + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); +} + +static irqreturn_t ath_isr(int irq, void *dev) +{ + struct ath_softc *sc = dev; + struct ath_hal *ah = sc->sc_ah; + enum ath9k_int status; + bool sched = false; + + do { + if (sc->sc_flags & SC_OP_INVALID) { + /* + * The hardware is not ready/present, don't + * touch anything. Note this can happen early + * on if the IRQ is shared. + */ + return IRQ_NONE; + } + if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ + return IRQ_NONE; + } + + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + + status &= sc->sc_imask; /* discard unasked-for bits */ + + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). + */ + if (!status) + return IRQ_NONE; + + sc->sc_intrstatus = status; + + if (status & ATH9K_INT_FATAL) { + /* need a chip reset */ + sched = true; + } else if (status & ATH9K_INT_RXORN) { + /* need a chip reset */ + sched = true; + } else { + if (status & ATH9K_INT_SWBA) { + /* schedule a tasklet for beacon handling */ + tasklet_schedule(&sc->bcon_tasklet); + } + if (status & ATH9K_INT_RXEOL) { + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work + * at least on older hardware revs. + */ + sched = true; + } + + if (status & ATH9K_INT_TXURN) + /* bump tx trigger level */ + ath9k_hw_updatetxtriglevel(ah, true); + /* XXX: optimize this */ + if (status & ATH9K_INT_RX) + sched = true; + if (status & ATH9K_INT_TX) + sched = true; + if (status & ATH9K_INT_BMISS) + sched = true; + /* carrier sense timeout */ + if (status & ATH9K_INT_CST) + sched = true; + if (status & ATH9K_INT_MIB) { + /* + * Disable interrupts until we service the MIB + * interrupt; otherwise it will continue to + * fire. + */ + ath9k_hw_set_interrupts(ah, 0); + /* + * Let the hal handle the event. We assume + * it will clear whatever condition caused + * the interrupt. + */ + ath9k_hw_procmibevent(ah, &sc->sc_halstats); + ath9k_hw_set_interrupts(ah, sc->sc_imask); + } + if (status & ATH9K_INT_TIM_TIMER) { + if (!(ah->ah_caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + /* Clear RxAbort bit so that we can + * receive frames */ + ath9k_hw_setrxabort(ah, 0); + sched = true; + } + } + } + } while (0); + + if (sched) { + /* turn off every interrupt except SWBA */ + ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); + tasklet_schedule(&sc->intr_tq); + } + + return IRQ_HANDLED; +} + static int ath_get_channel(struct ath_softc *sc, struct ieee80211_channel *chan) { @@ -90,6 +662,23 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, return chanmode; } +static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) +{ + ath9k_hw_keyreset(sc->sc_ah, keyix); + if (freeslot) + clear_bit(keyix, sc->sc_keymap); +} + +static int ath_keyset(struct ath_softc *sc, u16 keyix, + struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) +{ + bool status; + + status = ath9k_hw_set_keycache_entry(sc->sc_ah, + keyix, hk, mac, false); + + return status != false; +} static int ath_setkey_tkip(struct ath_softc *sc, struct ieee80211_key_conf *key, @@ -327,20 +916,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, } } -void ath_get_beaconconfig(struct ath_softc *sc, - int if_id, - struct ath_beacon_config *conf) -{ - struct ieee80211_hw *hw = sc->hw; - - /* fill in beacon config data */ - - conf->beacon_interval = hw->conf.beacon_int; - conf->listen_interval = 100; - conf->dtim_count = 1; - conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; -} - /********************************/ /* LED functions */ /********************************/ @@ -722,6 +1297,244 @@ static void ath_detach(struct ath_softc *sc) ath9k_hw_detach(sc->sc_ah); } +static int ath_init(u16 devid, struct ath_softc *sc) +{ + struct ath_hal *ah = NULL; + int status; + int error = 0, i; + int csz = 0; + + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; + sc->sc_debug = DBG_DEFAULT; + + spin_lock_init(&sc->sc_resetlock); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, + (unsigned long)sc); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + bus_read_cachesize(sc, &csz); + /* XXX assert csz is non-zero */ + sc->sc_cachelsz = csz << 2; /* convert to bytes */ + + ah = ath9k_hw_attach(devid, sc, sc->mem, &status); + if (ah == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to attach hardware; HAL status %u\n", + __func__, status); + error = -ENXIO; + goto bad; + } + sc->sc_ah = ah; + + /* Get the hardware key cache size. */ + sc->sc_keymax = ah->ah_caps.keycache_size; + if (sc->sc_keymax > ATH_KEYMAX) { + DPRINTF(sc, ATH_DBG_KEYCACHE, + "%s: Warning, using only %u entries in %u key cache\n", + __func__, ATH_KEYMAX, sc->sc_keymax); + sc->sc_keymax = ATH_KEYMAX; + } + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < sc->sc_keymax; i++) + ath9k_hw_keyreset(ah, (u16) i); + /* + * Mark key cache slots associated with global keys + * as in use. If we knew TKIP was not to be used we + * could leave the +32, +64, and +32+64 slots free. + * XXX only for splitmic. + */ + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + set_bit(i, sc->sc_keymap); + set_bit(i + 32, sc->sc_keymap); + set_bit(i + 64, sc->sc_keymap); + set_bit(i + 32 + 64, sc->sc_keymap); + } + + /* Collect the channel list using the default country code */ + + error = ath_setup_channels(sc); + if (error) + goto bad; + + /* default to MONITOR mode */ + sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; + + /* Setup rate tables */ + + ath_rate_attach(sc); + ath_setup_rates(sc, IEEE80211_BAND_2GHZ); + ath_setup_rates(sc, IEEE80211_BAND_5GHZ); + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + sc->sc_bhalq = ath_beaconq_setup(ah); + if (sc->sc_bhalq == -1) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to setup a beacon xmit queue\n", __func__); + error = -EIO; + goto bad2; + } + sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->sc_cabq == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to setup CAB xmit queue\n", __func__); + error = -EIO; + goto bad2; + } + + sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++) + sc->sc_haltype2q[i] = -1; + + /* Setup data queues */ + /* NB: ensure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to setup xmit queue for BK traffic\n", + __func__); + error = -EIO; + goto bad2; + } + + if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to setup xmit queue for BE traffic\n", + __func__); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to setup xmit queue for VI traffic\n", + __func__); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to setup xmit queue for VO traffic\n", + __func__); + error = -EIO; + goto bad2; + } + + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); + + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, + 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + sc->sc_splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, + 1, NULL); + + sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; + sc->sc_config.txpowlimit_override = 0; + + /* 11n Capabilities */ + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; + sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; + + ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->sc_defant = ath9k_hw_getdefantenna(ah); + + ath9k_hw_getmac(ah, sc->sc_myaddr); + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { + ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); + ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); + ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); + } + + sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++) + sc->sc_bslot[i] = ATH_IF_ID_ANY; + + /* save MISC configurations */ + sc->sc_config.swBeaconProcess = 1; + +#ifdef CONFIG_SLOW_ANT_DIV + /* range is 40 - 255, we use something in the middle */ + ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); +#endif + + /* setup channels and rates */ + + sc->sbands[IEEE80211_BAND_2GHZ].channels = + sc->channels[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = + sc->rates[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_5GHZ].channels = + sc->channels[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + sc->rates[IEEE80211_BAND_5GHZ]; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + } + + return 0; +bad2: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->sc_txq[i]); +bad: + if (ah) + ath9k_hw_detach(ah); + + return error; +} + static int ath_attach(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; @@ -810,11 +1623,243 @@ bad: return error; } +int ath_reset(struct ath_softc *sc, bool retry_tx) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + int error = 0; + + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, retry_tx); + ath_stoprecv(sc); + ath_flushrecv(sc); + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, + 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); + error = -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); + + if (ath_startrecv(sc) != 0) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to start recv logic\n", __func__); + + /* + * We may be doing a reset in response to a request + * that changes the channel so update any state that + * might change as a result. + */ + ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); + + ath_update_txpow(sc); + + 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); + + if (retry_tx) { + int i; + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + spin_lock_bh(&sc->sc_txq[i].axq_lock); + ath_txq_schedule(sc, &sc->sc_txq[i]); + spin_unlock_bh(&sc->sc_txq[i].axq_lock); + } + } + } + + return error; +} + +/* + * This function will allocate both the DMA descriptor structure, and the + * buffers it contains. These are used to contain the descriptors used + * by the system. +*/ +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc) +{ +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + + struct ath_desc *ds; + struct ath_buf *bf; + int i, bsize, error; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n", + __func__, name, nbuf, ndesc); + + /* ath_desc must be a multiple of DWORDs */ + if ((sizeof(struct ath_desc) % 4) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n", + __func__); + ASSERT((sizeof(struct ath_desc) % 4) == 0); + error = -ENOMEM; + goto fail; + } + + dd->dd_name = name; + dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + + /* + * Need additional DMA memory because we can't use + * descriptors that cross the 4K page boundary. Assume + * one skipped descriptor per 4K page. + */ + if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + u32 ndesc_skipped = + ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); + u32 dma_len; + + while (ndesc_skipped) { + dma_len = ndesc_skipped * sizeof(struct ath_desc); + dd->dd_desc_len += dma_len; + + ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); + }; + } + + /* allocate descriptors */ + dd->dd_desc = pci_alloc_consistent(sc->pdev, + dd->dd_desc_len, + &dd->dd_desc_paddr); + if (dd->dd_desc == NULL) { + error = -ENOMEM; + goto fail; + } + ds = dd->dd_desc; + DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n", + __func__, dd->dd_name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * nbuf; + bf = kmalloc(bsize, GFP_KERNEL); + if (bf == NULL) { + error = -ENOMEM; + goto fail2; + } + memset(bf, 0, bsize); + dd->dd_bufptr = bf; + + INIT_LIST_HEAD(head); + for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + + if (!(sc->sc_ah->ah_caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + ASSERT((caddr_t) bf->bf_desc < + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += ndesc; + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); + } + return 0; +fail2: + pci_free_consistent(sc->pdev, + dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); +fail: + memset(dd, 0, sizeof(*dd)); + return error; +#undef ATH_DESC_4KB_BOUND_CHECK +#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED +#undef DS2PHYS +} + +void ath_descdma_cleanup(struct ath_softc *sc, + struct ath_descdma *dd, + struct list_head *head) +{ + pci_free_consistent(sc->pdev, + dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); + + INIT_LIST_HEAD(head); + kfree(dd->dd_bufptr); + memset(dd, 0, sizeof(*dd)); +} + +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) +{ + int qnum; + + switch (queue) { + case 0: + qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO]; + break; + case 1: + qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI]; + break; + case 2: + qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; + break; + case 3: + qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK]; + break; + default: + qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; + break; + } + + return qnum; +} + +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) +{ + int qnum; + + switch (queue) { + case ATH9K_WME_AC_VO: + qnum = 0; + break; + case ATH9K_WME_AC_VI: + qnum = 1; + break; + case ATH9K_WME_AC_BE: + qnum = 2; + break; + case ATH9K_WME_AC_BK: + qnum = 3; + break; + default: + qnum = -1; + break; + } + + return qnum; +} + +/**********************/ +/* mac80211 callbacks */ +/**********************/ + static int ath9k_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; struct ieee80211_channel *curchan = hw->conf.channel; - int error = 0, pos; + struct ath9k_channel *init_channel; + int error = 0, pos, status; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " "initial channel: %d MHz\n", __func__, curchan->center_freq); @@ -827,24 +1872,103 @@ static int ath9k_start(struct ieee80211_hw *hw) if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); error = -EINVAL; - goto exit; + goto error; } sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; + init_channel = &sc->sc_ah->ah_channels[pos]; - error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); - if (error) { + /* Reset SERDES registers */ + ath9k_hw_configpcipowersave(sc->sc_ah, 0); + + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(sc->sc_ah, init_channel, + 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 complete ath_open\n", __func__); - goto exit; + "%s: unable to reset hardware; hal status %u " + "(freq %u flags 0x%x)\n", __func__, status, + init_channel->channel, init_channel->channelFlags); + error = -EIO; + spin_unlock_bh(&sc->sc_resetlock); + goto error; } + spin_unlock_bh(&sc->sc_resetlock); + + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath_update_txpow(sc); + + /* + * Setup the hardware after reset: + * The receive engine is set going. + * Frame transmit is handled entirely + * in the frame output path; there's nothing to do + * here except setup the interrupt mask. + */ + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to start recv logic\n", __func__); + error = -EIO; + goto error; + } + + /* Setup our intr mask. */ + sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX + | ATH9K_INT_RXEOL | ATH9K_INT_RXORN + | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) + sc->sc_imask |= ATH9K_INT_GTT; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) + sc->sc_imask |= ATH9K_INT_CST; + + /* + * Enable MIB interrupts when there are hardware phy counters. + * Note we only do this (at the moment) for station mode. + */ + if (ath9k_hw_phycounters(sc->sc_ah) && + ((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 + * interrupt when the TIM bit is set. For hardware + * that does, if not overridden by configuration, + * enable the TIM interrupt when operating as station. + */ + if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && + (sc->sc_ah->ah_opmode == ATH9K_M_STA) && + !sc->sc_config.swBeaconProcess) + sc->sc_imask |= ATH9K_INT_TIM; + + ath_setcurmode(sc, ath_chan2mode(init_channel)); + + sc->sc_flags &= ~SC_OP_INVALID; + + /* Disable BMISS interrupt when we're not associated */ + sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); + + ieee80211_wake_queues(sc->hw); #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) error = ath_start_rfkill_poll(sc); #endif -exit: +error: return error; } @@ -911,7 +2035,30 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; } - ath_stop(sc); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__); + + ieee80211_stop_queues(sc->hw); + + /* make sure h/w will not generate any interrupt + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(sc->sc_ah, 0); + + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_draintxq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(sc->sc_ah); + } else + sc->sc_rxlink = NULL; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(sc->sc_ah); + ath9k_hw_configpcipowersave(sc->sc_ah, 1); + + sc->sc_flags |= SC_OP_INVALID; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); } diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 7d1913d..93dfea8 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1401,7 +1401,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; struct ath_tx_info_priv *tx_info_priv = NULL; - struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; int final_ts_idx, tx_status = 0, is_underrun = 0; @@ -1410,21 +1409,15 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - an = (struct ath_node *)sta->drv_priv; final_ts_idx = tx_info_priv->tx.ts_rateindex; - if (!an || !priv_sta || !ieee80211_is_data(fc) || + if (!priv_sta || !ieee80211_is_data(fc) || !tx_info_priv->update_rc) goto exit; if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) goto exit; - if (tx_info_priv->tx.ts_rssi > 0) { - ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, - tx_info_priv->tx.ts_rssi); - } - /* * If underrun error is seen assume it as an excessive retry only * if prefetch trigger level have reached the max (0x3f for 5416) diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 6eae254..743ad22 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -55,6 +55,28 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ath9k_hw_rxena(ah); } +static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) +{ + /* XXX block beacon interrupts */ + ath9k_hw_setantenna(sc->sc_ah, antenna); + sc->sc_defant = antenna; + sc->sc_rxotherant = 0; +} + +/* + * Extend 15-bit time stamp from rx descriptor to + * a full 64-bit TSF using the current h/w TSF. +*/ +static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) +{ + u64 tsf; + + tsf = ath9k_hw_gettsf64(sc->sc_ah); + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + return (tsf & ~0x7fff) | rstamp; +} + static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { struct sk_buff *skb; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index dad81a9..3de60c5 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -147,6 +147,19 @@ static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) return 0; } +static void ath_get_beaconconfig(struct ath_softc *sc, int if_id, + struct ath_beacon_config *conf) +{ + struct ieee80211_hw *hw = sc->hw; + + /* fill in beacon config data */ + + conf->beacon_interval = hw->conf.beacon_int; + conf->listen_interval = 100; + conf->dtim_count = 1; + conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; +} + /* Calculate Atheros packet type from IEEE80211 packet header */ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) @@ -522,7 +535,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) struct ath_desc *ds = bf->bf_desc; struct ath_desc *lastds = bf->bf_lastbf->bf_desc; struct ath9k_11n_rate_series series[4]; - struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -540,9 +552,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; - if (tx_info->control.sta) - an = (struct ath_node *)tx_info->control.sta->drv_priv; - if (ieee80211_has_morefrags(fc) || (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { rates[1].count = rates[2].count = rates[3].count = 0; @@ -632,10 +641,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), bf_isshpreamble(bf)); - if (bf_isht(bf) && an) - series[i].ChSel = ath_chainmask_sel_logic(sc, an); - else - series[i].ChSel = sc->sc_tx_chainmask; + series[i].ChSel = sc->sc_tx_chainmask; if (rtsctsena) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; -- cgit v1.1 From 99405f930fda280c9114b15e178902cd204f967f Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 24 Nov 2008 12:08:35 +0530 Subject: ath9k: Use proper TX channel width for setting channels The TX channel width of the BSS can be obtained only after association. In all cases, default to HT20 if HT is enabled, and set chan width to HT40 only if the BSS supports it. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 7 +-- drivers/net/wireless/ath9k/hw.c | 3 +- drivers/net/wireless/ath9k/main.c | 117 +++++++++++++++++++------------------- drivers/net/wireless/ath9k/xmit.c | 2 +- 4 files changed, 60 insertions(+), 69 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 21ee0c2..f0c5437 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -633,11 +633,6 @@ enum PROT_MODE { PROT_M_CTSONLY }; -struct ath_ht_info { - enum ath9k_ht_macmode tx_chan_width; - u8 ext_chan_offset; -}; - #define SC_OP_INVALID BIT(0) #define SC_OP_BEACONS BIT(1) #define SC_OP_RXAGGR BIT(2) @@ -691,8 +686,8 @@ struct ath_softc { u8 sc_rxotherant; /* rx's on non-default antenna */ struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ - struct ath_ht_info sc_ht_info; enum ath9k_ht_extprotspacing sc_ht_extprotspacing; + enum ath9k_ht_macmode tx_chan_width; #ifdef CONFIG_SLOW_ANT_DIV struct ath_antdiv sc_antdiv; diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 10f6c08..6eef104 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2232,8 +2232,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, ((chan->channelFlags & CHANNEL_ALL) == (ah->ah_curchan->channelFlags & CHANNEL_ALL)) && (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && - !IS_CHAN_A_5MHZ_SPACED(ah-> - ah_curchan)))) { + !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) { if (ath9k_hw_channel_change(ah, chan, macmode)) { ath9k_hw_loadnf(ah, ah->ah_curchan); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f226a4d..437e38a 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -260,15 +260,6 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) if (sc->sc_flags & SC_OP_INVALID) return -EIO; - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", - __func__, - 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); - if (hchan->channel != sc->sc_ah->ah_curchan->channel || hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || @@ -294,8 +285,14 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) fastcc = false; + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: (%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", + __func__, + sc->sc_ah->ah_curchan->channel, + hchan->channel, hchan->channelFlags, sc->tx_chan_width); + spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, hchan, sc->sc_ht_info.tx_chan_width, + if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, fastcc, &status)) { DPRINTF(sc, ATH_DBG_FATAL, @@ -626,11 +623,13 @@ static int ath_get_channel(struct ath_softc *sc, } static u32 ath_get_extchanmode(struct ath_softc *sc, - struct ieee80211_channel *chan) + struct ieee80211_channel *chan, + struct ieee80211_bss_conf *bss_conf) { u32 chanmode = 0; - u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset; - enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width; + u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset; + enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ? + ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; switch (chan->band) { case IEEE80211_BAND_2GHZ: @@ -828,17 +827,17 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) static void ath9k_ht_conf(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { - struct ath_ht_info *ht_info = &sc->sc_ht_info; - if (sc->hw->conf.ht.enabled) { - ht_info->ext_chan_offset = bss_conf->ht.secondary_channel_offset; - if (bss_conf->ht.width_40_ok) - ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; else - ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; + sc->tx_chan_width = ATH9K_HT_MACMODE_20; - ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); + ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width); + + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: BSS Changed HT, chanwidth: %d\n", + __func__, sc->tx_chan_width); } } @@ -892,26 +891,30 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, return; } - if (hw->conf.ht.enabled) + if (hw->conf.ht.enabled) { sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); - else + ath_get_extchanmode(sc, curchan, bss_conf); + + if (bss_conf->ht.width_40_ok) + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; + else + sc->tx_chan_width = ATH9K_HT_MACMODE_20; + } else { sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; + } /* set h/w channel */ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to set channel\n", - __func__); + "%s: Unable to set channel\n", __func__); /* Start ANI */ mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); } else { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Bss Info DISSOC\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info DISSOC\n", __func__); sc->sc_curaid = 0; } } @@ -1044,7 +1047,7 @@ static void ath_radio_enable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, @@ -1102,7 +1105,7 @@ static void ath_radio_disable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, @@ -1636,7 +1639,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, @@ -1864,8 +1867,6 @@ static int ath9k_start(struct ieee80211_hw *hw) DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " "initial channel: %d MHz\n", __func__, curchan->center_freq); - memset(&sc->sc_ht_info, 0, sizeof(struct ath_ht_info)); - /* setup initial channel */ pos = ath_get_channel(sc, curchan); @@ -1875,6 +1876,7 @@ static int ath9k_start(struct ieee80211_hw *hw) goto error; } + sc->tx_chan_width = ATH9K_HT_MACMODE_20; sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; init_channel = &sc->sc_ah->ah_channels[pos]; @@ -1891,7 +1893,7 @@ static int ath9k_start(struct ieee80211_hw *hw) */ spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(sc->sc_ah, init_channel, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, @@ -2149,39 +2151,37 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; - struct ieee80211_channel *curchan = hw->conf.channel; struct ieee80211_conf *conf = &hw->conf; - int pos; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); - /* Update chainmask */ - ath_update_chainmask(sc, conf->ht.enabled); + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; - } + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", + __func__, curchan->center_freq); - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); + return -EINVAL; + } - if (sc->sc_curaid && hw->conf.ht.enabled) + sc->tx_chan_width = ATH9K_HT_MACMODE_20; sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); + (curchan->band == IEEE80211_BAND_2GHZ) ? + CHANNEL_G : CHANNEL_A; + + if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to set channel\n", __func__); + } + + if (changed & IEEE80211_CONF_CHANGE_HT) + ath_update_chainmask(sc, conf->ht.enabled); if (changed & IEEE80211_CONF_CHANGE_POWER) sc->sc_config.txpowlimit = 2 * conf->power_level; - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", - __func__); - return 0; } @@ -2421,11 +2421,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_HT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT\n", - __func__); + if (changed & BSS_CHANGED_HT) ath9k_ht_conf(sc, bss_conf); - } if (changed & BSS_CHANGED_ASSOC) { DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3de60c5..413fbdd 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1148,7 +1148,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_ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { -- cgit v1.1 From b50563a68520dea3a19b5a8013c4ae0f8e3b49dd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 24 Nov 2008 14:52:51 +0100 Subject: p54: fix wmm queue settings This patch fixes a regression (introduced by "p54: more definitions form lmac_longbow.h and pda.h") It turned out that the "ret" variable wasn't initialized and this caused the following warnings/errors to appear: wmaster1: failed to set TX queue parameters for queue 2 wmaster1: failed to set TX queue parameters for queue 3 wmaster1: failed to set TX queue parameters for queue 1 wmaster1: failed to set TX queue parameters for queue 0 Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 829b3f9..6023926 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1728,10 +1728,9 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, if ((params) && !(queue > 4)) { P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); + ret = p54_set_edcf(dev); } else ret = -EINVAL; - if (!ret) - ret = p54_set_edcf(dev); mutex_unlock(&priv->conf_mutex); return ret; } -- cgit v1.1 From b235507cc5e552b9e75678d596727249e8fba01b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 25 Nov 2008 16:47:36 -0500 Subject: mac80211_hwsim: fix-up some print_mac merge damage Some print_mac -> %pM conversions got lost in some merge or another... Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d8b5cf3..530648b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -452,9 +452,9 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, hwsim_check_magic(vif); if (conf->changed & IEEE80211_IFCC_BSSID) { DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n", + printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", wiphy_name(hw->wiphy), __func__, - print_mac(mac, conf->bssid)); + conf->bssid); memcpy(vp->bssid, conf->bssid, ETH_ALEN); } return 0; @@ -612,9 +612,8 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) if (!vp->assoc) return; - printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n", - wiphy_name(data->hw->wiphy), __func__, - print_mac(buf, vp->bssid), vp->aid); + printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n", + wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid); skb = dev_alloc_skb(sizeof(*pspoll)); if (!skb) @@ -644,9 +643,8 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, if (!vp->assoc) return; - printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n", - wiphy_name(data->hw->wiphy), __func__, - print_mac(buf, vp->bssid), ps); + printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n", + wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps); skb = dev_alloc_skb(sizeof(*hdr)); if (!skb) -- cgit v1.1 From df66f858074370a7ac7b21af2940e7a3a6af17c2 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Wed, 3 Dec 2008 22:24:05 -0800 Subject: if_usb: Kill directly reference of netdev->priv Simply replace netdev->priv with netdev_priv(). Signed-off-by: Wang Chen Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index fcd3fe6..2fc637a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -59,7 +59,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp); static ssize_t if_usb_firmware_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct if_usb_card *cardp = priv->card; char fwname[FIRMWARE_NAME_MAX]; int ret; @@ -86,7 +86,7 @@ static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); static ssize_t if_usb_boot2_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct if_usb_card *cardp = priv->card; char fwname[FIRMWARE_NAME_MAX]; int ret; -- cgit v1.1 From 04adf890667050b83a58abaf63610e53a604261b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 3 Dec 2008 13:55:38 -0500 Subject: hostap: select required crypto bits in Kconfig This is fallout from moving the crypto stuff to the new lib80211 component. Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 87bbd4d..932d207 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,6 +2,13 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" depends on WLAN_80211 select WIRELESS_EXT + select CRYPTO + select CRYPTO_ARC4 + select CRYPTO_ECB + select CRYPTO_AES + select CRYPTO_MICHAEL_MIC + select CRYPTO_ECB + select CRC32 select LIB80211 select LIB80211_CRYPT_WEP select LIB80211_CRYPT_TKIP -- cgit v1.1 From 0d950d84d9d16f7d4edf380a238c5b534ff00d11 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 25 Nov 2008 13:36:01 -0800 Subject: iwlwifi: properly initialize calibration command header Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 35 ++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-commands.h | 34 +++++++++++++--------------- 3 files changed, 40 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ab0b4053..f90c9e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -523,7 +523,7 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv) struct iwl_calib_diff_gain_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; @@ -574,7 +574,7 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, data->radio_write = 1; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a738886..c3dce81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -338,9 +338,13 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, if (!data->radio_write) { struct iwl_calib_chain_noise_gain_cmd cmd; + memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; cmd.delta_gain_1 = data->delta_gain_code[1]; cmd.delta_gain_2 = data->delta_gain_code[2]; iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, @@ -362,14 +366,19 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, static void iwl5000_chain_noise_reset(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = &priv->chain_noise_data; + int ret; if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { struct iwl_calib_chain_noise_reset_cmd cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; - if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd)) + + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (ret) IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); @@ -420,17 +429,17 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, */ static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { - u8 data[sizeof(struct iwl_calib_hdr) + - sizeof(struct iwl_cal_xtal_freq)]; - struct iwl_calib_cmd *cmd = (struct iwl_calib_cmd *)data; - struct iwl_cal_xtal_freq *xtal = (struct iwl_cal_xtal_freq *)cmd->data; + struct iwl_calib_xtal_freq_cmd cmd; u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); - cmd->hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; - xtal->cap_pin1 = (u8)xtal_calib[0]; - xtal->cap_pin2 = (u8)xtal_calib[1]; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + cmd.cap_pin1 = (u8)xtal_calib[0]; + cmd.cap_pin2 = (u8)xtal_calib[1]; return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], - data, sizeof(data)); + (u8 *)&cmd, sizeof(cmd)); } static int iwl5000_send_calib_cfg(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 1fe83d4..7761504 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2896,11 +2896,6 @@ enum { }; -struct iwl_cal_xtal_freq { - u8 cap_pin1; - u8 cap_pin2; -} __attribute__ ((packed)); - #define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) struct iwl_calib_cfg_elmnt_s { @@ -2935,31 +2930,34 @@ struct iwl_calib_cmd { u8 data[0]; } __attribute__ ((packed)); -/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ - +/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ struct iwl_calib_diff_gain_cmd { - u8 opCode; /* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ - u8 flags; /* not used */ - __le16 reserved; + struct iwl_calib_hdr hdr; s8 diff_gain_a; /* see above */ s8 diff_gain_b; s8 diff_gain_c; u8 reserved1; } __attribute__ ((packed)); -struct iwl_calib_chain_noise_reset_cmd { - u8 op_code; /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ - u8 flags; /* not used */ - __le16 reserved; +struct iwl_calib_xtal_freq_cmd { + struct iwl_calib_hdr hdr; + u8 cap_pin1; + u8 cap_pin2; + u8 pad[2]; } __attribute__ ((packed)); +/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ +struct iwl_calib_chain_noise_reset_cmd { + struct iwl_calib_hdr hdr; + u8 data[0]; +}; + +/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ struct iwl_calib_chain_noise_gain_cmd { - u8 op_code; /* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ - u8 flags; /* not used */ - __le16 reserved; + struct iwl_calib_hdr hdr; u8 delta_gain_1; u8 delta_gain_2; - __le16 reserved1; + u8 pad[2]; } __attribute__ ((packed)); /****************************************************************************** -- cgit v1.1 From 51e9bf5d795b8e01e54391f1790974c7b166d286 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 26 Nov 2008 13:12:52 -0800 Subject: iwlwifi: remove uses of __constant_{endian} helpers The base versions handle constant folding just fine. Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-commands.h | 134 ++++++++-------- drivers/net/wireless/iwlwifi/iwl-commands.h | 192 +++++++++++------------ 2 files changed, 163 insertions(+), 163 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 8772d9d..735891a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -220,7 +220,7 @@ struct iwl3945_power_per_rate { * *****************************************************************************/ -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) /* @@ -322,42 +322,42 @@ enum { /* rx_config flags */ /* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FLG_BAND_24G_MSK cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK cpu_to_le32(1 << 1) /* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2) /* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3) /* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FLG_SHORT_SLOT_MSK cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK cpu_to_le32(1 << 5) /* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define RXON_FLG_DIS_DIV_MSK cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +#define RXON_FLG_RADAR_DETECT_MSK cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK cpu_to_le32(1 << 13) /* rx response to host with 8-byte TSF * (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) +#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15) /* rx_config filter flags */ /* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0) /* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1) /* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2) /* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3) /* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4) /* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FILTER_ASSOC_MSK cpu_to_le32(1 << 5) /* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) +#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6) /** * REPLY_RXON = 0x10 (command, has simple generic response) @@ -471,9 +471,9 @@ struct iwl3945_ac_qos { } __attribute__ ((packed)); /* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK cpu_to_le32(0x10) /* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 @@ -508,27 +508,27 @@ struct iwl3945_qosparam_cmd { #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1 << 2); -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); +#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2); +#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); /* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) +#define STA_KEY_FLG_ENCRYPT_MSK cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +#define STA_KEY_FLG_INVALID cpu_to_le16(0x0800) /* wep key is either from global key (0) or from station info array (1) */ -#define STA_KEY_FLG_WEP_KEY_MAP_MSK __constant_cpu_to_le16(0x0008) +#define STA_KEY_FLG_WEP_KEY_MAP_MSK cpu_to_le16(0x0008) /* wep key in STA: 5-bytes (0) or 13-bytes (1) */ -#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) -#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) +#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) /* Flags indicate whether to modify vs. don't change various station params */ #define STA_MODIFY_KEY_MASK 0x01 @@ -666,14 +666,14 @@ struct iwl3945_rx_frame_hdr { u8 payload[0]; } __attribute__ ((packed)); -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) +#define RX_RES_STATUS_NO_CRC32_ERROR cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW cpu_to_le32(1 << 1) -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_BAND_24_MSK cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -733,57 +733,57 @@ struct iwl3945_rx_frame { /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) /* 1: Transmit Clear-To-Send to self before this frame. * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ -#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3) /* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). * Tx command's initial_rate_index indicates first rate to try; * uCode walks through table for additional Tx attempts. * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4) /* 1: Expect immediate block-ack. * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) /* 1: Frame requires full Tx-Op protection. * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) +#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12) /* 1: uCode overrides sequence control field in MAC header. * 0: Driver provides sequence control field in MAC header. * Set this for management frames, non-QOS data frames, non-unicast frames, * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) +#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13) /* 1: This frame is non-last MPDU; more fragments are coming. * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) +#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14) /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. * 0: No TSF required in outgoing frame. * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) +#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16) /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword * alignment of frame's payload data field. @@ -791,10 +791,10 @@ struct iwl3945_rx_frame { * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 * field (but not both). Driver must align frame data (i.e. data following * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20) /* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) +#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25) /* * TX command security control @@ -1158,9 +1158,9 @@ struct iwl3945_spectrum_notification { */ #define IWL_POWER_VEC_SIZE 5 -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1 << 3) +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le32(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le32(1 << 2) +#define IWL_POWER_PCI_PM_MSK cpu_to_le32(1 << 3) struct iwl3945_powertable_cmd { __le32 flags; __le32 rx_data_timeout; @@ -1278,8 +1278,8 @@ struct iwl3945_ssid_ie { } __attribute__ ((packed)); #define PROBE_OPTION_MAX 0x4 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -1379,7 +1379,7 @@ struct iwl3945_scan_cmd { } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +#define CAN_ABORT_STATUS cpu_to_le32(0x1) /* complete notification statuses */ #define ABORT_STATUS 0x2 @@ -1572,8 +1572,8 @@ struct statistics_general { * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */ struct iwl3945_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -1593,8 +1593,8 @@ struct iwl3945_statistics_cmd { * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) struct iwl3945_notif_statistics { __le32 flag; struct statistics_rx rx; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7761504..0591aec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -172,8 +172,8 @@ enum { #define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) #define SEQ_TO_INDEX(s) ((s) & 0xff) #define INDEX_TO_SEQ(i) ((i) & 0xff) -#define SEQ_HUGE_FRAME __constant_cpu_to_le16(0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_HUGE_FRAME cpu_to_le16(0x4000) +#define SEQ_RX_FRAME cpu_to_le16(0x8000) /** * struct iwl_cmd_header @@ -368,7 +368,7 @@ struct iwl5000_tx_power_dbm_cmd { * *****************************************************************************/ -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) /* @@ -517,75 +517,75 @@ enum { }; -#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0) -#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1) +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK cpu_to_le16(0x1 << 0) +#define RXON_RX_CHAIN_VALID_MSK cpu_to_le16(0x7 << 1) #define RXON_RX_CHAIN_VALID_POS (1) -#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7 << 4) +#define RXON_RX_CHAIN_FORCE_SEL_MSK cpu_to_le16(0x7 << 4) #define RXON_RX_CHAIN_FORCE_SEL_POS (4) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7 << 7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK cpu_to_le16(0x7 << 7) #define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3 << 10) +#define RXON_RX_CHAIN_CNT_MSK cpu_to_le16(0x3 << 10) #define RXON_RX_CHAIN_CNT_POS (10) -#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3 << 12) +#define RXON_RX_CHAIN_MIMO_CNT_MSK cpu_to_le16(0x3 << 12) #define RXON_RX_CHAIN_MIMO_CNT_POS (12) -#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1 << 14) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK cpu_to_le16(0x1 << 14) #define RXON_RX_CHAIN_MIMO_FORCE_POS (14) /* rx_config flags */ /* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FLG_BAND_24G_MSK cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK cpu_to_le32(1 << 1) /* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2) /* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3) /* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FLG_SHORT_SLOT_MSK cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK cpu_to_le32(1 << 5) /* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define RXON_FLG_DIS_DIV_MSK cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +#define RXON_FLG_RADAR_DETECT_MSK cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK cpu_to_le32(1 << 13) /* rx response to host with 8-byte TSF * (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) +#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15) /* HT flags */ #define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) -#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1 << 22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK cpu_to_le32(0x1 << 22) #define RXON_FLG_HT_OPERATING_MODE_POS (23) -#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23) +#define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) +#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) #define RXON_FLG_CHANNEL_MODE_POS (25) -#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) +#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) /* CTS to self (if spec allows) flag */ -#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30) +#define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) /* rx_config filter flags */ /* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0) /* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1) /* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2) /* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3) /* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4) /* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FILTER_ASSOC_MSK cpu_to_le32(1 << 5) /* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) +#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6) /** * REPLY_RXON = 0x10 (command, has simple generic response) @@ -745,9 +745,9 @@ struct iwl_ac_qos { } __attribute__ ((packed)); /* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK cpu_to_le32(0x10) /* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 @@ -784,34 +784,34 @@ struct iwl_qosparam_cmd { #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); -#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) -#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); +#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) -#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) -#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) #define STA_FLG_AGG_MPDU_DENSITY_POS (23) -#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) /* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x0007) -#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000) -#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001) -#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002) -#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003) +#define STA_KEY_FLG_ENCRYPT_MSK cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +#define STA_KEY_FLG_INVALID cpu_to_le16(0x0800) /* wep key is either from global key (0) or from station info array (1) */ -#define STA_KEY_FLG_MAP_KEY_MSK __constant_cpu_to_le16(0x0008) +#define STA_KEY_FLG_MAP_KEY_MSK cpu_to_le16(0x0008) /* wep key in STA: 5-bytes (0) or 13-bytes (1) */ -#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000) -#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000) +#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) #define STA_KEY_MAX_NUM 8 /* Flags indicate whether to modify vs. don't change various station params */ @@ -1036,14 +1036,14 @@ struct iwl4965_rx_frame_hdr { u8 payload[0]; } __attribute__ ((packed)); -#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) -#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) +#define RX_RES_STATUS_NO_CRC32_ERROR cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW cpu_to_le32(1 << 1) -#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) -#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) -#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) -#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) -#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_BAND_24_MSK cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -1174,21 +1174,21 @@ struct iwl4965_rx_mpdu_res_start { /* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it * before this frame. if CTS-to-self required check * RXON_FLG_SELF_CTS_EN status. */ -#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0) +#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0) /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) /* 1: Transmit Clear-To-Send to self before this frame. * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ -#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3) /* For 4965: * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). @@ -1196,40 +1196,40 @@ struct iwl4965_rx_mpdu_res_start { * uCode walks through table for additional Tx attempts. * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4) /* 1: Expect immediate block-ack. * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) /* 1: Frame requires full Tx-Op protection. * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) +#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12) /* 1: uCode overrides sequence control field in MAC header. * 0: Driver provides sequence control field in MAC header. * Set this for management frames, non-QOS data frames, non-unicast frames, * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) +#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13) /* 1: This frame is non-last MPDU; more fragments are coming. * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) +#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14) /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. * 0: No TSF required in outgoing frame. * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) +#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16) /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword * alignment of frame's payload data field. @@ -1237,14 +1237,14 @@ struct iwl4965_rx_mpdu_res_start { * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 * field (but not both). Driver must align frame data (i.e. data following * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20) /* accelerate aggregation support * 0 - no CCMP encryption; 1 - CCMP encryption */ -#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22) +#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22) /* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) +#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25) /* @@ -2076,10 +2076,10 @@ struct iwl4965_spectrum_notification { */ #define IWL_POWER_VEC_SIZE 5 -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) -#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(1 << 2) +#define IWL_POWER_PCI_PM_MSK cpu_to_le16(1 << 3) +#define IWL_POWER_FAST_PD cpu_to_le16(1 << 4) struct iwl_powertable_cmd { __le16 flags; @@ -2153,8 +2153,8 @@ struct iwl_ct_kill_config { * *****************************************************************************/ -#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0) -#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1) +#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0) +#define SCAN_CHANNEL_TYPE_ACTIVE cpu_to_le32(1) /** * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table @@ -2205,8 +2205,8 @@ struct iwl_ssid_ie { } __attribute__ ((packed)); #define PROBE_OPTION_MAX 0x14 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -2306,7 +2306,7 @@ struct iwl_scan_cmd { } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +#define CAN_ABORT_STATUS cpu_to_le32(0x1) /* complete notification statuses */ #define ABORT_STATUS 0x2 @@ -2568,8 +2568,8 @@ struct statistics_general { * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */ struct iwl_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -2589,8 +2589,8 @@ struct iwl_statistics_cmd { * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -2806,8 +2806,8 @@ struct iwl4965_missed_beacon_notif { #define HD_OFDM_ENERGY_TH_IN_INDEX (10) /* Control field in struct iwl_sensitivity_cmd */ -#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) -#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1) /** * struct iwl_sensitivity_cmd @@ -2896,7 +2896,7 @@ enum { }; -#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) +#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff) struct iwl_calib_cfg_elmnt_s { __le32 is_enable; -- cgit v1.1 From f6bac3ea5990653765700b2c3778b08782abebe5 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 26 Nov 2008 16:17:11 -0500 Subject: ath5k: preserve higher order bits when setting mac address In some cases we would like to set the mac address without changing the operating mode. However, Atheros cards store PCU data in the high 16 bits of the mac address register. Change ath5k_hw_set_lladdr() to not clobber the PCU settings. Changes-licensed-under: ISC Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/pcu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index d7f0c10..79879f2 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -267,24 +267,23 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) * @mac: The card's mac address * * Set station id on hw using the provided mac address - * - * NOTE: This is only called during attach, don't call it - * on reset because it overwrites all AR5K_STA_ID1 settings. - * We have set_opmode (above) for reset. */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { u32 low_id, high_id; + u32 pcu_reg; ATH5K_TRACE(ah->ah_sc); /* Set new station ID */ memcpy(ah->ah_sta_id, mac, ETH_ALEN); + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + low_id = AR5K_LOW_ID(mac); high_id = AR5K_HIGH_ID(mac); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); - ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); + ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); return 0; } -- cgit v1.1 From 671434904633876f89be70af415c35c89fb90115 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 25 Nov 2008 20:55:21 -0500 Subject: ath5k: clean up ath5k_hw_set_key Status: O With the addition of TKIP (and soon CCMP), key->alg is a more useful guide to key type than the key length. This patch cleans up key type assignment in ath5k_hw_set_key by extracting it into its own function. It also replaces the separate memcpy() calls for extracting key material into the hardware format with a loop that works regardless of key size. Finally, the patch removes support for WEP-128 since it is a non-standard key length that mac80211 also doesn't use. Changes-licensed-under: ISC Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/pcu.c | 58 +++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index 79879f2..ad7ea36 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -1013,6 +1013,23 @@ int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) AR5K_KEYTABLE_VALID; } +static +int ath5k_keycache_type(const struct ieee80211_key_conf *key) +{ + switch (key->alg) { + case ALG_TKIP: + return AR5K_KEYTABLE_TYPE_TKIP; + case ALG_CCMP: + return AR5K_KEYTABLE_TYPE_CCM; + case ALG_WEP: + if (key->keylen == LEN_WEP40) + return AR5K_KEYTABLE_TYPE_40; + else if (key->keylen == LEN_WEP104) + return AR5K_KEYTABLE_TYPE_104; + } + return -EINVAL; +} + /* * Set a key entry on the table */ @@ -1027,6 +1044,7 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, u32 keytype; u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; bool is_tkip; + const u8 *key_ptr; ATH5K_TRACE(ah->ah_sc); @@ -1042,33 +1060,25 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) return -EOPNOTSUPP; - switch (keylen) { - /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ - case 40 / 8: - memcpy(&key_v[0], key->key, 5); - keytype = AR5K_KEYTABLE_TYPE_40; - break; + if (unlikely(keylen > 16)) + return -EOPNOTSUPP; - /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ - case 104 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 1); - keytype = AR5K_KEYTABLE_TYPE_104; - break; - /* WEP/TKIP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ - case 128 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 4); - keytype = is_tkip ? - AR5K_KEYTABLE_TYPE_TKIP : - AR5K_KEYTABLE_TYPE_128; - break; + keytype = ath5k_keycache_type(key); + if (keytype < 0) + return keytype; - default: - return -EINVAL; /* shouldn't happen */ + /* + * each key block is 6 bytes wide, written as pairs of + * alternating 32 and 16 bit le values. + */ + key_ptr = key->key; + for (i = 0; keylen >= 6; keylen -= 6) { + memcpy(&key_v[i], key_ptr, 6); + i += 2; + key_ptr += 6; } + if (keylen) + memcpy(&key_v[i], key_ptr, keylen); /* intentionally corrupt key until mic is installed */ if (is_tkip) { -- cgit v1.1 From f650470a8f506bc33a15778432ebb8cdcf89175b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 26 Nov 2008 16:17:25 -0500 Subject: ath5k: enable combined michael mic in key cache For mac revisions >= "Griffin," the hardware allows the mic tx and rx authenticator keys to share the same cache line, whereas earlier hardware can only store the rx. Enable the combined mic on hardware that supports it. Changes to ath5k.h Changes-licensed-under: 3-Clause-BSD Changes to attach.c, pcu.c, reg.h Changes-licensed-under: ISC Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 1 + drivers/net/wireless/ath5k/attach.c | 6 ++++++ drivers/net/wireless/ath5k/pcu.c | 28 ++++++++++++++-------------- drivers/net/wireless/ath5k/reg.h | 1 + 4 files changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 5ee2dd1..13df119 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -1052,6 +1052,7 @@ struct ath5k_hw { bool ah_calibration; bool ah_running; bool ah_single_chip; + bool ah_combined_mic; enum ath5k_rfgain ah_rf_gain; u32 ah_mac_srev; diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 49d82d7..dea378f 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -317,6 +317,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } + if (srev >= AR5K_SREV_AR2414) { + ah->ah_combined_mic = true; + AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, + AR5K_MISC_MODE_COMBINED_MIC); + } + /* MAC address is cleared until add_interface */ ath5k_hw_set_lladdr(ah, mac); diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index ad7ea36..dabe422 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -1096,20 +1096,20 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, /* Install rx/tx MIC */ rxmic = (__le32 *) &key->key[16]; txmic = (__le32 *) &key->key[24]; -#if 0 - /* MISC_MODE register & 0x04 - for mac srev >= griffin */ - key_v[0] = rxmic[0]; - key_v[1] = (txmic[0] >> 16) & 0xffff; - key_v[2] = rxmic[1]; - key_v[3] = txmic[0] & 0xffff; - key_v[4] = txmic[1]; -#else - key_v[0] = rxmic[0]; - key_v[1] = 0; - key_v[2] = rxmic[1]; - key_v[3] = 0; - key_v[4] = 0; -#endif + + if (ah->ah_combined_mic) { + key_v[0] = rxmic[0]; + key_v[1] = (txmic[0] >> 16) & 0xffff; + key_v[2] = rxmic[1]; + key_v[3] = txmic[0] & 0xffff; + key_v[4] = txmic[1]; + } else { + key_v[0] = rxmic[0]; + key_v[1] = 0; + key_v[2] = rxmic[1]; + key_v[3] = 0; + key_v[4] = 0; + } for (i = 0; i < ARRAY_SIZE(key_v); i++) ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), AR5K_KEYTABLE_OFF(micentry, i)); diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 69755fc..91aaeaf 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -1729,6 +1729,7 @@ #define AR5K_MISC_MODE 0x8120 /* Register Address */ #define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ #define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ +#define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ /* more bits */ /* -- cgit v1.1 From e11602b7813502bf363c40cdb5a8c4b96d4bbc96 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 27 Nov 2008 09:46:27 +0530 Subject: ath9k: Handle channel initialization for AP mode Hostapd now passes the HT parameters through the config() callback, use these to set the appropriate channel in AP mode. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 60 ++++++++++++++++++++++++++++----------- drivers/net/wireless/ath9k/rc.c | 55 ++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 437e38a..e05eb1f 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -622,35 +622,35 @@ static int ath_get_channel(struct ath_softc *sc, return -1; } +/* ext_chan_offset: (-1, 0, 1) (below, none, above) */ + static u32 ath_get_extchanmode(struct ath_softc *sc, struct ieee80211_channel *chan, - struct ieee80211_bss_conf *bss_conf) + int ext_chan_offset, + enum ath9k_ht_macmode tx_chan_width) { u32 chanmode = 0; - u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset; - enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ? - ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; switch (chan->band) { case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && + if ((ext_chan_offset == 0) && (tx_chan_width == ATH9K_HT_MACMODE_20)) chanmode = CHANNEL_G_HT20; - if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && + if ((ext_chan_offset == 1) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && + if ((ext_chan_offset == -1) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_G_HT40MINUS; break; case IEEE80211_BAND_5GHZ: - if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) && + if ((ext_chan_offset == 0) && (tx_chan_width == ATH9K_HT_MACMODE_20)) chanmode = CHANNEL_A_HT20; - if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) && + if ((ext_chan_offset == 1) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) && + if ((ext_chan_offset == -1) && (tx_chan_width == ATH9K_HT_MACMODE_2040)) chanmode = CHANNEL_A_HT40MINUS; break; @@ -841,6 +841,18 @@ static void ath9k_ht_conf(struct ath_softc *sc, } } +static inline int ath_sec_offset(u8 ext_offset) +{ + if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) + return 0; + else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) + return 1; + else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) + return -1; + + return 0; +} + static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) @@ -892,13 +904,14 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, } if (hw->conf.ht.enabled) { - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan, bss_conf); + int offset = + ath_sec_offset(bss_conf->ht.secondary_channel_offset); + sc->tx_chan_width = (bss_conf->ht.width_40_ok) ? + ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; - if (bss_conf->ht.width_40_ok) - sc->tx_chan_width = ATH9K_HT_MACMODE_2040; - else - sc->tx_chan_width = ATH9K_HT_MACMODE_20; + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan, + offset, sc->tx_chan_width); } else { sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? @@ -2171,9 +2184,22 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) + if ((sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) && + (conf->ht.enabled)) { + sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ? + ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; + + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan, + conf->ht.sec_chan_offset, + sc->tx_chan_width); + } + + if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", __func__); + return -EINVAL; + } } if (changed & IEEE80211_CONF_CHANGE_HT) diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 93dfea8..7c08583 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1304,6 +1304,38 @@ static void ath_rc_tx_status(struct ath_softc *sc, xretries, long_retry); } +static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, + enum ieee80211_band band, + bool is_ht, bool is_cw_40) +{ + int mode = 0; + + switch(band) { + case IEEE80211_BAND_2GHZ: + mode = ATH9K_MODE_11G; + if (is_ht) + mode = ATH9K_MODE_11NG_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NG_HT40PLUS; + break; + case IEEE80211_BAND_5GHZ: + mode = ATH9K_MODE_11A; + if (is_ht) + mode = ATH9K_MODE_11NA_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NA_HT40PLUS; + break; + default: + DPRINTF(sc, ATH_DBG_RATE, "Invalid band\n"); + return NULL; + } + + BUG_ON(mode >= ATH9K_MODE_MAX); + + DPRINTF(sc, ATH_DBG_RATE, "Choosing rate table for mode: %d\n", mode); + return sc->hw_rate_table[mode]; +} + static void ath_rc_init(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_supported_band *sband, @@ -1314,16 +1346,25 @@ static void ath_rc_init(struct ath_softc *sc, u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; - rate_table = sc->hw_rate_table[sc->sc_curmode]; + /* FIXME: Adhoc */ + if ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) { + bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + is_cw_40); + } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + /* sc_curmode would be set on init through config() */ + rate_table = sc->hw_rate_table[sc->sc_curmode]; + } - if (sta->ht_cap.ht_supported) { - if (sband->band == IEEE80211_BAND_2GHZ) - rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20]; - else - rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; + if (!rate_table) { + DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); + return; + } + if (sta->ht_cap.ht_supported) { ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; } -- cgit v1.1 From 007e5ddddfed4ba039899754936e89b27d5cb551 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 27 Nov 2008 23:13:38 +0100 Subject: wireless: clean up radiotap a bit No need to pad the header so no constant needed for that, no need to carry any version number from netbsd nor CVS IDs from them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 24 +++--------------------- drivers/net/wireless/libertas/radiotap.h | 3 --- 2 files changed, 3 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index d2a2b75..48fa6df 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -7797,15 +7797,6 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), rxb->skb->data + IPW_RX_FRAME_SIZE, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes NOT - * part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before merging - * patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; @@ -8013,15 +8004,6 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, memcpy(ipw_rt->payload, hdr, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes - * NOT part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before - * merging patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */ @@ -10409,9 +10391,9 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, } else len = src->len; - dst = alloc_skb( - len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); - if (!dst) continue; + dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC); + if (!dst) + continue; rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h index 5d118f4..f8eb9097 100644 --- a/drivers/net/wireless/libertas/radiotap.h +++ b/drivers/net/wireless/libertas/radiotap.h @@ -6,9 +6,6 @@ struct tx_radiotap_hdr { u8 txpower; u8 rts_retries; u8 data_retries; -#if 0 - u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; -#endif } __attribute__ ((packed)); #define TX_RADIOTAP_PRESENT ( \ -- cgit v1.1 From d9a1f48648edbe99fa432626ce6964a1b58f7281 Mon Sep 17 00:00:00 2001 From: herton Date: Thu, 27 Nov 2008 22:53:24 -0200 Subject: rtl8187: fix retry count passed in rtl8187_tx I mistakenly changed retry count passed in rtl8187_tx in previous change "rtl8187: feedback transmitted packets using tx close descriptor for 8187B". For 8187 it should represent the number of retries (retry count limit). As explained by Johannes Berg, .count represents the number of tries (not retries), and retries = tries - 1. Signed-off-by: Herton Ronaldo Krzesinski Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 69ea522..dbf52e8 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -238,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.rates[0].count << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); buf = hdr; ep = 2; @@ -256,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(hdr, 0, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.rates[0].count << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, skb->len, txrate); -- cgit v1.1 From 04bd4638097c767278fdf12d50fecc8b60194d39 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 28 Nov 2008 22:18:05 +0530 Subject: ath9k: Use cleaner debug masks Remove all the useless __func__ prefixes in debug messages, and replace the DPRINTF macro with a function. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ani.c | 34 +++--- drivers/net/wireless/ath9k/beacon.c | 77 ++++++------ drivers/net/wireless/ath9k/calib.c | 69 +++++------ drivers/net/wireless/ath9k/core.h | 157 +++++++++--------------- drivers/net/wireless/ath9k/eeprom.c | 16 ++- drivers/net/wireless/ath9k/hw.c | 189 ++++++++++++---------------- drivers/net/wireless/ath9k/mac.c | 66 ++++------ drivers/net/wireless/ath9k/main.c | 237 ++++++++++++++++-------------------- drivers/net/wireless/ath9k/phy.c | 14 +-- drivers/net/wireless/ath9k/rc.c | 7 +- drivers/net/wireless/ath9k/recv.c | 14 +-- drivers/net/wireless/ath9k/regd.c | 81 ++++++------ drivers/net/wireless/ath9k/xmit.c | 77 +++++------- 13 files changed, 429 insertions(+), 609 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c index ada12e9..c25b72b 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath9k/ani.c @@ -53,8 +53,8 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, + "level out of range (%u > %u)\n", + level, (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)); return false; } @@ -158,8 +158,8 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, if (level >= ARRAY_SIZE(firstep)) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, + "level out of range (%u > %u)\n", + level, (unsigned) ARRAY_SIZE(firstep)); return false; } @@ -180,8 +180,8 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, if (level >= ARRAY_SIZE(cycpwrThr1)) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, + "level out of range (%u > %u)\n", + level, (unsigned) ARRAY_SIZE(cycpwrThr1)); return false; @@ -200,11 +200,11 @@ static bool ath9k_hw_ani_control(struct ath_hal *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: invalid cmd %u\n", __func__, cmd); + "invalid cmd %u\n", cmd); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); DPRINTF(ah->ah_sc, ATH_DBG_ANI, "noiseImmunityLevel=%d, spurImmunityLevel=%d, " "ofdmWeakSigDetectOff=%d\n", @@ -262,8 +262,8 @@ static void ath9k_ani_restart(struct ath_hal *ah) AR_PHY_COUNTMAX - aniState->cckTrigHigh; } DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Writing ofdmbase=%u cckbase=%u\n", - __func__, aniState->ofdmPhyErrBase, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); @@ -490,8 +490,7 @@ void ath9k_ani_reset(struct ath_hal *ah) if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA && ah->ah_opmode != ATH9K_M_IBSS) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Reset ANI state opmode %u\n", __func__, - ah->ah_opmode); + "Reset ANI state opmode %u\n", ah->ah_opmode); ahp->ah_stats.ast_ani_reset++; ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); @@ -581,9 +580,9 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah, phyCnt2 < aniState->cckPhyErrBase) { if (phyCnt1 < aniState->ofdmPhyErrBase) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt1 0x%x, resetting " + "phyCnt1 0x%x, resetting " "counter value to 0x%x\n", - __func__, phyCnt1, + phyCnt1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); @@ -592,9 +591,9 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah, } if (phyCnt2 < aniState->cckPhyErrBase) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt2 0x%x, resetting " + "phyCnt2 0x%x, resetting " "counter value to 0x%x\n", - __func__, phyCnt2, + phyCnt2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); @@ -692,8 +691,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, if (cycles == 0 || cycles > cc) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: cycle counter wrap. ExtBusy = 0\n", - __func__); + "cycle counter wrap. ExtBusy = 0\n"); good = 0; } else { u32 cc_d = cc - cycles; diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index e80d9b9..88fbfe5 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -41,8 +41,7 @@ static int ath_beaconq_config(struct ath_softc *sc) if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to update h/w beacon queue parameters\n", - __func__); + "unable to update h/w beacon queue parameters\n"); return 0; } else { ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ @@ -53,8 +52,8 @@ static int ath_beaconq_config(struct ath_softc *sc) static 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); + "stuck beacon; resetting (bmiss count %u)\n", + sc->sc_bmisscount); ath_reset(sc, false); } @@ -76,8 +75,7 @@ static void ath_beacon_setup(struct ath_softc *sc, int ctsrate = 0; int ctsduration = 0; - DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n", - __func__, skb, skb->len); + DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len); /* setup descriptors */ ds = bf->bf_desc; @@ -158,8 +156,8 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) cabq = sc->sc_cabq; if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", - __func__, avp, avp->av_bcbuf); + DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", + avp, avp->av_bcbuf); return NULL; } @@ -216,7 +214,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) if (sc->sc_nvaps > 1) { ath_tx_draintxq(sc, cabq, false); DPRINTF(sc, ATH_DBG_BEACON, - "%s: flush previous cabq traffic\n", __func__); + "flush previous cabq traffic\n"); } } @@ -253,8 +251,8 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) avp = (void *)vif->drv_priv; if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", - __func__, avp, avp != NULL ? avp->av_bcbuf : NULL); + DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", + avp, avp != NULL ? avp->av_bcbuf : NULL); return; } bf = avp->av_bcbuf; @@ -266,7 +264,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) /* NB: caller is known to have already stopped tx dma */ ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); ath9k_hw_txstart(ah, sc->sc_bhalq); - DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__, + DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc); } @@ -351,8 +349,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) */ skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n", - __func__); + DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); return -ENOMEM; } @@ -388,8 +385,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */ DPRINTF(sc, ATH_DBG_BEACON, - "%s: %s beacons, bslot %d intval %u tsfadjust %llu\n", - __func__, "stagger", + "stagger beacons, bslot %d intval %u tsfadjust %llu\n", avp->av_bslot, intval, (unsigned long long)tsfadjust); hdr = (struct ieee80211_hdr *)skb->data; @@ -468,40 +464,39 @@ void ath9k_beacon_tasklet(unsigned long data) if (sc->sc_bmisscount < BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->sc_bmisscount); if (show_cycles) { /* * Display cycle counter stats from HW * to aide in debug of stickiness. */ DPRINTF(sc, ATH_DBG_BEACON, - "%s: busy times: rx_clear=%d, " + "busy times: rx_clear=%d, " "rx_frame=%d, tx_frame=%d\n", - __func__, rx_clear, rx_frame, + rx_clear, rx_frame, tx_frame); } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: unable to obtain " - "busy times\n", __func__); + "unable to obtain " + "busy times\n"); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->sc_bmisscount); } } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_bmisscount == BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially " - "stuck\n", __func__); + "beacon is officially " + "stuck\n"); ath9k_hw_dmaRegDump(ah); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially stuck\n", - __func__); + "beacon is officially stuck\n"); ath_bstuck_process(sc); } } @@ -511,12 +506,12 @@ void ath9k_beacon_tasklet(unsigned long data) if (sc->sc_bmisscount != 0) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); + "resume beacon xmit after %u misses\n", + sc->sc_bmisscount); } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); + "resume beacon xmit after %u misses\n", + sc->sc_bmisscount); } sc->sc_bmisscount = 0; } @@ -536,8 +531,8 @@ void ath9k_beacon_tasklet(unsigned long data) if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; DPRINTF(sc, ATH_DBG_BEACON, - "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", - __func__, slot, (unsigned long long)tsf, tsftu, + "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", + slot, (unsigned long long)tsf, tsftu, intval, if_id); bfaddr = 0; @@ -580,8 +575,7 @@ void ath9k_beacon_tasklet(unsigned long data) */ if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: beacon queue %u did not stop?\n", - __func__, sc->sc_bhalq); + "beacon queue %u did not stop?\n", sc->sc_bhalq); /* NB: the HAL still stops DMA, so proceed */ } @@ -658,8 +652,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) else if (intval) /* NB: can be 0 for monitor mode */ nexttbtt = roundup(nexttbtt, intval); - DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", - __func__, nexttbtt, intval, conf.beacon_interval); + DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", + nexttbtt, intval, conf.beacon_interval); /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { @@ -746,7 +740,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) bs.bs_sleepduration = bs.bs_dtimperiod; DPRINTF(sc, ATH_DBG_BEACON, - "%s: tsf %llu " + "tsf %llu " "tsf:tu %u " "intval %u " "nexttbtt %u " @@ -758,7 +752,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) "maxdur %u " "next %u " "timoffset %u\n", - __func__, (unsigned long long)tsf, tsftu, bs.bs_intval, bs.bs_nexttbtt, @@ -798,8 +791,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) } #undef FUDGE DPRINTF(sc, ATH_DBG_BEACON, - "%s: IBSS nexttbtt %u intval %u (%u)\n", - __func__, nexttbtt, + "IBSS nexttbtt %u intval %u (%u)\n", + nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF, conf.beacon_interval); diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c index 0e214f7..51c8a3c 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath9k/calib.c @@ -31,11 +31,11 @@ static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) { if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: noise floor value detected (%d) is " + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor value detected (%d) is " "lower than what we think is a " "reasonable value (%d)\n", - __func__, nf, ATH9K_NF_TOO_LOW); + nf, ATH9K_NF_TOO_LOW); return false; } return true; @@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "NF calibrated [ctl] [chain 1] is %d\n", nf); nfarray[1] = nf; @@ -125,7 +125,7 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah, AR_PHY_CH2_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "NF calibrated [ctl] [chain 2] is %d\n", nf); nfarray[2] = nf; } @@ -139,7 +139,7 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "NF calibrated [ext] [chain 0] is %d\n", nf); nfarray[3] = nf; @@ -161,7 +161,7 @@ static void ath9k_hw_do_getnf(struct ath_hal *ah, AR_PHY_CH2_EXT_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "NF calibrated [ext] [chain 2] is %d\n", nf); nfarray[5] = nf; } @@ -187,8 +187,7 @@ static bool getNoiseFloorThresh(struct ath_hal *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel flags 0x%x\n", __func__, - chan->channelFlags); + "invalid channel flags 0x%x\n", chan->channelFlags); return false; } @@ -206,24 +205,22 @@ static void ath9k_hw_setup_calibration(struct ath_hal *ah, case IQ_MISMATCH_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting IQ Mismatch Calibration\n", - __func__); + "starting IQ Mismatch Calibration\n"); break; case ADC_GAIN_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC Gain Calibration\n", __func__); + "starting ADC Gain Calibration\n"); break; case ADC_DC_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC DC Calibration\n", __func__); + "starting ADC DC Calibration\n"); break; case ADC_DC_INIT_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting Init ADC DC Calibration\n", - __func__); + "starting Init ADC DC Calibration\n"); break; } @@ -594,16 +591,16 @@ void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, if (ichan == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); return; } if (currCal->calState != CAL_DONE) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Calibration state incorrect, %d\n", - __func__, currCal->calState); + "Calibration state incorrect, %d\n", + currCal->calState); return; } @@ -612,8 +609,8 @@ void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, return; DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Resetting Cal %d state for channel %u/0x%x\n", - __func__, currCal->calData->calType, chan->channel, + "Resetting Cal %d state for channel %u/0x%x\n", + currCal->calData->calType, chan->channel, chan->channelFlags); ichan->CalValid &= ~currCal->calData->calType; @@ -705,8 +702,7 @@ int16_t ath9k_hw_getnf(struct ath_hal *ah, chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: NF did not complete in calibration window\n", - __func__); + "NF did not complete in calibration window\n"); nf = 0; chan->rawNoiseFloor = nf; return chan->rawNoiseFloor; @@ -716,8 +712,8 @@ int16_t ath9k_hw_getnf(struct ath_hal *ah, if (getNoiseFloorThresh(ah, chan, &nfThresh) && nf > nfThresh) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: noise floor failed detected; " - "detected %d, threshold %d\n", __func__, + "noise floor failed detected; " + "detected %d, threshold %d\n", nf, nfThresh); chan->channelFlags |= CHANNEL_CW_INT; } @@ -759,9 +755,9 @@ s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) ichan = ath9k_regd_check_channel(ah, chan); if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); return ATH_DEFAULT_NOISE_FLOOR; } if (ichan->rawNoiseFloor == 0) { @@ -788,8 +784,8 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, if (ichan == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); return false; } @@ -834,8 +830,8 @@ bool ath9k_hw_init_cal(struct ath_hal *ah, if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: offset calibration failed to complete in 1ms; " - "noisy environment?\n", __func__); + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); return false; } @@ -850,22 +846,19 @@ bool ath9k_hw_init_cal(struct ath_hal *ah, INIT_CAL(&ahp->ah_adcGainCalData); INSERT_CAL(ahp, &ahp->ah_adcGainCalData); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC Gain Calibration.\n", - __func__); + "enabling ADC Gain Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { INIT_CAL(&ahp->ah_adcDcCalData); INSERT_CAL(ahp, &ahp->ah_adcDcCalData); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC DC Calibration.\n", - __func__); + "enabling ADC DC Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { INIT_CAL(&ahp->ah_iqCalData); INSERT_CAL(ahp, &ahp->ah_iqCalData); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling IQ Calibration.\n", - __func__); + "enabling IQ Calibration.\n"); } ahp->ah_cal_list_curr = ahp->ah_cal_list; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index f0c5437..ae32b2c 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -84,52 +84,33 @@ struct ath_node; static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -/*************/ -/* Debugging */ -/*************/ - enum ATH_DEBUG { ATH_DBG_RESET = 0x00000001, - ATH_DBG_PHY_IO = 0x00000002, - ATH_DBG_REG_IO = 0x00000004, - ATH_DBG_QUEUE = 0x00000008, - ATH_DBG_EEPROM = 0x00000010, - ATH_DBG_NF_CAL = 0x00000020, - ATH_DBG_CALIBRATE = 0x00000040, - ATH_DBG_CHANNEL = 0x00000080, - ATH_DBG_INTERRUPT = 0x00000100, - ATH_DBG_REGULATORY = 0x00000200, - ATH_DBG_ANI = 0x00000400, - ATH_DBG_POWER_MGMT = 0x00000800, - ATH_DBG_XMIT = 0x00001000, - ATH_DBG_BEACON = 0x00002000, - ATH_DBG_RATE = 0x00004000, - ATH_DBG_CONFIG = 0x00008000, - ATH_DBG_KEYCACHE = 0x00010000, - ATH_DBG_AGGR = 0x00020000, - ATH_DBG_FATAL = 0x00040000, + ATH_DBG_REG_IO = 0x00000002, + ATH_DBG_QUEUE = 0x00000004, + ATH_DBG_EEPROM = 0x00000008, + ATH_DBG_CALIBRATE = 0x00000010, + ATH_DBG_CHANNEL = 0x00000020, + ATH_DBG_INTERRUPT = 0x00000040, + ATH_DBG_REGULATORY = 0x00000080, + ATH_DBG_ANI = 0x00000100, + ATH_DBG_POWER_MGMT = 0x00000200, + ATH_DBG_XMIT = 0x00000400, + ATH_DBG_BEACON = 0x00001000, + ATH_DBG_CONFIG = 0x00002000, + ATH_DBG_KEYCACHE = 0x00004000, + ATH_DBG_FATAL = 0x00008000, ATH_DBG_ANY = 0xffffffff }; #define DBG_DEFAULT (ATH_DBG_FATAL) -#define DPRINTF(sc, _m, _fmt, ...) do { \ - if (sc->sc_debug & (_m)) \ - printk(_fmt , ##__VA_ARGS__); \ - } while (0) - -/***************************/ -/* Load-time Configuration */ -/***************************/ - -/* Per-instance load-time (note: NOT run-time) configurations - * for Atheros Device */ struct ath_config { u32 ath_aggr_prot; u16 txpowlimit; u16 txpowlimit_override; - u8 cabqReadytime; /* Cabq Readytime % */ - u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */ + u8 cabqReadytime; + u8 swBeaconProcess; }; /*************************/ @@ -160,14 +141,13 @@ enum buffer_type { }; 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 */ - u32 bf_type; /* BUF_* (enum buffer_type) */ - /* key type use to encrypt this frame */ + 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 */ + u32 bf_type; /* BUF_* (enum buffer_type) */ u32 bfs_keyix; enum ath9k_key_type bfs_keytype; }; @@ -213,13 +193,6 @@ struct ath_buf { dma_addr_t bf_dmacontext; }; -/* - * reset the rx buffer. - * any new fields added to the athbuf and require - * reset need to be added to this macro. - * currently bf_status is the only one requires that - * requires reset. - */ #define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) /* hw processing complete, desc processed by hal */ @@ -263,11 +236,8 @@ void ath_rx_cleanup(struct ath_softc *sc); int ath_rx_tasklet(struct ath_softc *sc, int flush); #define ATH_TXBUF 512 -/* max number of transmit attempts (tries) */ #define ATH_TXMAXTRY 13 -/* max number of 11n transmit attempts (tries) */ #define ATH_11N_TXMAXTRY 10 -/* max number of tries for management and control frames */ #define ATH_MGT_TXMAXTRY 4 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE @@ -279,22 +249,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush); WME_AC_VO) -/* Wireless Multimedia Extension Defines */ -#define WME_AC_BE 0 /* best effort */ -#define WME_AC_BK 1 /* background */ -#define WME_AC_VI 2 /* video */ -#define WME_AC_VO 3 /* voice */ -#define WME_NUM_AC 4 +#define WME_AC_BE 0 +#define WME_AC_BK 1 +#define WME_AC_VI 2 +#define WME_AC_VO 3 +#define WME_NUM_AC 4 -/* - * Data transmit queue state. One of these exists for each - * hardware transmit queue. Packets sent to us from above - * are assigned to queues based on their priority. Not all - * devices support a complete set of hardware transmit queues. - * For those devices the array sc_ac2q will map multiple - * priorities to fewer hardware queues (typically all to one - * hardware queue). - */ struct ath_txq { u32 axq_qnum; /* hardware q number */ u32 *axq_link; /* link ptr in last TX desc */ @@ -372,14 +332,15 @@ struct ath_xmit_status { #define ATH_TX_BAR 0x04 }; +/* All RSSI values are noise floor adjusted */ struct ath_tx_stat { - int rssi; /* RSSI (noise floor ajusted) */ - int rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int rateieee; /* data rate xmitted (IEEE rate code) */ - int rateKbps; /* data rate xmitted (Kbps) */ - int ratecode; /* phy rate code */ - int flags; /* validity flags */ + int rssi; + int rssictl[ATH_MAX_ANTENNA]; + int rssiextn[ATH_MAX_ANTENNA]; + int rateieee; + int rateKbps; + int ratecode; + int flags; /* if any of ctl,extn chain rssis are valid */ #define ATH_TX_CHAIN_RSSI_VALID 0x01 /* if extn chain rssis are valid */ @@ -415,7 +376,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /**********************/ #define ADDBA_EXCHANGE_ATTEMPTS 10 -#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ +#define ATH_AGGR_DELIM_SZ 4 #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ /* number of delimiters for encryption padding */ #define ATH_AGGR_ENCRYPTDELIM 10 @@ -466,10 +427,9 @@ struct aggr_rifs_param { /* Per-node aggregation state */ struct ath_node_aggr { - struct ath_atx tx; /* node transmit state */ + struct ath_atx tx; }; -/* driver-specific node state */ struct ath_node { struct ath_softc *an_sc; struct ath_node_aggr an_aggr; @@ -500,12 +460,11 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid #define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) -/* driver-specific vap state */ struct ath_vap { - int av_bslot; /* beacon slot index */ - enum ath9k_opmode av_opmode; /* VAP operational mode */ - struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_tx_control av_btxctl; /* txctl information for beacon */ + int av_bslot; + enum ath9k_opmode av_opmode; + struct ath_buf *av_bcbuf; + struct ath_tx_control av_btxctl; }; /*******************/ @@ -518,12 +477,11 @@ struct ath_vap { * number of beacon intervals, the game's up. */ #define BSTUCK_THRESH (9 * ATH_BCBUF) -#define ATH_BCBUF 4 /* number of beacon buffers */ -#define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */ +#define ATH_BCBUF 4 +#define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) -/* beacon configuration */ struct ath_beacon_config { u16 beacon_interval; u16 listen_interval; @@ -674,18 +632,18 @@ struct ath_softc { u8 sc_tx_chainmask; u8 sc_rx_chainmask; enum ath9k_int sc_imask; - enum wireless_mode sc_curmode; /* current phy mode */ + enum wireless_mode sc_curmode; enum PROT_MODE sc_protmode; - u8 sc_nbcnvaps; /* # of vaps sending beacons */ - u16 sc_nvaps; /* # of active virtual ap's */ + u8 sc_nbcnvaps; + u16 sc_nvaps; struct ieee80211_vif *sc_vaps[ATH_BCBUF]; u8 sc_mcastantenna; - u8 sc_defant; /* current default antenna */ - u8 sc_rxotherant; /* rx's on non-default antenna */ + u8 sc_defant; + u8 sc_rxotherant; - struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ + struct ath9k_node_stats sc_halstats; enum ath9k_ht_extprotspacing sc_ht_extprotspacing; enum ath9k_ht_macmode tx_chan_width; @@ -699,22 +657,22 @@ struct ath_softc { } sc_updateslot; /* slot time update fsm */ /* Crypto */ - u32 sc_keymax; /* size of key cache */ - DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */ + u32 sc_keymax; + DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); u8 sc_splitmic; /* split TKIP MIC keys */ /* RX */ struct list_head sc_rxbuf; struct ath_descdma sc_rxdma; - int sc_rxbufsize; /* rx size based on mtu */ - u32 *sc_rxlink; /* link ptr in last RX desc */ + int sc_rxbufsize; + u32 *sc_rxlink; /* TX */ struct list_head sc_txbuf; struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES]; struct ath_descdma sc_txdma; u32 sc_txqsetup; - int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ + int sc_haltype2q[ATH9K_WME_AC_VO+1]; u16 seq_no; /* TX sequence number */ /* Beacon */ @@ -724,13 +682,13 @@ struct ath_softc { struct list_head sc_bbuf; u32 sc_bhalq; u32 sc_bmisscount; - u32 ast_be_xmit; /* beacons transmitted */ + u32 ast_be_xmit; u64 bc_tstamp; /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; - u8 sc_protrix; /* protection rate index */ + u8 sc_protrix; /* Channel, Band */ struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; @@ -755,6 +713,7 @@ struct ath_softc { struct ath_ani sc_ani; }; +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index 466dbce..e180c90 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -116,7 +116,7 @@ static int ath9k_hw_flash_map(struct ath_hal *ah) if (!ahp->ah_cal_mem) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: cannot remap eeprom region \n", __func__); + "cannot remap eeprom region \n"); return -EIO; } @@ -149,7 +149,7 @@ static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) if (!ath9k_hw_use_flash(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading from EEPROM, not flash\n", __func__); + "Reading from EEPROM, not flash\n"); ar5416_eep_start_loc = 256; } @@ -162,8 +162,7 @@ static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, eep_data)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Unable to read eeprom region \n", - __func__); + "Unable to read eeprom region \n"); return false; } eep_data++; @@ -185,12 +184,11 @@ static int ath9k_hw_check_eeprom(struct ath_hal *ah) if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading Magic # failed\n", __func__); + "Reading Magic # failed\n"); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n", - __func__, magic); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -1205,11 +1203,11 @@ bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "PDADC: Chain %d | PDADC %3d Value %3d | " "PDADC %3d Value %3d | PDADC %3d Value %3d | " "PDADC %3d Value %3d |\n", diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 6eef104..b3f2899 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -104,9 +104,10 @@ bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) udelay(AH_TIME_QUANTUM); } - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - __func__, reg, REG_READ(ah, reg), mask, val); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + reg, REG_READ(ah, reg), mask, val); return false; } @@ -188,8 +189,8 @@ u16 ath9k_hw_computetxtime(struct ath_hal *ah, } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: unknown phy %u (rate ix %u)\n", __func__, + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Unknown phy %u (rate ix %u)\n", rates->info[rateix].phy, rateix); txTime = 0; break; @@ -355,9 +356,9 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah) rdData = REG_READ(ah, addr); if (rdData != wrData) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " + "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); + addr, wrData, rdData); return false; } } @@ -367,9 +368,9 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah) rdData = REG_READ(ah, addr); if (wrData != rdData) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " + "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); + addr, wrData, rdData); return false; } } @@ -449,8 +450,7 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); if (ahp == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: cannot allocate memory for state block\n", - __func__); + "Cannot allocate memory for state block\n"); *status = -ENOMEM; return NULL; } @@ -497,8 +497,7 @@ static int ath9k_hw_rfattach(struct ath_hal *ah) rfStatus = ath9k_hw_init_rf(ah, &ecode); if (!rfStatus) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RF setup failed, status %u\n", __func__, - ecode); + "RF setup failed, status %u\n", ecode); return ecode; } @@ -523,9 +522,9 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah) break; default: DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: 5G Radio Chip Rev 0x%02X is not " + "5G Radio Chip Rev 0x%02X is not " "supported by this driver\n", - __func__, ah->ah_analog5GhzRev); + ah->ah_analog5GhzRev); return -EOPNOTSUPP; } @@ -550,7 +549,7 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah) } if (sum == 0 || sum == 0xffff * 3) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: mac address read failed: %pM\n", __func__, + "mac address read failed: %pM\n", ahp->ah_macaddr); return -EADDRNOTAVAIL; } @@ -612,7 +611,7 @@ static int ath9k_hw_post_attach(struct ath_hal *ah) if (!ath9k_hw_chip_test(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: hardware self-test failed\n", __func__); + "hardware self-test failed\n"); return -ENODEV; } @@ -658,15 +657,13 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ahp->ah_intrMitigation = true; if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n"); ecode = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); ecode = -EIO; goto bad; } @@ -682,17 +679,16 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: serialize_regmode is %d\n", - __func__, ah->ah_config.serialize_regmode); + "serialize_regmode is %d\n", + ah->ah_config.serialize_regmode); if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->ah_macVersion != AR_SREV_VERSION_9160) && (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", __func__, - ah->ah_macVersion, ah->ah_macRev); + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->ah_macVersion, ah->ah_macRev); ecode = -EOPNOTSUPP; goto bad; } @@ -737,7 +733,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, + "This Mac Chip Rev 0x%02x.%x is \n", ah->ah_macVersion, ah->ah_macRev); if (AR_SREV_9280_20_OR_LATER(ah)) { @@ -874,7 +870,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, #endif if (!ath9k_hw_fill_cap_info(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s:failed ath9k_hw_fill_cap_info\n", __func__); + "failed ath9k_hw_fill_cap_info\n"); ecode = -EINVAL; goto bad; } @@ -882,8 +878,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ecode = ath9k_hw_init_macaddr(ah); if (ecode != 0) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: failed initializing mac address\n", - __func__); + "failed initializing mac address\n"); goto bad; } @@ -1080,8 +1075,7 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad ack timeout %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); ahp->ah_acktimeout = (u32) -1; return false; } else { @@ -1097,8 +1091,7 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad cts timeout %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); ahp->ah_ctstimeout = (u32) -1; return false; } else { @@ -1115,7 +1108,7 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu) if (tu > 0xFFFF) { DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: bad global tx timeout %u\n", __func__, tu); + "bad global tx timeout %u\n", tu); ahp->ah_globaltxtimeout = (u32) -1; return false; } else { @@ -1129,8 +1122,8 @@ static void ath9k_hw_init_user_settings(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n", - __func__, ahp->ah_miscMode); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n", + ahp->ah_miscMode); if (ahp->ah_miscMode != 0) REG_WRITE(ah, AR_PCU_MISC, @@ -1176,7 +1169,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, break; default: DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "devid=0x%x not supported.\n", devid); + "devid=0x%x not supported.\n", devid); ah = NULL; *error = -ENXIO; break; @@ -1355,13 +1348,13 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, (u32) ah->ah_powerLimit)); if (status != 0) { DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: error init'ing transmit power\n", __func__); + "error init'ing transmit power\n"); return -EIO; } if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: ar5416SetRfRegs failed\n", __func__); + "ar5416SetRfRegs failed\n"); return -EIO; } @@ -1533,8 +1526,7 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) REG_WRITE(ah, (u16) (AR_RTC_RC), 0); if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RTC stuck in MAC reset\n", - __func__); + "RTC stuck in MAC reset\n"); return false; } @@ -1561,8 +1553,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) AR_RTC_STATUS, AR_RTC_STATUS_M, AR_RTC_STATUS_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); return false; } @@ -1641,9 +1632,8 @@ static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, { if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "2GHz or 5GHz\n", __func__, chan->channel, - chan->channelFlags); + "invalid channel %u/0x%x; not marked as " + "2GHz or 5GHz\n", chan->channel, chan->channelFlags); return NULL; } @@ -1652,9 +1642,9 @@ static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, !IS_CHAN_HT20(chan) && !IS_CHAN_HT40(chan)) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " + "invalid channel %u/0x%x; not marked as " "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", - __func__, chan->channel, chan->channelFlags); + chan->channel, chan->channelFlags); return NULL; } @@ -1670,8 +1660,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Transmit frames pending on queue %d\n", - __func__, qnum); + "Transmit frames pending on queue %d\n", qnum); return false; } } @@ -1679,8 +1668,8 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: Could not kill baseband RX\n", __func__); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Could not kill baseband RX\n"); return false; } @@ -1689,13 +1678,13 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, if (AR_SREV_9280_10_OR_LATER(ah)) { if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "failed to set channel\n"); return false; } } else { if (!(ath9k_hw_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "failed to set channel\n"); return false; } } @@ -1707,7 +1696,7 @@ static bool ath9k_hw_channel_change(struct ath_hal *ah, min((u32) MAX_RATE_POWER, (u32) ah->ah_powerLimit)) != 0) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error init'ing transmit power\n", __func__); + "error init'ing transmit power\n"); return false; } @@ -2211,8 +2200,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, if (ath9k_hw_check_chan(ah, chan) == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); ecode = -EINVAL; goto bad; } @@ -2254,8 +2243,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, ath9k_hw_mark_phy_inactive(ah); if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n"); ecode = -EINVAL; goto bad; } @@ -2289,7 +2277,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, if (!ath9k_hw_eeprom_set_board_values(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error setting board options\n", __func__); + "error setting board options\n"); ecode = -EIO; goto bad; } @@ -2379,15 +2367,13 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s CFG Byte Swap Set 0x%x\n", __func__, - mask); + "CFG Byte Swap Set 0x%x\n", mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s Setting CFG 0x%x\n", __func__, - REG_READ(ah, AR_CFG)); + "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { #ifdef __BIG_ENDIAN @@ -2412,7 +2398,7 @@ bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) if (entry >= ah->ah_caps.keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); + "entry %u out of range\n", entry); return false; } @@ -2449,7 +2435,7 @@ bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) if (entry >= ah->ah_caps.keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); + "entry %u out of range\n", entry); return false; } @@ -2485,7 +2471,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, if (entry >= pCap->keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); + "entry %u out of range\n", entry); return false; } @@ -2496,8 +2482,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, case ATH9K_CIPHER_AES_CCM: if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: AES-CCM not supported by " - "mac rev 0x%x\n", __func__, + "AES-CCM not supported by mac rev 0x%x\n", ah->ah_macRev); return false; } @@ -2508,16 +2493,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, if (ATH9K_IS_MIC_ENABLED(ah) && entry + 64 >= pCap->keycache_size) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u inappropriate for TKIP\n", - __func__, entry); + "entry %u inappropriate for TKIP\n", entry); return false; } break; case ATH9K_CIPHER_WEP: if (k->kv_len < LEN_WEP40) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: WEP key length %u too small\n", - __func__, k->kv_len); + "WEP key length %u too small\n", k->kv_len); return false; } if (k->kv_len <= LEN_WEP40) @@ -2532,8 +2515,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, break; default: DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: cipher %u not supported\n", __func__, - k->kv_type); + "cipher %u not supported\n", k->kv_type); return false; } @@ -2682,8 +2664,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hal *ah, } if (i == 0) { DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: Failed to wakeup in %uus\n", - __func__, POWER_UP_TIME / 20); + "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); return false; } } @@ -2705,7 +2686,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah, }; int status = true, setChip = true; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", modes[ahp->ah_powerMode], modes[mode], setChip ? "set chip " : ""); @@ -2722,7 +2703,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: unknown power mode %u\n", __func__, mode); + "Unknown power mode %u\n", mode); return false; } ahp->ah_powerMode = mode; @@ -2899,8 +2880,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (isr & AR_ISR_RXORN) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: receive FIFO overrun interrupt\n", - __func__); + "receive FIFO overrun interrupt\n"); } if (!AR_SREV_9100(ah)) { @@ -2926,27 +2906,23 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI FATAL interrupt\n", - __func__); + "received PCI FATAL interrupt\n"); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI PERR interrupt\n", - __func__); + "received PCI PERR interrupt\n"); } } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", - __func__); + "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", - __func__); + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); @@ -2968,12 +2944,10 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: 0x%x => 0x%x\n", __func__, - omask, ints); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); if (omask & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: disable IER\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -3028,8 +3002,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) mask2 |= AR_IMR_S2_CST; } - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, - mask); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | @@ -3049,8 +3022,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: enable IER\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, @@ -3156,14 +3128,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, else nextTbtt = bs->bs_nexttbtt; - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next DTIM %d\n", __func__, - bs->bs_nextdtim); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__, - nextTbtt); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__, - beaconintval); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__, - dtimperiod); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); @@ -3216,8 +3184,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) else if (ah->ah_currentRD == 0x41) ah->ah_currentRD = 0x43; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: regdomain mapped to 0x%x\n", __func__, - ah->ah_currentRD); + "regdomain mapped to 0x%x\n", ah->ah_currentRD); } eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE); @@ -3823,8 +3790,7 @@ void ath9k_hw_reset_tsf(struct ath_hal *ah) count++; if (count > 10) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n", - __func__); + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); break; } udelay(10); @@ -3849,8 +3815,7 @@ bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); ahp->ah_slottime = (u32) -1; return false; } else { diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index 36955e0..8d2b139 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -25,10 +25,10 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah, struct ath_hal_5416 *ahp = AH5416(ah); DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - __func__, ahp->ah_txOkInterruptMask, - ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask, - ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask); + "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", + ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask, + ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask, + ahp->ah_txUrnInterruptMask); REG_WRITE(ah, AR_IMR_S0, SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) @@ -126,7 +126,7 @@ bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp) bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); @@ -207,9 +207,8 @@ bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) break; DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: TSF have moved while trying to set " - "quiet time TSF: 0x%08x\n", - __func__, tsfLow); + "TSF have moved while trying to set " + "quiet time TSF: 0x%08x\n", tsfLow); } REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); @@ -222,9 +221,8 @@ bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: Failed to stop Tx DMA in 100 " - "msec after killing last frame\n", - __func__); + "Failed to stop Tx DMA in 100 " + "msec after killing last frame\n"); break; } udelay(100); @@ -523,19 +521,17 @@ bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); return false; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -593,15 +589,13 @@ bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); return false; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); return false; } @@ -651,22 +645,21 @@ int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, break; if (q == pCap->total_queues) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: no available tx queue\n", __func__); + "no available tx queue\n"); return -1; } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n", - __func__, type); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type); return -1; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); qi = &ahp->ah_txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: tx queue %u already active\n", __func__, q); + "tx queue %u already active\n", q); return -1; } memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -697,19 +690,16 @@ bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); return false; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; ahp->ah_txOkInterruptMask &= ~(1 << q); @@ -731,19 +721,17 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) u32 cwMin, chanCwMin, value; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); return false; } qi = &ahp->ah_txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); return true; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -976,8 +964,7 @@ bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) reg = REG_READ(ah, AR_OBS_BUS_1); DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: rx failed to go idle in 10 ms RXSM=0x%x\n", - __func__, reg); + "rx failed to go idle in 10 ms RXSM=0x%x\n", reg); return false; } @@ -1022,9 +1009,8 @@ bool ath9k_hw_stopdmarecv(struct ath_hal *ah) if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: dma failed to stop in 10ms\n" + "dma failed to stop in 10ms\n" "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", - __func__, REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); return false; } else { diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index e05eb1f..de059c3 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -38,6 +38,21 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { static void ath_detach(struct ath_softc *sc); +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) +{ + if (!sc) + return; + + if (sc->sc_debug & dbg_mask) { + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "ath9k: "); + vprintk(fmt, args); + va_end(args); + } +} + /* return bus cachesize in 4B word units */ static void bus_read_cachesize(struct ath_softc *sc, int *csz) @@ -175,8 +190,8 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) rate[i].bitrate = rate_table->info[i].ratekbps / 100; rate[i].hw_value = rate_table->info[i].ratecode; sband->n_bitrates++; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Rate: %2dMbps, ratecode: %2d\n", - __func__, rate[i].bitrate / 10, rate[i].hw_value); + DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", + rate[i].bitrate / 10, rate[i].hw_value); } } @@ -198,9 +213,9 @@ static int ath_setup_channels(struct ath_softc *sc) &nregclass, CTRY_DEFAULT, false, 1)) { u32 rd = ah->ah_currentRD; DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to collect channel list; " + "Unable to collect channel list; " "regdomain likely %u country code %u\n", - __func__, rd, CTRY_DEFAULT); + rd, CTRY_DEFAULT); return -EINVAL; } @@ -223,9 +238,9 @@ static int ath_setup_channels(struct ath_softc *sc) band_2ghz->n_channels = ++a; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: 2MHz channel: %d, " + DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, " "channelFlags: 0x%x\n", - __func__, c->channel, c->channelFlags); + c->channel, c->channelFlags); } else if (IS_CHAN_5GHZ(c)) { chan_5ghz[b].band = IEEE80211_BAND_5GHZ; chan_5ghz[b].center_freq = c->channel; @@ -238,9 +253,9 @@ static int ath_setup_channels(struct ath_softc *sc) band_5ghz->n_channels = ++b; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: 5MHz channel: %d, " + DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, " "channelFlags: 0x%x\n", - __func__, c->channel, c->channelFlags); + c->channel, c->channelFlags); } } @@ -274,9 +289,9 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* clear pending tx frames */ - stopped = ath_stoprecv(sc); /* turn off frame recv */ + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, false); + stopped = ath_stoprecv(sc); /* XXX: do not flush receive queue here. We don't want * to flush data frames already in queue because of @@ -286,8 +301,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) fastcc = false; DPRINTF(sc, ATH_DBG_CONFIG, - "%s: (%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", - __func__, + "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", sc->sc_ah->ah_curchan->channel, hchan->channel, hchan->channelFlags, sc->tx_chan_width); @@ -296,8 +310,8 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) 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__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), hchan->channel, hchan->channelFlags, status); @@ -311,7 +325,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); + "Unable to restart recv logic\n"); return -EIO; } @@ -352,8 +366,7 @@ static void ath_ani_calibrate(unsigned long data) /* Long calibration runs independently of short calibration. */ if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", - __func__, jiffies); + DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); sc->sc_ani.sc_longcal_timer = timestamp; } @@ -362,8 +375,7 @@ static void ath_ani_calibrate(unsigned long data) if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= ATH_SHORT_CALINTERVAL) { shortcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", - __func__, jiffies); + DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); sc->sc_ani.sc_shortcal_timer = timestamp; sc->sc_ani.sc_resetcal_timer = timestamp; } @@ -404,15 +416,13 @@ static void ath_ani_calibrate(unsigned long data) ah->ah_curchan); DPRINTF(sc, ATH_DBG_ANI, - "%s: calibrate chan %u/%x nf: %d\n", - __func__, + "calibrate chan %u/%x nf: %d\n", ah->ah_curchan->channel, ah->ah_curchan->channelFlags, sc->sc_ani.sc_noise_floor); } else { DPRINTF(sc, ATH_DBG_ANY, - "%s: calibrate chan %u/%x failed\n", - __func__, + "calibrate chan %u/%x failed\n", ah->ah_curchan->channel, ah->ah_curchan->channelFlags); } @@ -449,8 +459,8 @@ static void ath_update_chainmask(struct ath_softc *sc, int is_ht) sc->sc_rx_chainmask = 1; } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n", - __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); + DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", + sc->sc_tx_chainmask, sc->sc_rx_chainmask); } static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -712,7 +722,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, if (!ath_keyset(sc, key->keyidx, hk, NULL)) { /* Txmic entry failed. No need to proceed further */ DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s Setting TX MIC Key Failed\n", __func__); + "Setting TX MIC Key Failed\n"); return 0; } @@ -836,8 +846,7 @@ static void ath9k_ht_conf(struct ath_softc *sc, ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: BSS Changed HT, chanwidth: %d\n", - __func__, sc->tx_chan_width); + "BSS Changed HT, chanwidth: %d\n", sc->tx_chan_width); } } @@ -863,9 +872,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, int pos; if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", - __func__, - bss_conf->aid); + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d\n", bss_conf->aid); /* New association, store aid */ if (avp->av_opmode == ATH9K_M_STA) { @@ -888,18 +895,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_update_chainmask(sc, hw->conf.ht.enabled); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %pM aid 0x%x\n", - __func__, + "bssid %pM aid 0x%x\n", sc->sc_curbssid, sc->sc_curaid); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); - pos = ath_get_channel(sc, curchan); if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid channel\n", __func__); + "Invalid channel: %d\n", curchan->center_freq); return; } @@ -920,14 +922,15 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* set h/w channel */ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to set channel\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel: %d\n", + curchan->center_freq); + /* Start ANI */ mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); } else { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info DISSOC\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); sc->sc_curaid = 0; } } @@ -1066,8 +1069,8 @@ static void ath_radio_enable(struct ath_softc *sc) sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, ah->ah_curchan->channel, ah->ah_curchan->channelFlags), @@ -1079,7 +1082,7 @@ static void ath_radio_enable(struct ath_softc *sc) ath_update_txpow(sc); if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); + "Unable to restart recv logic\n"); return; } @@ -1124,8 +1127,8 @@ static void ath_radio_disable(struct ath_softc *sc) sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, ah->ah_curchan->channel, ah->ah_curchan->channelFlags), @@ -1205,7 +1208,7 @@ static int ath_sw_toggle_radio(void *data, enum rfkill_state state) sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" - "radio as it is disabled by h/w \n"); + "radio as it is disabled by h/w\n"); return -EPERM; } ath_radio_enable(sc); @@ -1285,7 +1288,7 @@ static void ath_detach(struct ath_softc *sc) struct ieee80211_hw *hw = sc->hw; int i = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); @@ -1340,8 +1343,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah = ath9k_hw_attach(devid, sc, sc->mem, &status); if (ah == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to attach hardware; HAL status %u\n", - __func__, status); + "Unable to attach hardware; HAL status %u\n", status); error = -ENXIO; goto bad; } @@ -1351,8 +1353,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) sc->sc_keymax = ah->ah_caps.keycache_size; if (sc->sc_keymax > ATH_KEYMAX) { DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s: Warning, using only %u entries in %u key cache\n", - __func__, ATH_KEYMAX, sc->sc_keymax); + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, sc->sc_keymax); sc->sc_keymax = ATH_KEYMAX; } @@ -1399,14 +1401,14 @@ static int ath_init(u16 devid, struct ath_softc *sc) sc->sc_bhalq = ath_beaconq_setup(ah); if (sc->sc_bhalq == -1) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup a beacon xmit queue\n", __func__); + "Unable to setup a beacon xmit queue\n"); error = -EIO; goto bad2; } sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->sc_cabq == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup CAB xmit queue\n", __func__); + "Unable to setup CAB xmit queue\n"); error = -EIO; goto bad2; } @@ -1421,30 +1423,26 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* NB: ensure BK queue is the lowest priority h/w queue */ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BK traffic\n", - __func__); + "Unable to setup xmit queue for BK traffic\n"); error = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BE traffic\n", - __func__); + "Unable to setup xmit queue for BE traffic\n"); error = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VI traffic\n", - __func__); + "Unable to setup xmit queue for VI traffic\n"); error = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VO traffic\n", - __func__); + "Unable to setup xmit queue for VO traffic\n"); error = -EIO; goto bad2; } @@ -1556,7 +1554,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc) struct ieee80211_hw *hw = sc->hw; int error = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); error = ath_init(devid, sc); if (error != 0) @@ -1587,8 +1585,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc) error = ath_rate_control_register(); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to register rate control " - "algorithm:%d\n", __func__, error); + "Unable to register rate control algorithm: %d\n", error); ath_rate_control_unregister(); goto bad; } @@ -1656,15 +1653,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) 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); + "Unable to reset hardware; hal status %u\n", status); error = -EIO; } spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); /* * We may be doing a reset in response to a request @@ -1712,13 +1707,12 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct ath_buf *bf; int i, bsize, error; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n", - __func__, name, nbuf, ndesc); + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); /* ath_desc must be a multiple of DWORDs */ if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n", - __func__); + DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); ASSERT((sizeof(struct ath_desc) % 4) == 0); error = -ENOMEM; goto fail; @@ -1754,8 +1748,8 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, goto fail; } ds = dd->dd_desc; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n", - __func__, dd->dd_name, ds, (u32) dd->dd_desc_len, + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + dd->dd_name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); /* allocate buffers */ @@ -1877,14 +1871,14 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath9k_channel *init_channel; int error = 0, pos, status; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " - "initial channel: %d MHz\n", __func__, curchan->center_freq); + DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " + "initial channel: %d MHz\n", curchan->center_freq); /* setup initial channel */ pos = ath_get_channel(sc, curchan); if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); error = -EINVAL; goto error; } @@ -1910,8 +1904,8 @@ static int ath9k_start(struct ieee80211_hw *hw) 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, + "Unable to reset hardware; hal status %u " + "(freq %u flags 0x%x)\n", status, init_channel->channel, init_channel->channelFlags); error = -EIO; spin_unlock_bh(&sc->sc_resetlock); @@ -1934,7 +1928,7 @@ static int ath9k_start(struct ieee80211_hw *hw) */ if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); + "Unable to start recv logic\n"); error = -EIO; goto error; } @@ -2026,12 +2020,10 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (!txctl.txq) goto exit; - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", - __func__, - skb); + DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); if (ath_tx_start(sc, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); goto exit; } @@ -2046,11 +2038,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; if (sc->sc_flags & SC_OP_INVALID) { - DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__); + DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); return; } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); ieee80211_stop_queues(sc->hw); @@ -2075,7 +2067,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) sc->sc_flags |= SC_OP_INVALID; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -2102,14 +2094,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Interface type %d not yet supported\n", - __func__, conf->type); + "Interface type %d not yet supported\n", conf->type); return -EOPNOTSUPP; } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n", - __func__, - ic_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode); /* Set the VAP opmode */ avp->av_opmode = ic_opmode; @@ -2140,7 +2129,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_vap *avp = (void *)conf->vif->drv_priv; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); #ifdef CONFIG_SLOW_ANT_DIV ath_slow_ant_div_stop(&sc->sc_antdiv); @@ -2170,12 +2159,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *curchan = hw->conf.channel; int pos; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, curchan->center_freq); + DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); pos = ath_get_channel(sc, curchan); if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", + curchan->center_freq); return -EINVAL; } @@ -2196,8 +2186,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to set channel\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); return -EINVAL; } } @@ -2247,9 +2236,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, sc->sc_config.ath_aggr_prot = 0; DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %pM aid 0x%x\n", - __func__, rfilt, - sc->sc_curbssid, sc->sc_curaid); + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, sc->sc_curbssid, sc->sc_curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -2326,8 +2314,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, 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); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx_filter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, @@ -2367,20 +2354,14 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, qnum = ath_get_hal_qnum(queue, sc); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Configure tx [queue/halq] [%d/%d], " + "Configure tx [queue/halq] [%d/%d], " "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", - __func__, - queue, - qnum, - params->aifs, - params->cw_min, - params->cw_max, - params->txop); + queue, qnum, params->aifs, params->cw_min, + params->cw_max, params->txop); ret = ath_txq_update(sc, qnum, &qi); if (ret) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: TXQ Update failed\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); return ret; } @@ -2394,7 +2375,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; int ret = 0; - DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__); + DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); switch (cmd) { case SET_KEY: @@ -2427,8 +2408,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) sc->sc_flags |= SC_OP_PREAMBLE_SHORT; @@ -2437,8 +2417,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) @@ -2451,8 +2430,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_ht_conf(sc, bss_conf); if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); ath9k_bss_assoc_info(sc, vif, bss_conf); } @@ -2496,8 +2474,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start TX aggregation\n", - __func__); + "Unable to start TX aggregation\n"); else ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; @@ -2505,8 +2482,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ret = ath_tx_aggr_stop(sc, sta, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop TX aggregation\n", - __func__); + "Unable to stop TX aggregation\n"); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; @@ -2514,8 +2490,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ath_tx_aggr_resume(sc, sta, tid); break; default: - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unknown AMPDU action\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); } return ret; @@ -2571,7 +2546,6 @@ static struct { /* * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. */ - static const char * ath_mac_bb_name(u32 mac_bb_version) { @@ -2589,7 +2563,6 @@ ath_mac_bb_name(u32 mac_bb_version) /* * Return the RF name. "????" is returned if the RF is unknown. */ - static const char * ath_rf_name(u16 rf_version) { @@ -2628,7 +2601,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA consistent " - "DMA enable faled\n"); + "DMA enable failed\n"); goto bad; } @@ -2838,6 +2811,6 @@ module_init(init_ath_pci); static void __exit exit_ath_pci(void) { pci_unregister_driver(&ath_pci_driver); - printk(KERN_INFO "%s: driver unloaded\n", dev_info); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } module_exit(exit_ath_pci); diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index 4f1c8bf..766982a 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c @@ -52,8 +52,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) bModeSynth = 1; } else { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u MHz\n", __func__, - freq); + "Invalid channel %u MHz\n", freq); return false; } @@ -86,7 +85,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u MHz\n", __func__, freq); + "Invalid channel %u MHz\n", freq); return false; } @@ -348,8 +347,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) || ahp->ah_analogBank6TPCData == NULL || ahp->ah_analogBank7Data == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate RF banks\n", - __func__); + "Cannot allocate RF banks\n"); *status = -ENOMEM; return false; } @@ -360,8 +358,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) ahp->ah_iniAddac.ia_columns), GFP_KERNEL); if (ahp->ah_addac5416_21 == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate ah_addac5416_21\n", - __func__); + "Cannot allocate ah_addac5416_21\n"); *status = -ENOMEM; return false; } @@ -371,8 +368,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) ahp->ah_iniBank6.ia_rows), GFP_KERNEL); if (ahp->ah_bank6Temp == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate ah_bank6Temp\n", - __func__); + "Cannot allocate ah_bank6Temp\n"); *status = -ENOMEM; return false; } diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 7c08583..7d5affd 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1326,13 +1326,13 @@ static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, mode = ATH9K_MODE_11NA_HT40PLUS; break; default: - DPRINTF(sc, ATH_DBG_RATE, "Invalid band\n"); + DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n"); return NULL; } BUG_ON(mode >= ATH9K_MODE_MAX); - DPRINTF(sc, ATH_DBG_RATE, "Choosing rate table for mode: %d\n", mode); + DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); return sc->hw_rate_table[mode]; } @@ -1572,8 +1572,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to allocate private rc structure\n", - __func__); + "Unable to allocate private rc structure\n"); return NULL; } diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index e49e323..0b9a3d9 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -105,8 +105,7 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) skb_reserve(skb, sc->sc_cachelsz - off); } else { DPRINTF(sc, ATH_DBG_FATAL, - "%s: skbuff alloc of size %u failed\n", - __func__, len); + "skbuff alloc of size %u failed\n", len); return NULL; } @@ -263,11 +262,7 @@ static void ath_opmode_init(struct ath_softc *sc) /* calculate and install multicast filter */ mfilt[0] = mfilt[1] = ~0; - ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); - DPRINTF(sc, ATH_DBG_CONFIG , - "%s: RX filter 0x%x, MC filter %08x:%08x\n", - __func__, rfilt, mfilt[0], mfilt[1]); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -285,8 +280,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) min(sc->sc_cachelsz, (u16)64)); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: cachelsz %u rxbufsize %u\n", - __func__, sc->sc_cachelsz, sc->sc_rxbufsize); + DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + sc->sc_cachelsz, sc->sc_rxbufsize); /* Initialize rx descriptors */ @@ -294,8 +289,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) "rx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate rx descriptors: %d\n", - __func__, error); + "failed to allocate rx descriptors: %d\n", error); break; } diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 62e2888..e3dd91f 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -78,8 +78,7 @@ static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah) return true; } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid regulatory domain/country code 0x%x\n", - __func__, rd); + "invalid regulatory domain/country code 0x%x\n", rd); return false; } @@ -107,13 +106,12 @@ static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah, return true; rd = ath9k_regd_get_eepromRD(ah); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n", - __func__, rd); + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd); if (rd & COUNTRY_ERD_FLAG) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: EEPROM setting is country code %u\n", - __func__, rd & ~COUNTRY_ERD_FLAG); + "EEPROM setting is country code %u\n", + rd & ~COUNTRY_ERD_FLAG); return cc == (rd & ~COUNTRY_ERD_FLAG); } @@ -290,8 +288,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, } if (!found) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find reg domain pair %u\n", - __func__, regDmn); + "Failed to find reg domain pair %u\n", regDmn); return false; } if (!(channelFlag & CHANNEL_2GHZ)) { @@ -307,8 +304,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, found = ath9k_regd_is_valid_reg_domain(regDmn, rd); if (!found) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find unitary reg domain %u\n", - __func__, regDmn); + "Failed to find unitary reg domain %u\n", regDmn); return false; } else { rd->pscan &= regPair->pscanMask; @@ -430,30 +426,27 @@ ath9k_regd_add_channel(struct ath_hal *ah, if (!(c_lo <= c && c <= c_hi)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u out of range [%u..%u]\n", - __func__, c, c_lo, c_hi); + "c %u out of range [%u..%u]\n", + c, c_lo, c_hi); return false; } if ((fband->channelBW == CHANNEL_HALF_BW) && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u half rate channel\n", - __func__, c); + "Skipping %u half rate channel\n", c); return false; } if ((fband->channelBW == CHANNEL_QUARTER_BW) && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u quarter rate channel\n", - __func__, c); + "Skipping %u quarter rate channel\n", c); return false; } if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u > maxChan %u\n", - __func__, c, maxChan); + "c %u > maxChan %u\n", c, maxChan); return false; } @@ -606,8 +599,7 @@ static bool ath9k_regd_japan_check(struct ath_hal *ah, } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %d freq band\n", - __func__, j_bandcheck[i].freqbandbit); + "Skipping %d freq band\n", j_bandcheck[i].freqbandbit); return skipband; } @@ -632,20 +624,19 @@ ath9k_regd_init_channels(struct ath_hal *ah, unsigned long *modes_avail; DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n", - __func__, cc, + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc, enableOutdoor ? "Enable outdoor" : "", enableExtendedChannels ? "Enable ecm" : ""); if (!ath9k_regd_is_ccode_valid(ah, cc)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid country code %d\n", __func__, cc); + "Invalid country code %d\n", cc); return false; } if (!ath9k_regd_is_eeprom_valid(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid EEPROM contents\n", __func__); + "Invalid EEPROM contents\n"); return false; } @@ -693,9 +684,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, ~CHANNEL_2GHZ, &rd5GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary " + "Couldn't find unitary " "5GHz reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } if (!ath9k_regd_get_wmode_regdomain(ah, @@ -703,9 +694,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, CHANNEL_2GHZ, &rd2GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 2GHz " + "Couldn't find unitary 2GHz " "reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } @@ -717,9 +708,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, ~CHANNEL_2GHZ, &rd5GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 5GHz " + "Couldn't find unitary 5GHz " "reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } } @@ -749,15 +740,14 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (!test_bit(cm->mode, modes_avail)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: !avail mode %d flags 0x%x\n", - __func__, cm->mode, cm->flags); + "!avail mode %d flags 0x%x\n", + cm->mode, cm->flags); continue; } if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channels 0x%x not supported " - "by hardware\n", - __func__, cm->flags); + "channels 0x%x not supported " + "by hardware\n", cm->flags); continue; } @@ -788,8 +778,7 @@ ath9k_regd_init_channels(struct ath_hal *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Unknown HAL mode 0x%x\n", __func__, - cm->mode); + "Unknown HAL mode 0x%x\n", cm->mode); continue; } @@ -841,9 +830,8 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (next >= maxchans) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels " - "for channel table\n", - __func__); + "too many channels " + "for channel table\n"); goto done; } if (ath9k_regd_add_channel(ah, @@ -869,9 +857,8 @@ done: if (next > ARRAY_SIZE(ah->ah_channels)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels %u; truncating to %u\n", - __func__, next, - (int) ARRAY_SIZE(ah->ah_channels)); + "too many channels %u; truncating to %u\n", + next, (int) ARRAY_SIZE(ah->ah_channels)); next = ARRAY_SIZE(ah->ah_channels); } #ifdef ATH_NF_PER_CHAN @@ -919,7 +906,7 @@ ath9k_regd_check_channel(struct ath_hal *ah, int n, lim; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x (0x%x) requested\n", __func__, + "channel %u/0x%x (0x%x) requested\n", c->channel, c->channelFlags, flags); cc = ah->ah_curchan; @@ -950,15 +937,15 @@ ath9k_regd_check_channel(struct ath_hal *ah, d = flags - (cc->channelFlags & CHAN_FLAGS); } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x d %d\n", __func__, + "channel %u/0x%x d %d\n", cc->channel, cc->channelFlags, d); if (d > 0) { base = cc + 1; lim--; } } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n", - __func__, c->channel, c->channelFlags); + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n", + c->channel, c->channelFlags); return NULL; } diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 413fbdd..fc52f61 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -83,18 +83,16 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, 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); + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); if (txq->axq_link == NULL) { ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); DPRINTF(sc, ATH_DBG_XMIT, - "%s: TXDP[%u] = %llx (%p)\n", - __func__, txq->axq_qnum, - ito64(bf->bf_daddr), bf->bf_desc); + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } else { *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, "%s: link[%u] (%p)=%llx (%p)\n", - __func__, + DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", txq->axq_qnum, txq->axq_link, ito64(bf->bf_daddr), bf->bf_desc); } @@ -109,8 +107,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - DPRINTF(sc, ATH_DBG_XMIT, - "%s: TX complete: skb: %p\n", __func__, skb); + DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { @@ -983,8 +980,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) int txok, nbad = 0; int status; - DPRINTF(sc, ATH_DBG_QUEUE, - "%s: tx queue %d (%x), link %p\n", __func__, + DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); @@ -1116,9 +1112,9 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) struct ath_hal *ah = sc->sc_ah; (void) ath9k_hw_stoptxdma(ah, txq->axq_qnum); - DPRINTF(sc, ATH_DBG_XMIT, "%s: tx queue [%u] %x, link %p\n", - __func__, txq->axq_qnum, - ath9k_hw_gettxbuf(ah, txq->axq_qnum), txq->axq_link); + DPRINTF(sc, ATH_DBG_XMIT, "tx queue [%u] %x, link %p\n", + txq->axq_qnum, ath9k_hw_gettxbuf(ah, txq->axq_qnum), + txq->axq_link); } /* Drain only the data queues */ @@ -1142,8 +1138,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) if (npend) { /* TxDMA not stopped, reset the hal */ - DPRINTF(sc, ATH_DBG_XMIT, - "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, @@ -1153,8 +1148,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) sc->sc_ht_extprotspacing, true, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, + "Unable to reset hardware; hal status %u\n", status); } spin_unlock_bh(&sc->sc_resetlock); @@ -1194,7 +1188,6 @@ static void ath_tx_addto_baw(struct ath_softc *sc, * Function to send an A-MPDU * NB: must be called with txq lock held */ - static int ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head *bf_head, @@ -1242,7 +1235,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, * looks up the rate * returns aggr limit based on lowest of the rates */ - static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) @@ -1310,7 +1302,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, * meet the minimum required mpdudensity. * caller should make sure that the rate is HT rate . */ - static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, @@ -1382,7 +1373,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, * For aggregation from software buffer queue. * NB: must be called with txq lock held */ - static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head *bf_q, @@ -1505,7 +1495,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * process pending frames possibly doing a-mpdu aggregation * NB: must be called with txq lock held */ - static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { @@ -1635,7 +1624,6 @@ static void ath_tid_drain(struct ath_softc *sc, * Drain all pending buffers * NB: must be called with txq lock held */ - static void ath_txq_drain_pending_buffers(struct ath_softc *sc, struct ath_txq *txq) { @@ -1795,8 +1783,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, bf = ath_tx_get_buffer(sc); if (!bf) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX buffers are full\n", - __func__); + DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); return -1; } @@ -1820,8 +1807,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate tx descriptors: %d\n", - __func__, error); + "Failed to allocate tx descriptors: %d\n", + error); break; } @@ -1830,9 +1817,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) "beacon", ATH_BCBUF, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate " - "beacon descripotrs: %d\n", - __func__, error); + "Failed to allocate beacon descriptors: %d\n", + error); break; } @@ -1904,8 +1890,8 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) } if (qnum >= ARRAY_SIZE(sc->sc_txq)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: hal qnum %u out of range, max %u!\n", - __func__, qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq)); + "qnum %u out of range, max %u!\n", + qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq)); ath9k_hw_releasetxqueue(ah, qnum); return NULL; } @@ -1950,8 +1936,8 @@ int ath_tx_setup(struct ath_softc *sc, int haltype) if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: HAL AC %u out of range, max %zu!\n", - __func__, haltype, ARRAY_SIZE(sc->sc_haltype2q)); + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->sc_haltype2q)); return 0; } txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); @@ -1970,8 +1956,7 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) case ATH9K_TX_QUEUE_DATA: if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: HAL AC %u out of range, max %zu!\n", - __func__, + "HAL AC %u out of range, max %zu!\n", haltype, ARRAY_SIZE(sc->sc_haltype2q)); return -1; } @@ -2004,8 +1989,8 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) /* Try to avoid running out of descriptors */ if (txq->axq_depth >= (ATH_TXBUF - 20)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: TX queue: %d is full, depth: %d\n", - __func__, qnum, txq->axq_depth); + "TX queue: %d is full, depth: %d\n", + qnum, txq->axq_depth); ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); txq->stopped = 1; spin_unlock_bh(&txq->axq_lock); @@ -2047,8 +2032,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to update hardware queue %u!\n", - __func__, qnum); + "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */ @@ -2167,7 +2151,7 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) * we go to INIT state */ 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__, + DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n", ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); } @@ -2267,8 +2251,6 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__); - if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */ return; @@ -2501,8 +2483,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) if (hdrlen & 3) { padsize = hdrlen % 4; if (skb_headroom(skb) < padsize) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding " - "failed\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); dev_kfree_skb_any(skb); return; } @@ -2512,12 +2493,10 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) txctl.txq = sc->sc_cabq; - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", - __func__, - skb); + DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); if (ath_tx_start(sc, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); goto exit; } -- cgit v1.1 From 88b126af946e7ea789f2a52d9d25aca681f93067 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 28 Nov 2008 22:19:02 +0530 Subject: ath9k: Add ATH9K_DEBUG configuration option Make debugging configurable, and add a module parameter to give the debug mask. Add debug.c to hold all debug specific code. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/Kconfig | 11 ++++++++++ drivers/net/wireless/ath9k/Makefile | 2 ++ drivers/net/wireless/ath9k/core.h | 21 ++++++++++++++++++- drivers/net/wireless/ath9k/debug.c | 40 +++++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath9k/main.c | 18 ++--------------- 5 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 drivers/net/wireless/ath9k/debug.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 80a6924..c43bd32 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath9k/Kconfig @@ -9,3 +9,14 @@ config ATH9K Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. If you choose to build a module, it'll be called ath9k. + +config ATH9K_DEBUG + bool "Atheros ath9k debugging" + depends on ATH9K + ---help--- + Say Y, if you need ath9k to display debug messages. + Pass the debug mask as a module parameter: + + modprobe ath9k debug=0x00002000 + + Look in ath9k/core.h for possible debug masks diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index c741e8d..1209d14 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -11,4 +11,6 @@ ath9k-y += hw.o \ xmit.o \ rc.o +ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o + obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index ae32b2c..50bef47 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -105,6 +105,24 @@ enum ATH_DEBUG { #define DBG_DEFAULT (ATH_DBG_FATAL) +#ifdef CONFIG_ATH9K_DEBUG + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); +void ath9k_init_debug(struct ath_softc *sc); + +#else + +static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, + const char *fmt, ...) +{ +} + +static inline ath9k_init_debug(struct ath_softc *sc) +{ +} + +#endif + struct ath_config { u32 ath_aggr_prot; u16 txpowlimit; @@ -619,7 +637,9 @@ struct ath_softc { u8 sc_myaddr[ETH_ALEN]; u8 sc_bssidmask[ETH_ALEN]; +#ifdef CONFIG_ATH9K_DEBUG int sc_debug; +#endif u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ unsigned int rx_filter; @@ -713,7 +733,6 @@ struct ath_softc { struct ath_ani sc_ani; }; -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c new file mode 100644 index 0000000..31af7cc --- /dev/null +++ b/drivers/net/wireless/ath9k/debug.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" + +static unsigned int ath9k_debug = DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) +{ + if (!sc) + return; + + if (sc->sc_debug & dbg_mask) { + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "ath9k: "); + vprintk(fmt, args); + va_end(args); + } +} + +void ath9k_init_debug(struct ath_softc *sc) +{ + sc->sc_debug = ath9k_debug; +} diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index de059c3..9e7045d 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -38,21 +38,6 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { static void ath_detach(struct ath_softc *sc); -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) -{ - if (!sc) - return; - - if (sc->sc_debug & dbg_mask) { - va_list args; - - va_start(args, fmt); - printk(KERN_DEBUG "ath9k: "); - vprintk(fmt, args); - va_end(args); - } -} - /* return bus cachesize in 4B word units */ static void bus_read_cachesize(struct ath_softc *sc, int *csz) @@ -1325,7 +1310,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; - sc->sc_debug = DBG_DEFAULT; + + ath9k_init_debug(sc); spin_lock_init(&sc->sc_resetlock); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); -- cgit v1.1 From 16d68abee5d700bfe09ae8324dbb76028995c589 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 28 Nov 2008 22:19:42 +0530 Subject: ath9k: Remove includes that are not needed Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 50bef47..4493879 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -17,27 +17,8 @@ #ifndef CORE_H #define CORE_H -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include #include -- cgit v1.1 From 826d268091f0e0ecc50103f648b6183eb3efe04d Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 28 Nov 2008 22:20:23 +0530 Subject: ath9k: Add initial layout for an ath9k specific debugfs mechanism Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 20 ++++++++++++++++---- drivers/net/wireless/ath9k/debug.c | 26 +++++++++++++++++++++++--- drivers/net/wireless/ath9k/main.c | 4 +++- 3 files changed, 42 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 4493879..5b75558 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -88,8 +88,15 @@ enum ATH_DEBUG { #ifdef CONFIG_ATH9K_DEBUG +struct ath9k_debug { + int debug_mask; + struct dentry *debugfs_root; + struct dentry *debugfs_phy; +}; + void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); -void ath9k_init_debug(struct ath_softc *sc); +int ath9k_init_debug(struct ath_softc *sc); +void ath9k_exit_debug(struct ath_softc *sc); #else @@ -98,11 +105,16 @@ static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, { } -static inline ath9k_init_debug(struct ath_softc *sc) +static inline int ath9k_init_debug(struct ath_softc *sc) { + return 0; } -#endif +static inline void ath9k_exit_debug(struct ath_softc *sc) +{ +} + +#endif /* CONFIG_ATH9K_DEBUG */ struct ath_config { u32 ath_aggr_prot; @@ -619,7 +631,7 @@ struct ath_softc { u8 sc_bssidmask[ETH_ALEN]; #ifdef CONFIG_ATH9K_DEBUG - int sc_debug; + struct ath9k_debug sc_debug; #endif u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index 31af7cc..c146e48 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c @@ -24,7 +24,7 @@ void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) if (!sc) return; - if (sc->sc_debug & dbg_mask) { + if (sc->sc_debug.debug_mask & dbg_mask) { va_list args; va_start(args, fmt); @@ -34,7 +34,27 @@ void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) } } -void ath9k_init_debug(struct ath_softc *sc) +int ath9k_init_debug(struct ath_softc *sc) { - sc->sc_debug = ath9k_debug; + sc->sc_debug.debug_mask = ath9k_debug; + + sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!sc->sc_debug.debugfs_root) + goto err; + + sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + sc->sc_debug.debugfs_root); + if (!sc->sc_debug.debugfs_phy) + goto err; + + return 0; +err: + ath9k_exit_debug(sc); + return -ENOMEM; +} + +void ath9k_exit_debug(struct ath_softc *sc) +{ + debugfs_remove(sc->sc_debug.debugfs_phy); + debugfs_remove(sc->sc_debug.debugfs_root); } diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 9e7045d..7138964 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1299,6 +1299,7 @@ static void ath_detach(struct ath_softc *sc) ath_tx_cleanupq(sc, &sc->sc_txq[i]); ath9k_hw_detach(sc->sc_ah); + ath9k_exit_debug(sc); } static int ath_init(u16 devid, struct ath_softc *sc) @@ -1311,7 +1312,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; - ath9k_init_debug(sc); + if (ath9k_init_debug(sc) < 0) + printk(KERN_ERR "Unable to create debugfs files\n"); spin_lock_init(&sc->sc_resetlock); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); -- cgit v1.1 From 2a163c6de452c0b321396caceac5d163949b4cf2 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 28 Nov 2008 22:21:08 +0530 Subject: ath9k: Add a debugfs file for dumping DMA status Debugfs file location: ath9k//dma Contains values in DMA debug registers. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 1 - drivers/net/wireless/ath9k/beacon.c | 1 - drivers/net/wireless/ath9k/core.h | 1 + drivers/net/wireless/ath9k/debug.c | 100 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath9k/mac.c | 72 -------------------------- drivers/net/wireless/ath9k/main.c | 1 + 6 files changed, 102 insertions(+), 74 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 5b9bc54..9eaa3fc 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -1009,7 +1009,6 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); /* MAC (PCU/QCU) */ -void ath9k_hw_dmaRegDump(struct ath_hal *ah); u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp); bool ath9k_hw_txstart(struct ath_hal *ah, u32 q); diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 88fbfe5..ca5782f 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -492,7 +492,6 @@ void ath9k_beacon_tasklet(unsigned long data) DPRINTF(sc, ATH_DBG_BEACON, "beacon is officially " "stuck\n"); - ath9k_hw_dmaRegDump(ah); } } else { DPRINTF(sc, ATH_DBG_BEACON, diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 5b75558..8c11c0f 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -92,6 +92,7 @@ struct ath9k_debug { int debug_mask; struct dentry *debugfs_root; struct dentry *debugfs_phy; + struct dentry *debugfs_dma; }; void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index c146e48..da52812 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c @@ -15,6 +15,8 @@ */ #include "core.h" +#include "reg.h" +#include "hw.h" static unsigned int ath9k_debug = DBG_DEFAULT; module_param_named(debug, ath9k_debug, uint, 0); @@ -34,6 +36,98 @@ void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) } } +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_dma(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hal *ah = sc->sc_ah; + char buf[1024]; + unsigned int len = 0; + u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; + int i, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase = &val[0], *dcuBase = &val[4]; + + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + len += snprintf(buf + len, sizeof(buf) - len, + "Raw DMA Debug values:\n"); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { + if (i % 4 == 0) + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); + len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", + i, val[i]); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); + len += snprintf(buf + len, sizeof(buf) - len, + "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + + len += snprintf(buf + len, sizeof(buf) - len, + "%2d %2x %1x %2x %2x\n", + i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), + val[2] & (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_stitch state: %2x qcu_fetch state: %2x\n", + (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_complete state: %2x dcu_complete state: %2x\n", + (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); + len += snprintf(buf + len, sizeof(buf) - len, + "dcu_arb state: %2x dcu_fp state: %2x\n", + (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); + len += snprintf(buf + len, sizeof(buf) - len, + "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", + (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", + (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", + (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); + + len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", + REG_READ(ah, AR_OBS_BUS_1)); + len += snprintf(buf + len, sizeof(buf) - len, + "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_dma = { + .read = read_file_dma, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + int ath9k_init_debug(struct ath_softc *sc) { sc->sc_debug.debug_mask = ath9k_debug; @@ -47,6 +141,11 @@ int ath9k_init_debug(struct ath_softc *sc) if (!sc->sc_debug.debugfs_phy) goto err; + sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->sc_debug.debugfs_phy, sc, &fops_dma); + if (!sc->sc_debug.debugfs_dma) + goto err; + return 0; err: ath9k_exit_debug(sc); @@ -55,6 +154,7 @@ err: void ath9k_exit_debug(struct ath_softc *sc) { + debugfs_remove(sc->sc_debug.debugfs_dma); debugfs_remove(sc->sc_debug.debugfs_phy); debugfs_remove(sc->sc_debug.debugfs_root); } diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index 8d2b139..a4e9898 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -40,78 +40,6 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah, AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); } -void ath9k_hw_dmaRegDump(struct ath_hal *ah) -{ - u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; - int qcuOffset = 0, dcuOffset = 0; - u32 *qcuBase = &val[0], *dcuBase = &val[4]; - int i; - - REG_WRITE(ah, AR_MACMISC, - ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | - (AR_MACMISC_MISC_OBS_BUS_1 << - AR_MACMISC_MISC_OBS_BUS_MSB_S))); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n"); - - for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { - if (i % 4 == 0) - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - - val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); - - for (i = 0; i < ATH9K_NUM_QUEUES; - i++, qcuOffset += 4, dcuOffset += 5) { - if (i == 8) { - qcuOffset = 0; - qcuBase++; - } - - if (i == 6) { - dcuOffset = 0; - dcuBase++; - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%2d %2x %1x %2x %2x\n", - i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, - (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), - val[2] & (0x7 << (i * 3)) >> (i * 3), - (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_stitch state: %2x qcu_fetch state: %2x\n", - (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_complete state: %2x dcu_complete state: %2x\n", - (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "dcu_arb state: %2x dcu_fp state: %2x\n", - (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", - (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", - (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", - (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n", - REG_READ(ah, AR_OBS_BUS_1)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "AR_CR 0x%x \n", REG_READ(ah, AR_CR)); -} - u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) { return REG_READ(ah, AR_QTXDP(q)); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7138964..ac37605 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -17,6 +17,7 @@ #include #include "core.h" #include "reg.h" +#include "hw.h" #define ATH_PCI_VERSION "0.1" -- cgit v1.1 From c772a08ba7192fa5450f85ef53adcbc6e0c5e1c9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:33:57 +0100 Subject: p54: revamp station power save management in access point mode This patch addresses the problem in: http://marc.info/?l=linux-wireless&m=122727674810057&w=2 Thanks to Stefan Steuerwald extensive iPod touch tests. We could finally squash some bugs in p54's master mode / access point implementation. Let's hope we got everything right this time and all stations from now on will wake up on TIM and receive their queued frames and go to sleep again without any hiccups. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 73 ++++++++++++++++++++++++------------ drivers/net/wireless/p54/p54common.h | 2 +- 2 files changed, 49 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6023926..de92b58 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -652,6 +652,10 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + priv->tx_stats[entry_data->hw_queue].len--; + if (unlikely(entry == priv->cached_beacon)) { kfree_skb(entry); priv->cached_beacon = NULL; @@ -668,8 +672,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); - entry_hdr = (struct p54_hdr *) entry->data; - entry_data = (struct p54_tx_data *) entry_hdr->data; if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) pad = entry_data->align[0]; @@ -687,7 +689,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) } } - priv->tx_stats[entry_data->hw_queue].len--; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && (!payload->status)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -1004,6 +1005,38 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) return 0; } +static void p54_sta_notify_ps(struct ieee80211_hw *dev, + enum sta_notify_ps_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + switch (notify_cmd) { + case STA_NOTIFY_AWAKE: + p54_sta_unlock(dev, sta->addr); + break; + default: + break; + } +} + +static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + switch (notify_cmd) { + case STA_NOTIFY_ADD: + case STA_NOTIFY_REMOVE: + /* + * Notify the firmware that we don't want or we don't + * need to buffer frames for this station anymore. + */ + + p54_sta_unlock(dev, sta->addr); + break; + default: + break; + } +} + static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) { struct p54_common *priv = dev->priv; @@ -1069,7 +1102,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, if (info->control.sta) *aid = info->control.sta->aid; else - *flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL; + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; } return ret; } @@ -1082,7 +1115,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_hdr *hdr; struct p54_tx_data *txhdr; size_t padding, len, tim_len = 0; - int i, j, ridx; + int i, j, ridx, ret; u16 hdr_flags = 0, aid = 0; u8 rate, queue; u8 cts_rate = 0x20; @@ -1092,30 +1125,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) queue = skb_get_queue_mapping(skb); - if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) { - current_queue = &priv->tx_stats[queue]; - if (unlikely(current_queue->len > current_queue->limit)) - return NETDEV_TX_BUSY; - current_queue->len++; - current_queue->count++; - if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); - } + ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid); + current_queue = &priv->tx_stats[queue]; + if (unlikely((current_queue->len > current_queue->limit) && ret)) + return NETDEV_TX_BUSY; + current_queue->len++; + current_queue->count++; + if ((current_queue->len == current_queue->limit) && ret) + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) { - if (info->control.sta) - if (p54_sta_unlock(dev, info->control.sta->addr)) { - if (current_queue) { - current_queue->len--; - current_queue->count--; - } - return NETDEV_TX_BUSY; - } - } - txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); @@ -1834,6 +1855,8 @@ static const struct ieee80211_ops p54_ops = { .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, .set_tim = p54_set_tim, + .sta_notify_ps = p54_sta_notify_ps, + .sta_notify = p54_sta_notify, .config = p54_config, .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 3419f16..d292ffb 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -302,7 +302,7 @@ enum p54_frame_sent_status { P54_TX_OK = 0, P54_TX_FAILED, P54_TX_PSM, - P54_TX_PSM_CANCELLED + P54_TX_PSM_CANCELLED = 4 }; struct p54_frame_sent { -- cgit v1.1 From 25900ef0191af98bbb24d8088c6887af31c1ba27 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:34:37 +0100 Subject: p54: utilize cryptographic accelerator This patch allows p54 to utilize its WEP, TKIP and CCMP accelerator. Tested-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 + drivers/net/wireless/p54/p54common.c | 179 ++++++++++++++++++++++++++++++++--- 2 files changed, 168 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 491ab96..ebe1ea1 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -115,6 +115,8 @@ struct p54_common { int noise; void *eeprom; struct completion eeprom_comp; + u8 privacy_caps; + u8 rx_keycache_size; }; 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 de92b58..6f7e82b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -25,6 +25,9 @@ #include "p54.h" #include "p54common.h" +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); @@ -185,6 +188,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; + priv->privacy_caps = desc->privacy_caps; + priv->rx_keycache_size = desc->rx_keycache_size; if (le32_to_cpu(bootrec->len) == 11) priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else @@ -228,6 +233,16 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) dev->queues = 4; } + if (!modparam_nohwcrypt) + printk(KERN_INFO "%s: cryptographic accelerator " + "WEP:%s, TKIP:%s, CCMP:%s\n", + wiphy_name(dev->wiphy), + (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : + "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | + BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", + (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? + "YES" : "no"); + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -526,6 +541,12 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) return 0; } + if (hdr->decrypt_status == P54_DECRYPT_OK) + rx_status.flag |= RX_FLAG_DECRYPTED; + if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || + (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) + rx_status.flag |= RX_FLAG_MMIC_ERROR; + rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; /* XX correct? */ @@ -1107,6 +1128,20 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, return ret; } +static u8 p54_convert_algo(enum ieee80211_key_alg alg) +{ + switch (alg) { + case ALG_WEP: + return P54_CRYPTO_WEP; + case ALG_TKIP: + return P54_CRYPTO_TKIPMICHAEL; + case ALG_CCMP: + return P54_CRYPTO_AESCCMP; + default: + return 0; + } +} + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1117,7 +1152,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) size_t padding, len, tim_len = 0; int i, j, ridx, ret; u16 hdr_flags = 0, aid = 0; - u8 rate, queue; + u8 rate, queue, crypt_offset = 0; u8 cts_rate = 0x20; u8 rc_flags; u8 calculated_tries[4]; @@ -1137,12 +1172,25 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; + if (info->control.hw_key) { + crypt_offset = ieee80211_get_hdrlen_from_skb(skb); + if (info->control.hw_key->alg == ALG_TKIP) { + u8 *iv = (u8 *)(skb->data + crypt_offset); + /* + * The firmware excepts that the IV has to have + * this special format + */ + iv[1] = iv[0]; + iv[0] = iv[2]; + iv[2] = 0; + } + } + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; - hdr->len = cpu_to_le16(len); hdr->type = cpu_to_le16(aid); hdr->rts_tries = info->control.rates[0].count; @@ -1217,10 +1265,27 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) /* TODO: enable bursting */ hdr->flags = cpu_to_le16(hdr_flags); hdr->tries = ridx; - txhdr->crypt_offset = 0; txhdr->rts_rate_idx = 0; - txhdr->key_type = 0; - txhdr->key_len = 0; + if (info->control.hw_key) { + crypt_offset += info->control.hw_key->iv_len; + txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); + txhdr->key_len = min((u8)16, info->control.hw_key->keylen); + memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); + if (info->control.hw_key->alg == ALG_TKIP) { + if (unlikely(skb_tailroom(skb) < 12)) + goto err; + /* reserve space for the MIC key */ + len += 8; + memcpy(skb_put(skb, 8), &(info->control.hw_key->key + [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + } + /* reserve some space for ICV */ + len += info->control.hw_key->icv_len; + } else { + txhdr->key_type = 0; + txhdr->key_len = 0; + } + txhdr->crypt_offset = crypt_offset; txhdr->hw_queue = queue; if (current_queue) txhdr->backlog = current_queue->len; @@ -1234,17 +1299,20 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (padding) txhdr->align[0] = padding; + hdr->len = cpu_to_le16(len); /* modifies skb->cb and with it info, so must be last! */ - if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) { - skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); - if (current_queue) { - current_queue->len--; - current_queue->count--; - } - return NETDEV_TX_BUSY; - } + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) + goto err; priv->tx(dev, skb, 0); return 0; + + err: + skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + if (current_queue) { + current_queue->len--; + current_queue->count--; + } + return NETDEV_TX_BUSY; } static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) @@ -1848,6 +1916,90 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, } +static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_keycache *rxkey; + u8 algo = 0; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + if (cmd == DISABLE_KEY) + algo = 0; + else { + switch (key->alg) { + case ALG_TKIP: + if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | + BR_DESC_PRIV_CAP_TKIP))) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_TKIPMICHAEL; + break; + case ALG_WEP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_WEP; + break; + case ALG_CCMP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_AESCCMP; + break; + default: + return -EINVAL; + } + } + + if (key->keyidx > priv->rx_keycache_size) { + /* + * The device supports the choosen algorithm, but the firmware + * does not provide enough key slots to store all of them. + * So, incoming frames have to be decoded by the mac80211 stack, + * but we can still offload encryption for outgoing frames. + */ + + return 0; + } + + mutex_lock(&priv->conf_mutex); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_RX_KEYCACHE, + GFP_ATOMIC); + if (!skb) { + mutex_unlock(&priv->conf_mutex); + return -ENOMEM; + } + + /* TODO: some devices have 4 more free slots for rx keys */ + rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey->entry = key->keyidx; + rxkey->key_id = key->keyidx; + rxkey->key_type = algo; + if (address) + memcpy(rxkey->mac, address, ETH_ALEN); + else + memset(rxkey->mac, ~0, ETH_ALEN); + if (key->alg != ALG_TKIP) { + rxkey->key_len = min((u8)16, key->keylen); + memcpy(rxkey->key, key->key, rxkey->key_len); + } else { + rxkey->key_len = 24; + memcpy(rxkey->key, key->key, 16); + memcpy(&(rxkey->key[16]), &(key->key + [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); + } + + priv->tx(dev, skb, 1); + mutex_unlock(&priv->conf_mutex); + return 0; +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, @@ -1857,6 +2009,7 @@ static const struct ieee80211_ops p54_ops = { .set_tim = p54_set_tim, .sta_notify_ps = p54_sta_notify_ps, .sta_notify = p54_sta_notify, + .set_key = p54_set_key, .config = p54_config, .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, -- cgit v1.1 From 64c354ddcd65c98d9a1e2a8f7fb5cc80c7fa488e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:35:43 +0100 Subject: p54: include support for 2.13.24.0 USB LM87 Firmwares Those firmwares are probably capable of reprogramming the device's eeprom. We better support them officially, before all the accidents happen. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 35 +++++++++++++++++++++++++++-------- drivers/net/wireless/p54/p54common.h | 18 +++++++++++++++--- 2 files changed, 42 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6f7e82b..1b5627d 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -739,7 +739,13 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, if (!priv->eeprom) return ; - memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len)); + if (priv->fw_var >= 0x509) { + memcpy(priv->eeprom, eeprom->v2.data, + le16_to_cpu(eeprom->v2.len)); + } else { + memcpy(priv->eeprom, eeprom->v1.data, + le16_to_cpu(eeprom->v1.len)); + } complete(&priv->eeprom_comp); } @@ -940,12 +946,18 @@ int p54_read_eeprom(struct ieee80211_hw *dev) struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; struct sk_buff *skb; - size_t eeprom_size = 0x2020, offset = 0, blocksize; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; void *eeprom = NULL; - skb = p54_alloc_skb(dev, 0x8000, sizeof(*hdr) + sizeof(*eeprom_hdr) + - EEPROM_READBACK_LEN, + maxblocksize = EEPROM_READBACK_LEN; + if (priv->fw_var >= 0x509) + maxblocksize -= 0xc; + else + maxblocksize -= 0x4; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*hdr) + + sizeof(*eeprom_hdr) + maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); if (!skb) goto free; @@ -957,12 +969,19 @@ int p54_read_eeprom(struct ieee80211_hw *dev) goto free; eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN); + sizeof(*eeprom_hdr) + maxblocksize); while (eeprom_size) { - blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); - eeprom_hdr->offset = cpu_to_le16(offset); - eeprom_hdr->len = cpu_to_le16(blocksize); + blocksize = min(eeprom_size, maxblocksize); + if (priv->fw_var < 0x509) { + eeprom_hdr->v1.offset = cpu_to_le16(offset); + eeprom_hdr->v1.len = cpu_to_le16(blocksize); + } else { + eeprom_hdr->v2.offset = cpu_to_le32(offset); + eeprom_hdr->v2.len = cpu_to_le16(blocksize); + eeprom_hdr->v2.magic2 = 0xf; + memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); + } priv->tx(dev, skb, 0); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index d292ffb..5a68fda 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -246,9 +246,21 @@ struct memrecord { }; struct p54_eeprom_lm86 { - __le16 offset; - __le16 len; - u8 data[0]; + union { + struct { + __le16 offset; + __le16 len; + u8 data[0]; + } v1; + struct { + __le32 offset; + __le16 len; + u8 magic2; + u8 pad; + u8 magic[4]; + u8 data[0]; + } v2; + } __attribute__ ((packed)); } __attribute__ ((packed)); enum p54_rx_decrypt_status { -- cgit v1.1 From b2023ddcfa6b79f26ef459867324f3d32b91aa07 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:37:31 +0100 Subject: p54: refactoring Thanks to the introduction of "changed" flags, we no longer have to do the bookkeeping of p54's firmware state for everything. Thus we can cut down redundancy code. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 - drivers/net/wireless/p54/p54common.c | 158 +++++++++++++++++------------------ 2 files changed, 79 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ebe1ea1..d2dbb9e 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -85,7 +85,6 @@ struct p54_common { struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - u16 mac_mode; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; @@ -95,7 +94,6 @@ struct p54_common { bool use_short_slot; u16 rxhw; u8 version; - u8 rx_antenna; unsigned int tx_hdr_len; unsigned int fw_var; unsigned int fw_interface; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1b5627d..06c8321 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1334,11 +1334,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) return NETDEV_TX_BUSY; } -static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_setup_mac *setup; + u16 mode; skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP, @@ -1347,14 +1348,31 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) return -ENOMEM; setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); - priv->mac_mode = mode; + if (dev->conf.radio_enabled) { + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + mode = P54_FILTER_TYPE_STATION; + break; + case NL80211_IFTYPE_AP: + mode = P54_FILTER_TYPE_AP; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = P54_FILTER_TYPE_IBSS; + break; + default: + mode = P54_FILTER_TYPE_NONE; + break; + } + if (priv->filter_flags & FIF_PROMISC_IN_BSS) + mode |= P54_FILTER_TYPE_TRANSPARENT; + } else + mode = P54_FILTER_TYPE_RX_DISABLED; + setup->mac_mode = cpu_to_le16(mode); memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); - if (!bssid) - memset(setup->bssid, ~0, ETH_ALEN); - else - memcpy(setup->bssid, bssid, ETH_ALEN); - setup->rx_antenna = priv->rx_antenna; + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2; /* automatic */ setup->rx_align = 0; if (priv->fw_var < 0x500) { setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); @@ -1383,7 +1401,8 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, + u16 frequency) { struct p54_common *priv = dev->priv; struct sk_buff *skb; @@ -1400,8 +1419,8 @@ static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency) chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); memset(chan->padding1, 0, sizeof(chan->padding1)); - chan->mode = cpu_to_le16(P54_SCAN_EXIT); - chan->dwell = cpu_to_le16(0x0); + chan->mode = cpu_to_le16(mode); + chan->dwell = cpu_to_le16(dwell); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -1644,10 +1663,14 @@ static int p54_start(struct ieee80211_hw *dev) err = p54_init_stats(dev); if (err) goto out; - err = p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); - if (err) - goto out; + + memset(priv->bssid, ~0, ETH_ALEN); priv->mode = NL80211_IFTYPE_MONITOR; + err = p54_setup_mac(dev); + if (err) { + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + goto out; + } out: mutex_unlock(&priv->conf_mutex); @@ -1700,27 +1723,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, } memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - - p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL); - break; - case NL80211_IFTYPE_AP: - p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr); - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL); - break; - default: - BUG(); /* impossible */ - break; - } - + p54_setup_mac(dev); p54_set_leds(dev, 1, 0, 0); - mutex_unlock(&priv->conf_mutex); return 0; } @@ -1733,9 +1737,10 @@ static void p54_remove_interface(struct ieee80211_hw *dev, mutex_lock(&priv->conf_mutex); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); - p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(dev); mutex_unlock(&priv->conf_mutex); } @@ -1746,11 +1751,21 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) struct ieee80211_conf *conf = &dev->conf; mutex_lock(&priv->conf_mutex); - priv->rx_antenna = 2; /* automatic */ - priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, conf->channel->center_freq); - if (!ret) - ret = p54_set_edcf(dev); + if (changed & IEEE80211_CONF_CHANGE_POWER) + priv->output_power = conf->power_level << 2; + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0, + conf->channel->center_freq); + if (ret) + goto out; + } + +out: mutex_unlock(&priv->conf_mutex); return ret; } @@ -1763,36 +1778,31 @@ static int p54_config_interface(struct ieee80211_hw *dev, int ret = 0; mutex_lock(&priv->conf_mutex); - switch (priv->mode) { - case NL80211_IFTYPE_STATION: - ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid); + if (conf->changed & IEEE80211_IFCC_BSSID) { + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); if (ret) goto out; - ret = p54_set_leds(dev, 1, - !is_multicast_ether_addr(conf->bssid), 0); + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0, + dev->conf.channel->center_freq); if (ret) goto out; - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - ret = p54_set_freq(dev, dev->conf.channel->center_freq); + ret = p54_setup_mac(dev); if (ret) goto out; - ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid); + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + ret = p54_set_edcf(dev); if (ret) goto out; - if (conf->changed & IEEE80211_IFCC_BEACON) { - ret = p54_beacon_update(dev, vif); - if (ret) - goto out; - ret = p54_set_edcf(dev); - if (ret) - goto out; - } } + + ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0); + out: mutex_unlock(&priv->conf_mutex); return ret; @@ -1805,25 +1815,14 @@ static void p54_configure_filter(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - *total_flags &= FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | - FIF_FCSFAIL; + *total_flags &= FIF_PROMISC_IN_BSS | + (*total_flags & FIF_PROMISC_IN_BSS) ? + FIF_FCSFAIL : 0; priv->filter_flags = *total_flags; - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_setup_mac(dev, priv->mac_mode, NULL); - else - p54_setup_mac(dev, priv->mac_mode, priv->bssid); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - if (*total_flags & FIF_PROMISC_IN_BSS) - p54_setup_mac(dev, priv->mac_mode | 0x8, NULL); - else - p54_setup_mac(dev, priv->mac_mode & ~0x8, priv->bssid); - } + if (changed_flags & FIF_PROMISC_IN_BSS) + p54_setup_mac(dev); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, @@ -1920,16 +1919,17 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->basic_rate_mask = (info->basic_rates << 4); else priv->basic_rate_mask = info->basic_rates; - p54_setup_mac(dev, priv->mac_mode, priv->bssid); + p54_setup_mac(dev); if (priv->fw_var >= 0x500) - p54_set_freq(dev, dev->conf.channel->center_freq); + p54_scan(dev, P54_SCAN_EXIT, 0, + dev->conf.channel->center_freq); } if (changed & BSS_CHANGED_ASSOC) { if (info->assoc) { priv->aid = info->aid; priv->wakeup_timer = info->beacon_int * info->dtim_period * 5; - p54_setup_mac(dev, priv->mac_mode, priv->bssid); + p54_setup_mac(dev); } } -- cgit v1.1 From 02e37ba1298359baa123cf71ffa03d92abd259b2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 29 Nov 2008 22:39:08 +0100 Subject: p54: per-device names This patch replaces the static "p54:" strings in front of most printk's with their corresponding per-device names. It was always a bit of a hassle to check which device was generating all the messages. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 59 ++++++++++++++++++------------------ drivers/net/wireless/p54/p54usb.c | 43 +++++++++++++++----------- 2 files changed, 55 insertions(+), 47 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 06c8321..89968a5 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -158,21 +158,21 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->fw_interface = be32_to_cpup((__be32 *) bootrec->data); switch (priv->fw_interface) { - case FW_FMAC: - printk(KERN_INFO "p54: FreeMAC firmware\n"); - break; - case FW_LM20: - printk(KERN_INFO "p54: LM20 firmware\n"); - break; case FW_LM86: - printk(KERN_INFO "p54: LM86 firmware\n"); - break; - case FW_LM87: - printk(KERN_INFO "p54: LM87 firmware\n"); + case FW_LM20: + case FW_LM87: { + char *iftype = (char *)bootrec->data; + printk(KERN_INFO "%s: p54 detected a LM%c%c " + "firmware\n", + wiphy_name(dev->wiphy), + iftype[2], iftype[3]); break; + } + case FW_FMAC: default: - printk(KERN_INFO "p54: unknown firmware\n"); - break; + printk(KERN_ERR "%s: unsupported firmware\n", + wiphy_name(dev->wiphy)); + return -ENODEV; } break; case BR_CODE_COMPONENT_VERSION: @@ -216,13 +216,15 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) } if (fw_version) - printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", - fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", + wiphy_name(dev->wiphy), fw_version, + priv->fw_var >> 8, priv->fw_var & 0xff); if (priv->fw_var < 0x500) - printk(KERN_INFO "p54: you are using an obsolete firmware. " + printk(KERN_INFO "%s: you are using an obsolete firmware. " "visit http://wireless.kernel.org/en/users/Drivers/p54 " - "and grab one for \"kernel >= 2.6.28\"!\n"); + "and grab one for \"kernel >= 2.6.28\"!\n", + wiphy_name(dev->wiphy)); if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ @@ -399,8 +401,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) err = p54_convert_rev1(dev, curve_data); break; default: - printk(KERN_ERR "p54: unknown curve data " + printk(KERN_ERR "%s: unknown curve data " "revision %d\n", + wiphy_name(dev->wiphy), curve_data->cal_method_rev); err = -ENODEV; break; @@ -460,7 +463,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_PER_CHANNEL_BASEBAND_REGISTERS: break; default: - printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", + printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", + wiphy_name(dev->wiphy), le16_to_cpu(entry->code)); break; } @@ -470,7 +474,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) if (!synth || !priv->iq_autocal || !priv->output_limit || !priv->curve_data) { - printk(KERN_ERR "p54: not all required entries found in eeprom!\n"); + printk(KERN_ERR "%s: not all required entries found in eeprom!\n", + wiphy_name(dev->wiphy)); err = -EINVAL; goto err; } @@ -515,7 +520,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) priv->curve_data = NULL; } - printk(KERN_ERR "p54: eeprom parse failed!\n"); + printk(KERN_ERR "%s: eeprom parse failed!\n", + wiphy_name(dev->wiphy)); return err; } @@ -1573,28 +1579,23 @@ static int p54_beacon_tim(struct sk_buff *skb) struct ieee80211_mgmt *mgmt = (void *)skb->data; u8 *pos, *end; - if (skb->len <= sizeof(mgmt)) { - printk(KERN_ERR "p54: beacon is too short!\n"); + if (skb->len <= sizeof(mgmt)) return -EINVAL; - } pos = (u8 *)mgmt->u.beacon.variable; end = skb->data + skb->len; while (pos < end) { - if (pos + 2 + pos[1] > end) { - printk(KERN_ERR "p54: parsing beacon failed\n"); + if (pos + 2 + pos[1] > end) return -EINVAL; - } if (pos[0] == WLAN_EID_TIM) { u8 dtim_len = pos[1]; u8 dtim_period = pos[3]; u8 *next = pos + 2 + dtim_len; - if (dtim_len < 3) { - printk(KERN_ERR "p54: invalid dtim len!\n"); + if (dtim_len < 3) return -EINVAL; - } + memmove(pos, next, end - next); if (dtim_len > 3) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 21ba526..e9630b9 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -405,7 +405,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); + dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" + "upload buffer!\n"); err = -ENOMEM; goto err_bufalloc; } @@ -413,13 +414,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) memcpy(buf, start_string, 4); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); if (err) { - printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); + dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err); goto err_reset; } err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n"); + dev_err(&priv->udev->dev, "p54usb: cannot find firmware " + "(isl3887usb)\n"); err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); if (err) @@ -474,7 +476,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware " + "upload failed!\n"); goto err_upload_failed; } @@ -485,10 +488,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; } - timeout = jiffies + msecs_to_jiffies(1000); while (!(err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { @@ -496,25 +498,27 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "p54usb: firmware boot timed out!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot " + "timed out!\n"); err = -ETIMEDOUT; break; } } - if (err) + if (err) { + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; + } buf[0] = 'g'; buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "p54usb: firmware boot failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n"); goto err_upload_failed; } @@ -554,13 +558,15 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) buf = kmalloc(512, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware buffer " + "alloc failed!\n"); return -ENOMEM; } err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n"); + dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " + "(isl3886usb)\n"); err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); if (err) { @@ -685,8 +691,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); if (err) { - printk(KERN_ERR "p54usb: firmware block upload " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware block " + "upload failed\n"); goto fail; } @@ -719,8 +725,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) 0x002C | (unsigned long)&devreg->direct_mem_win); if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { - printk(KERN_ERR "p54usb: firmware DMA transfer " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware DMA " + "transfer failed\n"); goto fail; } @@ -825,8 +831,9 @@ static int __devinit p54u_probe(struct usb_interface *intf, unsigned int i, recognized_pipes; dev = p54_init_common(sizeof(*priv)); + if (!dev) { - printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); + dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n"); return -ENOMEM; } @@ -887,7 +894,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "p54usb: Cannot register netdevice\n"); + dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n"); goto err_free_dev; } -- cgit v1.1 From c58f9f635afe688c5c5709f441af57c12c7a4856 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 1 Dec 2008 16:53:28 +0100 Subject: iwl3945: remove obsolete irq handling 3945 hardware does not emit the interrupts CSR_INT_BIT_RF_KILL (rfkill toggled) and CSR_INT_BIT_CT_KILL (adapter too hot). Hence this part of code can be removed since iwl3945_irq_tasklet does not handle 4965 hw at all. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 29 ----------------------------- 1 file changed, 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 69fda64..94ea4c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4311,35 +4311,6 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) /* Safely ignore these bits for debug checks below */ inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - /* HW RF KILL switch toggled (4965 only) */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl3945_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, - "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio" : "enable radio"); - - /* Queue restart only if RF_KILL switch was set to "kill" - * when we loaded driver, and is now set to "enable". - * After we're Alive, RF_KILL gets handled by - * iwl3945_rx_card_state_notif() */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { - clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->restart); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself (4965 only) */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERROR("Microcode CT kill error detected.\n"); - handled |= CSR_INT_BIT_CT_KILL; - } - /* Error detected by uCode */ if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", -- cgit v1.1 From c91276592695e13d1b52eab572551017cbf96ee7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Dec 2008 18:19:36 +0100 Subject: p54: fix lm87 checksum endianness This fixes the checksum calculation for lm87 firmwares on big endian platforms, the device treats the data as an array of 32-bit little endian values so the driver needs to do that as well. Signed-off-by: Johannes Berg Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index e9630b9..2dd3cd4 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -244,13 +244,13 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, usb_submit_urb(data_urb, GFP_ATOMIC); } -static __le32 p54u_lm87_chksum(const u32 *data, size_t length) +static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) { u32 chk = 0; length >>= 2; while (length--) { - chk ^= *data++; + chk ^= le32_to_cpu(*data++); chk = (chk >> 5) ^ (chk << 3); } @@ -270,7 +270,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, if (!data_urb) return; - checksum = p54u_lm87_chksum((u32 *)skb->data, skb->len); + checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr->chksum = checksum; hdr->device_addr = addr; -- cgit v1.1 From 33fd8195529d74c0fe23cddd1c76fe7e03bbd324 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 1 Dec 2008 18:50:27 +0100 Subject: iwlwifi: disable AP mode iwlwifi does not support AP mode in any way. For one, it doesn't even buffer multicast/broadcast frames properly. We didn't allow zd1211rw AP mode to be enabled without this, so iwlwifi shouldn't be allowed to advertise AP mode either. It also doesn't work at all, it doesn't even answer to probe requests, I'm guessing the packet injection code was disabled again. Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6aa332b..0980f21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -808,7 +808,6 @@ int iwl_setup_mac(struct iwl_priv *priv) IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 94ea4c2..1d4658a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7814,7 +7814,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); -- cgit v1.1 From d97809dbbf1b8a6df79c82be75fa0cababec783b Mon Sep 17 00:00:00 2001 From: Colin McCabe Date: Mon, 1 Dec 2008 13:38:55 -0800 Subject: ath9k: Replace ath9k_opmode with nl80211_iftype This patch kills ath9k's ath9k_opmode enum by replacing it with nl80211_iftype. Signed-off-by: Colin McCabe Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ani.c | 12 ++++----- drivers/net/wireless/ath9k/ath9k.h | 10 ++------ drivers/net/wireless/ath9k/beacon.c | 24 ++++++++--------- drivers/net/wireless/ath9k/core.h | 2 +- drivers/net/wireless/ath9k/hw.c | 29 +++++++++++++-------- drivers/net/wireless/ath9k/main.c | 51 ++++++++++++++++++++----------------- drivers/net/wireless/ath9k/rc.c | 6 ++--- drivers/net/wireless/ath9k/recv.c | 16 ++++++------ drivers/net/wireless/ath9k/regd.c | 2 +- drivers/net/wireless/ath9k/xmit.c | 3 ++- 10 files changed, 81 insertions(+), 74 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c index c25b72b..251e2d9 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath9k/ani.c @@ -303,7 +303,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) } } - if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (ah->ah_opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); @@ -368,7 +368,7 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) return; } } - if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (ah->ah_opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); @@ -398,7 +398,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) aniState = ahp->ah_curani; - if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (ah->ah_opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel > 0) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1)) @@ -487,8 +487,8 @@ void ath9k_ani_reset(struct ath_hal *ah) aniState = &ahp->ah_ani[index]; ahp->ah_curani = aniState; - if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA - && ah->ah_opmode != ATH9K_M_IBSS) { + if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION + && ah->ah_opmode != NL80211_IFTYPE_ADHOC) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Reset ANI state opmode %u\n", ah->ah_opmode); ahp->ah_stats.ast_ani_reset++; @@ -504,7 +504,7 @@ void ath9k_ani_reset(struct ath_hal *ah) ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | ATH9K_RX_FILTER_PHYERR); - if (ah->ah_opmode == ATH9K_M_HOSTAP) { + if (ah->ah_opmode == NL80211_IFTYPE_AP) { ahp->ah_curani->ofdmTrigHigh = ah->ah_config.ofdm_trig_high; ahp->ah_curani->ofdmTrigLow = diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 9eaa3fc..9520aa0 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -647,13 +647,6 @@ enum ath9k_ant_setting { ATH9K_ANT_FIXED_B }; -enum ath9k_opmode { - ATH9K_M_STA = 1, - ATH9K_M_IBSS = 0, - ATH9K_M_HOSTAP = 6, - ATH9K_M_MONITOR = 8 -}; - #define ATH9K_SLOT_TIME_6 6 #define ATH9K_SLOT_TIME_9 9 #define ATH9K_SLOT_TIME_20 20 @@ -780,7 +773,8 @@ struct ath_hal { void __iomem *ah_sh; struct ath_softc *ah_sc; - enum ath9k_opmode ah_opmode; + + enum nl80211_iftype ah_opmode; struct ath9k_ops_config ah_config; struct ath9k_hw_capabilities ah_caps; diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index ca5782f..fe6929d 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -27,7 +27,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_ah->ah_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; @@ -82,7 +82,7 @@ static void ath_beacon_setup(struct ath_softc *sc, flags = ATH9K_TXDESC_NOACK; - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; @@ -302,7 +302,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_ah->ah_opmode == ATH9K_M_HOSTAP || + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* @@ -607,16 +607,16 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) struct ath_hal *ah = sc->sc_ah; struct ath_beacon_config conf; struct ath_vap *avp; - enum ath9k_opmode av_opmode; + enum nl80211_iftype opmode; u32 nexttbtt, intval; if (if_id != ATH_IF_ID_ANY) { vif = sc->sc_vaps[if_id]; ASSERT(vif); avp = (void *)vif->drv_priv; - av_opmode = avp->av_opmode; + opmode = avp->av_opmode; } else { - av_opmode = sc->sc_ah->ah_opmode; + opmode = sc->sc_ah->ah_opmode; } memset(&conf, 0, sizeof(struct ath_beacon_config)); @@ -632,7 +632,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); /* XXX conditionalize multi-bss support? */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* * For multi-bss ap support beacons are either staggered * evenly over N slots or burst together. For the former @@ -654,8 +654,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", nexttbtt, intval, conf.beacon_interval); - /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { + /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) { struct ath9k_beacon_state bs; u64 tsf; u32 tsftu; @@ -774,7 +774,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_ah->ah_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { /* * Pull nexttbtt forward to reflect the current * TSF @@ -806,7 +806,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_ah->ah_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* * In AP mode we enable the beacon timers and * SWBA interrupts to prepare beacon frames. @@ -822,7 +822,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_ah->ah_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 8c11c0f..a500d17 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -474,7 +474,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid struct ath_vap { int av_bslot; - enum ath9k_opmode av_opmode; + enum nl80211_iftype av_opmode; struct ath_buf *av_bcbuf; struct ath_tx_control av_btxctl; }; diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index b3f2899..668865d 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -1040,7 +1040,8 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); } -static 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 nl80211_iftype opmode) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -1057,7 +1058,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, enum ath9k_opmode ahp->ah_maskReg |= AR_IMR_TXOK; - if (opmode == ATH9K_M_HOSTAP) + if (opmode == NL80211_IFTYPE_AP) ahp->ah_maskReg |= AR_IMR_MIB; REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); @@ -1423,18 +1424,18 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) val = REG_READ(ah, AR_STA_ID1); val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); switch (opmode) { - case ATH9K_M_HOSTAP: + case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE); REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ATH9K_M_IBSS: + case NL80211_IFTYPE_ADHOC: REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE); REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ATH9K_M_STA: - case ATH9K_M_MONITOR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); break; } @@ -3054,14 +3055,14 @@ void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) ahp->ah_beaconInterval = beacon_period; switch (ah->ah_opmode) { - case ATH9K_M_STA: - case ATH9K_M_MONITOR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); flags |= AR_TBTT_TIMER_EN; break; - case ATH9K_M_IBSS: + case NL80211_IFTYPE_ADHOC: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); REG_WRITE(ah, AR_NEXT_NDP_TIMER, @@ -3069,7 +3070,7 @@ void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) (ahp->ah_atimWindow ? ahp-> ah_atimWindow : 1))); flags |= AR_NDP_TIMER_EN; - case ATH9K_M_HOSTAP: + case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, TU_TO_USEC(next_beacon - @@ -3082,6 +3083,12 @@ void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, + "%s: unsupported opmode: %d\n", + __func__, ah->ah_opmode); + return; + break; } REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); @@ -3177,7 +3184,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP); - if (ah->ah_opmode != ATH9K_M_HOSTAP && + if (ah->ah_opmode != NL80211_IFTYPE_AP && ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) ah->ah_currentRD += 5; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index ac37605..3d7111e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -754,13 +754,17 @@ static int ath_key_config(struct ath_softc *sc, /* * Strategy: - * For _M_STA mc tx, we will not setup a key at all since we never - * tx mc. - * _M_STA mc rx, we will use the keyID. - * for _M_IBSS mc tx, we will use the keyID, and no macaddr. - * for _M_IBSS mc rx, we will alloc a slot and plumb the mac of the - * peer node. BUT we will plumb a cleartext key so that we can do - * perSta default key table lookup in software. + * For STA mc tx, we will not setup a key at + * all since we never tx mc. + * + * For STA mc rx, we will use the keyID. + * + * For ADHOC mc tx, we will use the keyID, and no macaddr. + * + * For ADHOC mc rx, we will alloc a slot and plumb the mac of + * the peer node. + * BUT we will plumb a cleartext key so that we can do + * per-Sta default key table lookup in software. */ if (is_broadcast_ether_addr(addr)) { switch (opmode) { @@ -861,7 +865,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d\n", bss_conf->aid); /* New association, store aid */ - if (avp->av_opmode == ATH9K_M_STA) { + if (avp->av_opmode == NL80211_IFTYPE_STATION) { sc->sc_curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, sc->sc_curaid); @@ -1373,7 +1377,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) goto bad; /* default to MONITOR mode */ - sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; + sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; + /* Setup rate tables */ @@ -1938,8 +1943,8 @@ static int ath9k_start(struct ieee80211_hw *hw) * Note we only do this (at the moment) for station mode. */ if (ath9k_hw_phycounters(sc->sc_ah) && - ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) + ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC))) sc->sc_imask |= ATH9K_INT_MIB; /* * Some hardware processes the TIM IE and fires an @@ -1948,7 +1953,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * enable the TIM interrupt when operating as station. */ if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_ah->ah_opmode == ATH9K_M_STA) && + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) && !sc->sc_config.swBeaconProcess) sc->sc_imask |= ATH9K_INT_TIM; @@ -2064,7 +2069,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_vap *avp = (void *)conf->vif->drv_priv; - int ic_opmode = 0; + enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; /* Support only vap for now */ @@ -2073,13 +2078,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, switch (conf->type) { case NL80211_IFTYPE_STATION: - ic_opmode = ATH9K_M_STA; + ic_opmode = NL80211_IFTYPE_STATION; break; case NL80211_IFTYPE_ADHOC: - ic_opmode = ATH9K_M_IBSS; + ic_opmode = NL80211_IFTYPE_ADHOC; break; case NL80211_IFTYPE_AP: - ic_opmode = ATH9K_M_HOSTAP; + ic_opmode = NL80211_IFTYPE_AP; break; default: DPRINTF(sc, ATH_DBG_FATAL, @@ -2093,7 +2098,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, avp->av_opmode = ic_opmode; avp->av_bslot = -1; - if (ic_opmode == ATH9K_M_HOSTAP) + if (ic_opmode == NL80211_IFTYPE_AP) ath9k_hw_set_tsfadjust(sc->sc_ah, 1); sc->sc_vaps[0] = conf->vif; @@ -2127,8 +2132,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, del_timer_sync(&sc->sc_ani.timer); /* Reclaim beacon resources */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || - sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); ath_beacon_return(sc, avp); } @@ -2163,7 +2168,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - if ((sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) && + if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) && (conf->ht.enabled)) { sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ? ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; @@ -2202,8 +2207,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ if (vif->type == NL80211_IFTYPE_AP && - ah->ah_opmode != ATH9K_M_HOSTAP) { - ah->ah_opmode = ATH9K_M_HOSTAP; + ah->ah_opmode != NL80211_IFTYPE_AP) { + ah->ah_opmode = NL80211_IFTYPE_STATION; ath9k_hw_setopmode(ah); ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); /* Request full reset to get hw opmode changed properly */ @@ -2258,7 +2263,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != ATH9K_M_STA)) { + if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 7d5affd..76acd2b 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1347,13 +1347,13 @@ static void ath_rc_init(struct ath_softc *sc, u8 i, j, k, hi = 0, hthi = 0; /* FIXME: Adhoc */ - if ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) { + if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) { bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; rate_table = ath_choose_rate_table(sc, sband->band, sta->ht_cap.ht_supported, is_cw_40); - } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* sc_curmode would be set on init through config() */ rate_table = sc->hw_rate_table[sc->sc_curmode]; } diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 0b9a3d9..51e0587 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -165,7 +165,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, * discard the frame. Enable this if you want to see * error frames in Monitor mode. */ - if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) + if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR) goto rx_next; } else if (ds->ds_rxstat.rs_status != 0) { if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) @@ -191,7 +191,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) { if (ds->ds_rxstat.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) @@ -361,25 +361,25 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_ah->ah_opmode != ATH9K_M_STA) + if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && + if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) && (sc->rx_filter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (sc->sc_ah->ah_opmode == ATH9K_M_STA || - sc->sc_ah->ah_opmode == ATH9K_M_IBSS) + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames & beacon frames */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); return rfilt; diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index e3dd91f..42ce1d9 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -456,7 +456,7 @@ ath9k_regd_add_channel(struct ath_hal *ah, return false; } - if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) { + if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Skipping HOSTAP channel\n"); return false; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index fc52f61..5cf8311 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -760,7 +760,8 @@ 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_ah->ah_opmode == ATH9K_M_STA) + if (sc->sc_ah->ah_opmode == + NL80211_IFTYPE_STATION) needreset = 1; } } else { -- cgit v1.1 From 7100e924661cc23609de8e7ab9fc3a13e0173891 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 1 Dec 2008 16:32:18 -0800 Subject: iwlwifi: 5150 add support for 5150 Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 ++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 3 files changed, 17 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c3dce81..8f92ab0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -45,8 +45,10 @@ #include "iwl-5000-hw.h" #define IWL5000_UCODE_API "-1" +#define IWL5150_UCODE_API "-1" #define IWL5000_MODULE_FIRMWARE "iwlwifi-5000" IWL5000_UCODE_API ".ucode" +#define IWL5150_MODULE_FIRMWARE "iwlwifi-5150" IWL5150_UCODE_API ".ucode" static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC3, @@ -1563,7 +1565,17 @@ struct iwl_cfg iwl5350_agn_cfg = { .mod_params = &iwl50_mod_params, }; +struct iwl_cfg iwl5150_agn_cfg = { + .name = "5150AGN", + .fw_name = IWL5150_MODULE_FIRMWARE, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .mod_params = &iwl50_mod_params, +}; + MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE); +MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE); module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7888250..7014924 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4210,7 +4210,11 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, +/* 5150 Wifi/WiMax */ + {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, + {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, #endif /* CONFIG_IWL5000 */ + {0} }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4da988e..cb6edfd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -54,6 +54,7 @@ extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; +extern struct iwl_cfg iwl5150_agn_cfg; /* CT-KILL constants */ #define CT_KILL_THRESHOLD 110 /* in Celsius */ -- cgit v1.1 From 819500c5892aeeed079d3ea1671df40f2dd1d417 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 1 Dec 2008 16:32:19 -0800 Subject: iwlwifi: 5150 enable DC calibration This patch enables DC calibration for 5150 Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 7 ++++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8f92ab0..c1e7a42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -477,6 +477,9 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, * uCode. iwl_send_calib_results sends them in a row according to their * index. We sort them here */ switch (hdr->op_code) { + case IWL_PHY_CALIBRATE_DC_CMD: + index = IWL_CALIB_DC; + break; case IWL_PHY_CALIBRATE_LO_CMD: index = IWL_CALIB_LO; break; @@ -873,7 +876,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) BIT(IWL_CALIB_BASE_BAND); break; case CSR_HW_REV_TYPE_5150: - priv->hw_params.calib_init_cfg = 0; + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_DC); + break; } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cb6edfd..b2ce29c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -693,6 +693,7 @@ struct statistics_general_data { */ enum iwl_calib { IWL_CALIB_XTAL, + IWL_CALIB_DC, IWL_CALIB_LO, IWL_CALIB_TX_IQ, IWL_CALIB_TX_IQ_PERD, -- cgit v1.1 From 339afc893d3c1a36151c7578d7eacd2f4b293d5f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 1 Dec 2008 16:32:20 -0800 Subject: iwlwifi: 5150 compute ct kill threshold This patch adds computation of ct kill threshold for 5150. Threshold is computed from calibration data in the EEPROM. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 13 ++++++++++++- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c1e7a42..26e04ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -426,6 +426,17 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } +static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv) +{ + const s32 volt2temp_coef = -5; + u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, + EEPROM_5000_TEMPERATURE); + /* offset = temperate - voltage / coef */ + s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef; + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset; + return threshold * volt2temp_coef; +} + /* * Calibration */ @@ -859,7 +870,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) case CSR_HW_REV_TYPE_5150: /* 5150 wants in Kelvin */ priv->hw_params.ct_kill_threshold = - CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + iwl5150_get_ct_threshold(priv); break; } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 997f23c..8f6b05f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -147,6 +147,7 @@ struct iwl_eeprom_channel { /*5000 calibrations */ #define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) #define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL) +#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_5000_CALIB_ALL) /* 5000 links */ #define EEPROM_5000_LINK_HOST (2*0x64) -- cgit v1.1 From fd63edba43c584d334e8fc161ca84e4cf54e26a0 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 1 Dec 2008 16:32:21 -0800 Subject: iwlwifi: 5150 parametrize eeprom versions Add support for 5150 eeprom versions Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 26e04ec..488b580 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1587,6 +1587,8 @@ struct iwl_cfg iwl5150_agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; -- cgit v1.1 From 7470d7f54064557b6210671c2692bba19af5b79d Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 1 Dec 2008 16:32:22 -0800 Subject: iwlwifi: 5150 enable LO, TXIQ and BB calibrations This patch enables LO, TXIQ, and BB calibrations for 5150 Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 488b580..b6c57cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -888,7 +888,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) break; case CSR_HW_REV_TYPE_5150: priv->hw_params.calib_init_cfg = - BIT(IWL_CALIB_DC); + BIT(IWL_CALIB_DC) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); break; } -- cgit v1.1 From aac9207e45b1ec1f36d67e57d94f59ac036d37ee Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 2 Dec 2008 18:37:54 +0530 Subject: ath9k: Choose correct ANI calibration period ANI can't be turned on/off dynamically yet, but the calculation of the calibration period is wrong anyway. This patch fixes it. Reported-by: Johannes Berg Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 3d7111e..26c47577 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -421,8 +421,9 @@ static void ath_ani_calibrate(unsigned long data) * The interval must be the shortest necessary to satisfy ANI, * short calibration and long calibration. */ - - cal_interval = ATH_ANI_POLLINTERVAL; + cal_interval = ATH_LONG_CALINTERVAL; + if (sc->sc_ah->ah_config.enable_ani) + cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); if (!sc->sc_ani.sc_caldone) cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); -- cgit v1.1 From 1ce9cdac482f0dfbbd22ba4b3e5c016a05543a42 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 2 Dec 2008 18:19:48 +0100 Subject: rt2x00: Optimize IV/EIV handling IV and EIV belong to eachother and don't require 2 seperate fields. Instead they can logically be merged into a single array with size 2. With this approach we can simplify the code in rt2x00crypto.c by using a single memcpy() when copying the iv/eiv data. Additionally we can move some code out of if-statements because the if-statement would always be true. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00crypto.c | 44 ++++++++++-------------------- drivers/net/wireless/rt2x00/rt2x00queue.h | 12 +++----- drivers/net/wireless/rt2x00/rt61pci.c | 8 +++--- drivers/net/wireless/rt2x00/rt73usb.c | 8 +++--- 4 files changed, 26 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 5a858e5..e0fc7c1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -78,10 +78,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) return; /* Copy IV/EIV data */ - if (iv_len >= 4) - memcpy(&skbdesc->iv, skb->data + header_length, 4); - if (iv_len >= 8) - memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4); + memcpy(skbdesc->iv, skb->data + header_length, iv_len); /* Move ieee80211 header */ memmove(skb->data + iv_len, skb->data, header_length); @@ -98,7 +95,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); const unsigned int iv_len = - ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4); + ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4); if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) return; @@ -109,10 +106,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) memmove(skb->data, skb->data + iv_len, header_length); /* Copy IV/EIV data */ - if (iv_len >= 4) - memcpy(skb->data + header_length, &skbdesc->iv, 4); - if (iv_len >= 8) - memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4); + memcpy(skb->data + header_length, skbdesc->iv, iv_len); /* IV/EIV data has returned into the frame */ skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; @@ -172,17 +166,9 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, header_length); transfer += header_length; - /* Copy IV data */ - if (iv_len >= 4) { - memcpy(skb->data + transfer, &rxdesc->iv, 4); - transfer += 4; - } - - /* Copy EIV data */ - if (iv_len >= 8) { - memcpy(skb->data + transfer, &rxdesc->eiv, 4); - transfer += 4; - } + /* Copy IV/EIV data */ + memcpy(skb->data + transfer, rxdesc->iv, iv_len); + transfer += iv_len; /* Move payload */ if (align) { @@ -198,16 +184,14 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, */ transfer += payload_len; - /* Copy ICV data */ - if (icv_len >= 4) { - memcpy(skb->data + transfer, &rxdesc->icv, 4); - /* - * AES appends 8 bytes, we can't fill the upper - * 4 bytes, but mac80211 doesn't care about what - * we provide here anyway and strips it immediately. - */ - transfer += icv_len; - } + /* + * Copy ICV data + * AES appends 8 bytes, we can't fill the upper + * 4 bytes, but mac80211 doesn't care about what + * we provide here anyway and strips it immediately. + */ + memcpy(skb->data + transfer, &rxdesc->icv, 4); + transfer += icv_len; /* IV/EIV/ICV has been inserted into frame */ rxdesc->size = transfer; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 2e99ab5..7889f91 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -109,8 +109,7 @@ enum skb_frame_desc_flags { * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. - * @iv: IV data used during encryption/decryption. - * @eiv: EIV data used during encryption/decryption. + * @iv: IV/EIV data used during encryption/decryption. * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. * @entry: The entry to which this sk buffer belongs. */ @@ -123,8 +122,7 @@ struct skb_frame_desc { void *desc; - __le32 iv; - __le32 eiv; + __le32 iv[2]; dma_addr_t skb_dma; @@ -168,8 +166,7 @@ enum rxdone_entry_desc_flags { * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). * @cipher: Cipher type used during decryption. * @cipher_status: Decryption status. - * @iv: IV data used during decryption. - * @eiv: EIV data used during decryption. + * @iv: IV/EIV data used during decryption. * @icv: ICV data used during decryption. */ struct rxdone_entry_desc { @@ -182,8 +179,7 @@ struct rxdone_entry_desc { u8 cipher; u8 cipher_status; - __le32 iv; - __le32 eiv; + __le32 iv[2]; __le32 icv; }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d54443c..c1ebb65 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1778,8 +1778,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { - _rt2x00_desc_write(txd, 3, skbdesc->iv); - _rt2x00_desc_write(txd, 4, skbdesc->eiv); + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } rt2x00_desc_read(txd, 5, &word); @@ -1949,8 +1949,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, } if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv); - _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv); + _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]); _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 37a782d..3c8b235 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1428,8 +1428,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { - _rt2x00_desc_write(txd, 3, skbdesc->iv); - _rt2x00_desc_write(txd, 4, skbdesc->eiv); + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } rt2x00_desc_read(txd, 5, &word); @@ -1618,8 +1618,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, } if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv); - _rt2x00_desc_read(rxd, 3, &rxdesc->eiv); + _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); _rt2x00_desc_read(rxd, 4, &rxdesc->icv); /* -- cgit v1.1 From 42c8285767dd17f450d986bdb163a8d56fb0330a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 2 Dec 2008 18:20:04 +0100 Subject: rt2x00: Store retry limit values Store retry limit values in the rt2x00dev structure. This allows the removal of the FIXME where we assumed the long retry is only used when working with RTS frames. Instead we should check the current retry limit values and decide if the required retry count for this frame is a long or short retry. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 6 ++++++ drivers/net/wireless/rt2x00/rt2x00config.c | 2 ++ drivers/net/wireless/rt2x00/rt2x00queue.c | 9 +-------- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 780ba73..e7ed56d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -803,6 +803,12 @@ struct rt2x00_dev { u16 tx_power; /* + * Current retry values. + */ + u8 short_retry; + u8 long_retry; + + /* * Rssi <-> Dbm offset */ u8 rssi_offset; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 7c62ce1..b3bc8b4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -194,6 +194,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, rt2x00dev->curr_band = conf->channel->band; rt2x00dev->tx_power = conf->power_level; + rt2x00dev->short_retry = conf->short_frame_max_tx_count; + rt2x00dev->long_retry = conf->long_frame_max_tx_count; rt2x00dev->rx_status.band = conf->channel->band; rt2x00dev->rx_status.freq = conf->channel->center_freq; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index b8de9d2..7f908a1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -231,14 +231,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Determine retry information. */ txdesc->retry_limit = tx_info->control.rates[0].count - 1; - /* - * XXX: If at this point we knew whether the HW is going to use - * the RETRY_MODE bit or the retry_limit (currently all - * use the RETRY_MODE bit) we could do something like b43 - * does, set the RETRY_MODE bit when the RC algorithm is - * requesting more than the long retry limit. - */ - if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + if (txdesc->retry_limit >= rt2x00dev->long_retry) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* -- cgit v1.1 From 0b927a079106e5f66c736e297370d3feb008e28e Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 2 Dec 2008 18:20:22 +0100 Subject: rt2x00: Remove duplicate code Simplify rt2x00lib_config_antenna() by moving duplicate code into a seperate static inlined function. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00config.c | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index b3bc8b4..e66fb31 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -108,33 +108,34 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } +static inline +enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, + enum antenna default_ant) +{ + if (current_ant != ANTENNA_SW_DIVERSITY) + return current_ant; + return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; +} + void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) { + struct antenna_setup *def = &rt2x00dev->default_ant; + struct antenna_setup *active = &rt2x00dev->link.ant.active; + /* * Failsafe: Make sure we are not sending the * ANTENNA_SW_DIVERSITY state to the driver. * If that happes fallback to hardware default, * or our own default. + * The calls to rt2x00lib_config_antenna_check() + * might have caused that we restore back to the already + * active setting. If that has happened we can quit. */ - if (ant->rx == ANTENNA_SW_DIVERSITY) { - if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) - ant->rx = ANTENNA_B; - else - ant->rx = rt2x00dev->default_ant.rx; - } - if (ant->tx == ANTENNA_SW_DIVERSITY) { - if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) - ant->tx = ANTENNA_B; - else - ant->tx = rt2x00dev->default_ant.tx; - } + ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); + ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); - /* - * Only reconfigure when something has changed. - */ - if (ant->rx == rt2x00dev->link.ant.active.rx && - ant->tx == rt2x00dev->link.ant.active.tx) + if (ant->rx == active->rx && ant->tx == active->tx) return; /* @@ -154,7 +155,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00lib_reset_link_tuner(rt2x00dev); rt2x00_reset_link_ant_rssi(&rt2x00dev->link); - memcpy(&rt2x00dev->link.ant.active, ant, sizeof(*ant)); + memcpy(active, ant, sizeof(*ant)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); -- cgit v1.1 From dddfb478b26e29a2b47f655ec219e743b8111015 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 2 Dec 2008 18:20:42 +0100 Subject: rt2x00: Implement HW encryption (rt2500usb) rt2500usb supports hardware encryption. rt2500usb supports up to 4 shared and pairwise keys. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 1 + drivers/net/wireless/rt2x00/rt2500usb.c | 132 +++++++++++++++++++++++++++-- drivers/net/wireless/rt2x00/rt2500usb.h | 3 + drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00crypto.c | 12 +++ drivers/net/wireless/rt2x00/rt2x00lib.h | 6 ++ drivers/net/wireless/rt2x00/rt2x00mac.c | 2 - drivers/net/wireless/rt2x00/rt2x00queue.c | 8 +- 8 files changed, 156 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 95511ac..178b313 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -57,6 +57,7 @@ config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB select RT2X00_LIB_USB + select RT2X00_LIB_CRYPTO ---help--- This adds support for rt2500 wireless chipset family. Supported chips: RT2571 & RT2572. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0447e93..90bf0b9 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -36,6 +36,13 @@ #include "rt2500usb.h" /* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 1; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +/* * Register access. * All access to the CSR registers will go through the methods * rt2500usb_register_read and rt2500usb_register_write. @@ -323,6 +330,82 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ + +/* + * rt2500usb does not differentiate between shared and pairwise + * keys, so we should use the same function for both key types. + */ +static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + int timeout; + u32 mask; + u16 reg; + + if (crypto->cmd == SET_KEY) { + /* + * Pairwise key will always be entry 0, but this + * could collide with a shared key on the same + * position... + */ + mask = TXRX_CSR0_KEY_ID.bit_mask; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * The encryption key doesn't fit within the CSR cache, + * this means we should allocate it seperately and use + * rt2x00usb_vendor_request() to send the key to the hardware. + */ + reg = KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(crypto->key)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + crypto->key, + sizeof(crypto->key), + timeout); + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + } + + /* + * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate + * a particular key is valid. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, crypto->cipher); + rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); + + mask = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); + if (crypto->cmd == SET_KEY) + mask |= 1 << key->hw_key_idx; + else if (crypto->cmd == DISABLE_KEY) + mask &= ~(1 << key->hw_key_idx); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, mask); + rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + return 0; +} + static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -844,7 +927,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0xff); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); @@ -1066,7 +1149,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); @@ -1079,6 +1162,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); + } + rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1093,7 +1181,8 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, 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); - rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher); + rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx); rt2x00_desc_write(txd, 0, word); } @@ -1204,6 +1293,7 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = @@ -1231,6 +1321,31 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER); + if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY; + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + /* ICV is located at the end of frame */ + + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. It has provided the data seperately but rt2x00lib + * should decide if it should be reinserted. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + if (rxdesc->cipher != CIPHER_TKIP) + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + /* * Obtain the status about this packet. * When frame was received with an OFDM bitrate, @@ -1238,8 +1353,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 100kbit/s. */ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - - entry->queue->rt2x00dev->rssi_offset; + rxdesc->rssi = + rt2x00_get_field32(word1, RXD_W1_RSSI) - rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) @@ -1727,6 +1842,10 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + if (!modparam_nohwcrypt) { + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + __set_bit(CONFIG_CRYPTO_COPY_IV, &rt2x00dev->flags); + } __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); /* @@ -1746,6 +1865,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, @@ -1767,6 +1887,8 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, + .config_shared_key = rt2500usb_config_key, + .config_pairwise_key = rt2500usb_config_key, .config_filter = rt2500usb_config_filter, .config_intf = rt2500usb_config_intf, .config_erp = rt2500usb_config_erp, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index dbb5d689..4347dfd 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -447,6 +447,9 @@ #define SEC_CSR30 0x04bc #define SEC_CSR31 0x04be +#define KEY_ENTRY(__idx) \ + ( SEC_CSR0 + ((__idx) * 16) ) + /* * PHY control registers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e7ed56d..03d34bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -653,6 +653,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_CRYPTO_COPY_IV, }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index e0fc7c1..c6709b3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -69,6 +69,18 @@ unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) return overhead; } +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); + + if (unlikely(!iv_len)) + return; + + /* Copy IV/EIV data */ + memcpy(skbdesc->iv, skb->data + header_length, iv_len); +} + void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 9399733..1e189377 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -219,6 +219,7 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, #ifdef CONFIG_RT2X00_LIB_CRYPTO enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, @@ -235,6 +236,11 @@ static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx return 0; } +static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, + unsigned int iv_len) +{ +} + static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) { diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4c03957..fa91ca5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -79,10 +79,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, * RTS/CTS frame should use the length of the frame plus any * encryption overhead that will be added by the hardware. */ -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (!frag_skb->do_not_encrypt) data_length += rt2x00crypto_tx_overhead(tx_info); -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7f908a1..e4a1dbe 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -420,8 +420,12 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) * the frame so we can provide it to the driver seperately. */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && - !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) - rt2x00crypto_tx_remove_iv(skb, iv_len); + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { + if (test_bit(CONFIG_CRYPTO_COPY_IV, &queue->rt2x00dev->flags)) + rt2x00crypto_tx_copy_iv(skb, iv_len); + else + rt2x00crypto_tx_remove_iv(skb, iv_len); + } /* * It could be possible that the queue was corrupted and this -- cgit v1.1 From 304a698a5819bf318fe7e6ea9fe7ff2560365ec2 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 2 Dec 2008 18:20:59 +0100 Subject: rt2x00: Release rt2x00 2.2.3 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 03d34bb..39ecf3b 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.2" +#define DRV_VERSION "2.2.3" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.1 From 8f5c87dcf6d1a5e6d7ffe642cfd4debb5ccbec49 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 2 Dec 2008 12:13:57 -0800 Subject: iwlwifi: move host command check function into separate file This patch moves iwl_check_rxon_cmd into iwl-agn-hcmd-check.c This function compiled out in none debugging or non development mode and more. We haven't decided which one yet hence preserving the current 'always compile' state. More functions will be added to the file namely for checking TX and LQ commands. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c | 108 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 75 +-------------- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 + drivers/net/wireless/iwlwifi/iwl-dev.h | 5 - 5 files changed, 112 insertions(+), 80 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 8b45b30..0be9e6b 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -8,7 +8,7 @@ iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-hcmd-check.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c new file mode 100644 index 0000000..c50494a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include +#include +#include "iwl-dev.h" +#include "iwl-debug.h" +#include "iwl-commands.h" + + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7014924..4311a56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -108,79 +108,6 @@ static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } /** - * iwl_check_rxon_cmd - validate RXON structure is valid - * - * NOTE: This is really only useful during development and can eventually - * be #ifdef'd out once the driver is stable and folks aren't actively - * making changes - */ -static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) -{ - int error = 0; - int counter = 1; - - if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - error |= le32_to_cpu(rxon->flags & - (RXON_FLG_TGJ_NARROW_BAND_MSK | - RXON_FLG_RADAR_DETECT_MSK)); - if (error) - IWL_WARNING("check 24G fields %d | %d\n", - counter++, error); - } else { - error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? - 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); - if (error) - IWL_WARNING("check 52 fields %d | %d\n", - counter++, error); - error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); - if (error) - IWL_WARNING("check 52 CCK %d | %d\n", - counter++, error); - } - error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; - if (error) - IWL_WARNING("check mac addr %d | %d\n", counter++, error); - - /* make sure basic rates 6Mbps and 1Mbps are supported */ - error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && - ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); - if (error) - IWL_WARNING("check basic rate %d | %d\n", counter++, error); - - error |= (le16_to_cpu(rxon->assoc_id) > 2007); - if (error) - IWL_WARNING("check assoc id %d | %d\n", counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); - if (error) - IWL_WARNING("check CCK and short slot %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); - if (error) - IWL_WARNING("check CCK & auto detect %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); - if (error) - IWL_WARNING("check TGG and auto detect %d | %d\n", - counter++, error); - - if (error) - IWL_WARNING("Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); - return -1; - } - return 0; -} - -/** * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon * @@ -252,7 +179,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) * 5000, but will not damage 4965 */ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; - ret = iwl_check_rxon_cmd(&priv->staging_rxon); + ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon); if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0591aec..9c786db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3064,4 +3064,6 @@ struct iwl_rx_packet { #define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) +int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon); + #endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b2ce29c..846b8b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1086,9 +1086,4 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -extern const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); - -/* Requires full declaration of iwl_priv before including */ - #endif /* __iwl_dev_h__ */ -- cgit v1.1 From 99df630c3453e4a66b3408212dd8e55bc0e04f54 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 2 Dec 2008 12:13:58 -0800 Subject: iwlwifi: fix printk size format error The patch fixes a printk size format error. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4311a56..4ea7566 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1535,7 +1535,7 @@ static irqreturn_t iwl_isr(int irq, void *data) if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { /* Hardware disappeared. It might have already raised * an interrupt */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); goto unplugged; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 1d4658a..12ff112 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4411,7 +4411,7 @@ static irqreturn_t iwl3945_isr(int irq, void *data) if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { /* Hardware disappeared */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); goto unplugged; } -- cgit v1.1 From c93007efaad0a90520ba73f025c663441bf7e9d6 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 2 Dec 2008 12:13:59 -0800 Subject: iwl3945: Select correct sta ID from find_station() The find_station routine needs to look at the IWL_AP_ID entry if we're a STA. Currently, it only looks for STA entries which causes HW crypto to fail. Signed-off-by: Samuel Ortiz Acked-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index af77ea7..6150004 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -809,12 +809,19 @@ int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue * u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) { - int i; + int i, start = IWL_AP_ID; int ret = IWL_INVALID_STATION; unsigned long flags; + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || + (priv->iw_mode == NL80211_IFTYPE_AP)) + start = IWL_STA_ID; + + if (is_broadcast_ether_addr(addr)) + return priv->hw_setting.bcast_sta_id; + spin_lock_irqsave(&priv->sta_lock, flags); - for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + for (i = start; i < priv->hw_setting.max_stations; i++) if ((priv->stations[i].used) && (!compare_ether_addr (priv->stations[i].sta.sta.addr, addr))) { -- cgit v1.1 From 0ad91a35bcb6dd993ad7d34f159afae929b4743d Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 2 Dec 2008 12:14:00 -0800 Subject: iwlwifi: move disable/enable interrupts to iwl-core.c This patch moves iwl_enable_interrupts and iwl_disable_interrupts functions to iwl-core.c Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 22 ---------------------- drivers/net/wireless/iwlwifi/iwl-core.c | 25 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 6 ++++++ 3 files changed, 31 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4ea7566..40905d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1255,13 +1255,6 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) } #endif -static void iwl_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR("Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); -} - /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl_priv *priv) { @@ -1270,21 +1263,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static inline void iwl_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR("Disabled interrupts\n"); -} - - /** * iwl_irq_handle_error - called for HW or SW error interrupt from card */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0980f21..1b021ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -961,6 +961,30 @@ void iwl_uninit_drv(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_uninit_drv); + +void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR("Disabled interrupts\n"); +} +EXPORT_SYMBOL(iwl_disable_interrupts); + +void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} +EXPORT_SYMBOL(iwl_enable_interrupts); + int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) { u32 stat_flags = 0; @@ -1336,6 +1360,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rf_kill_ct_config); + /* * CARD_STATE_CMD * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 82bf263..f68883b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -313,6 +313,12 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /***************************************************** + * PCI * + *****************************************************/ +void iwl_disable_interrupts(struct iwl_priv *priv); +void iwl_enable_interrupts(struct iwl_priv *priv); + +/***************************************************** * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); -- cgit v1.1 From d366df5abb8d5ce7e2c36d3b678177787ccd9749 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 2 Dec 2008 12:14:01 -0800 Subject: iwlwifi: move channels sysfs to debugfs This patch moves channels info display from sysfs to debugfs. This shows channel information as stored in NIC EEPROM. This is useful in debugging CRDA or iwl goes setting so it belongs rather to debugfs then to sysfs. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 63 ------------------------- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 76 ++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 40905d2..e8368b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3580,68 +3580,6 @@ static ssize_t show_power_level(struct device *d, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, char *buf) -{ - - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_channel *channels = NULL; - const struct ieee80211_supported_band *supp_band = NULL; - int len = 0, i; - int count = 0; - - if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) - return -EAGAIN; - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - len += sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - return len; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -3741,7 +3679,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) } static struct attribute *iwl_sysfs_entries[] = { - &dev_attr_channels.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, &dev_attr_power_level.attr, diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 0e79a6a..a115dc6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -60,6 +60,7 @@ struct iwl_debugfs { struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; struct dentry *file_log_event; + struct dentry *file_channels; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index c3df5aa..370b66c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -348,12 +348,86 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, return count; } + + +static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_supported_band *supp_band = NULL; + int pos = 0, i, bufsz = PAGE_SIZE; + char *buf; + ssize_t ret; + + if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERROR("Can not allocate Buffer\n"); + return -ENOMEM; + } + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); + channels = supp_band->channels; + + pos += scnprintf(buf + pos, bufsz - pos, + "Displaying %d channels in 2.4GHz band 802.11bg):\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); + channels = supp_band->channels; + + pos += scnprintf(buf + pos, bufsz - pos, + "Displaying %d channels in 5.2GHz band (802.11a)\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); +DEBUGFS_READ_FILE_OPS(channels); /* * Create the debugfs files and directories @@ -387,6 +461,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); + DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -415,6 +490,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v1.1 From c30e30e17dad86d5e161cf9774eb4d549cc13191 Mon Sep 17 00:00:00 2001 From: "Abbas, Mohamed" Date: Tue, 2 Dec 2008 12:14:02 -0800 Subject: iwl3945: add debugfs support Add debugfs support to 3945 driver to display rs info. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index bfeef70..76100d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -63,6 +63,9 @@ struct iwl3945_rs_sta { u8 ibss_sta_added; struct timer_list rate_scale_flush; struct iwl3945_rate_scale_data win[IWL_RATE_COUNT]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_stats_table_file; +#endif /* used to be in sta_info */ int last_txrate_idx; @@ -772,6 +775,60 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, IWL_DEBUG_RATE("leave: %d\n", index); } +#ifdef CONFIG_MAC80211_DEBUGFS +static int iwl3945_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int j; + struct iwl3945_rs_sta *lq_sta = file->private_data; + + desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n" + "rate=0x%X flush time %d\n", + lq_sta->tx_packets, + lq_sta->last_txrate_idx, + lq_sta->start_rate, jiffies_to_msecs(lq_sta->flush_time)); + for (j = 0; j < IWL_RATE_COUNT; j++) { + desc += sprintf(buff+desc, + "counter=%d success=%d %%=%d\n", + lq_sta->win[j].counter, + lq_sta->win[j].success_counter, + lq_sta->win[j].success_ratio); + } + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_stats_table_ops = { + .read = iwl3945_sta_dbgfs_stats_table_read, + .open = iwl3945_open_file_generic, +}; + +static void iwl3945_add_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + struct iwl3945_rs_sta *lq_sta = priv_sta; + + lq_sta->rs_sta_dbgfs_stats_table_file = + debugfs_create_file("rate_stats_table", 0600, dir, + lq_sta, &rs_sta_dbgfs_stats_table_ops); + +} + +static void iwl3945_remove_debugfs(void *priv, void *priv_sta) +{ + struct iwl3945_rs_sta *lq_sta = priv_sta; + debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); +} +#endif + static struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, @@ -782,6 +839,11 @@ static struct rate_control_ops rs_ops = { .free = rs_free, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = iwl3945_add_debugfs, + .remove_sta_debugfs = iwl3945_remove_debugfs, +#endif + }; void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) -- cgit v1.1 From 74221d07408c473721cce853ef4e0e66c0b326ba Mon Sep 17 00:00:00 2001 From: "Abbas, Mohamed" Date: Tue, 2 Dec 2008 12:14:03 -0800 Subject: iwl3945: Fix iwl3945 rate scaling. 3945 rate scaling was broken in recent tree. This patch fix the following: 1- Get TX response info and update rates window. 2- Rate scaling selection. 3- Flush window timer. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 83 ++++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-3945.c | 24 ++------- 2 files changed, 52 insertions(+), 55 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 76100d5..b03dd06 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -117,9 +117,11 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { }; #define IWL_RATE_MAX_WINDOW 62 -#define IWL_RATE_FLUSH (3*HZ/10) +#define IWL_RATE_FLUSH (3*HZ) #define IWL_RATE_WIN_FLUSH (HZ/2) #define IWL_RATE_HIGH_TH 11520 +#define IWL_SUCCESS_UP_TH 8960 +#define IWL_SUCCESS_DOWN_TH 10880 #define IWL_RATE_MIN_FAILURE_TH 8 #define IWL_RATE_MIN_SUCCESS_TH 8 #define IWL_RATE_DECREASE_TH 1920 @@ -206,6 +208,7 @@ static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta) #define IWL_RATE_FLUSH_MAX 5000 /* msec */ #define IWL_RATE_FLUSH_MIN 50 /* msec */ +#define IWL_AVERAGE_PACKETS 1500 static void iwl3945_bg_rate_scale_flush(unsigned long data) { @@ -220,8 +223,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) spin_lock_irqsave(&rs_sta->lock, flags); - rs_sta->flush_pending = 0; - /* Number of packets Rx'd since last time this timer ran */ packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1; @@ -230,7 +231,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) if (unflushed) { duration = jiffies_to_msecs(jiffies - rs_sta->last_partial_flush); -/* duration = jiffies_to_msecs(rs_sta->flush_time); */ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", packet_count, duration); @@ -242,9 +242,11 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) pps = 0; if (pps) { - duration = IWL_RATE_FLUSH_MAX / pps; + duration = (IWL_AVERAGE_PACKETS * 1000) / pps; if (duration < IWL_RATE_FLUSH_MIN) duration = IWL_RATE_FLUSH_MIN; + else if (duration > IWL_RATE_FLUSH_MAX) + duration = IWL_RATE_FLUSH_MAX; } else duration = IWL_RATE_FLUSH_MAX; @@ -257,8 +259,10 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) rs_sta->flush_time); rs_sta->last_partial_flush = jiffies; + } else { + rs_sta->flush_time = IWL_RATE_FLUSH; + rs_sta->flush_pending = 0; } - /* If there weren't any unflushed entries, we don't schedule the timer * to run again */ @@ -278,17 +282,18 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) */ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, struct iwl3945_rate_scale_data *window, - int success, int retries) + int success, int retries, int index) { unsigned long flags; + s32 fail_count; if (!retries) { IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); return; } + spin_lock_irqsave(&rs_sta->lock, flags); while (retries--) { - spin_lock_irqsave(&rs_sta->lock, flags); /* If we have filled up the window then subtract one from the * success counter if the high-bit is counting toward @@ -316,8 +321,18 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, /* Tag this window as having been updated */ window->stamp = jiffies; - spin_unlock_irqrestore(&rs_sta->lock, flags); } + + fail_count = window->counter - window->success_counter; + if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + window->average_tpt = ((window->success_ratio * + rs_sta->expected_tpt[index] + 64) / 128); + else + window->average_tpt = IWL_INV_TPT; + + spin_unlock_irqrestore(&rs_sta->lock, flags); + } static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, @@ -429,19 +444,16 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - u8 retries = 0, current_count; + s8 retries = 0, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct iwl3945_rs_sta *rs_sta = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int i; IWL_DEBUG_RATE("enter\n"); - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) - retries += info->status.rates[i].count; - retries--; + retries = info->status.rates[0].count; first_index = sband->bitrates[info->status.rates[0].idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { @@ -469,9 +481,9 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband * at which the frame was finally transmitted (or failed if no * ACK) */ - while (retries > 0) { - if (retries < priv->retry_rate) { - current_count = retries; + while (retries > 1) { + if ((retries - 1) < priv->retry_rate) { + current_count = (retries - 1); last_index = scale_rate_index; } else { current_count = priv->retry_rate; @@ -483,15 +495,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband * as was used for it (per current_count) */ iwl3945_collect_tx_data(rs_sta, &rs_sta->win[scale_rate_index], - 0, current_count); + 0, current_count, scale_rate_index); IWL_DEBUG_RATE("Update rate %d for %d retries.\n", scale_rate_index, current_count); retries -= current_count; - if (retries) - scale_rate_index = - iwl3945_rs_next_rate(priv, scale_rate_index); + scale_rate_index = last_index; } @@ -502,7 +512,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband "success" : "failure"); iwl3945_collect_tx_data(rs_sta, &rs_sta->win[last_index], - info->flags & IEEE80211_TX_STAT_ACK, 1); + info->flags & IEEE80211_TX_STAT_ACK, 1, last_index); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush @@ -510,9 +520,10 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband spin_lock_irqsave(&rs_sta->lock, flags); if (!rs_sta->flush_pending && - time_after(jiffies, rs_sta->last_partial_flush + + time_after(jiffies, rs_sta->last_flush + rs_sta->flush_time)) { + rs_sta->last_partial_flush = jiffies; rs_sta->flush_pending = 1; mod_timer(&rs_sta->rate_scale_flush, jiffies + rs_sta->flush_time); @@ -660,8 +671,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, spin_lock_irqsave(&rs_sta->lock, flags); + /* for recent assoc, choose best rate regarding + * to rssi value + */ if (rs_sta->start_rate != IWL_RATE_INVALID) { - index = rs_sta->start_rate; + if (rs_sta->start_rate < index && + (rate_mask & (1 << rs_sta->start_rate))) + index = rs_sta->start_rate; rs_sta->start_rate = IWL_RATE_INVALID; } @@ -671,7 +687,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { - window->average_tpt = IWL_INV_TPT; spin_unlock_irqrestore(&rs_sta->lock, flags); IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " @@ -685,8 +700,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, } - window->average_tpt = ((window->success_ratio * - rs_sta->expected_tpt[index] + 64) / 128); current_tpt = window->average_tpt; high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, @@ -734,13 +747,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, } } - if ((window->success_ratio > IWL_RATE_HIGH_TH) || - (current_tpt > window->average_tpt)) { - IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or " - "current_tpt [%d] > average_tpt [%d]\n", - window->success_ratio, - current_tpt, window->average_tpt); - scale_action = 0; + if (scale_action == -1) { + if (window->success_ratio > IWL_SUCCESS_DOWN_TH) + scale_action = 0; + } else if (scale_action == 1) { + if (window->success_ratio < IWL_SUCCESS_UP_TH) { + IWL_DEBUG_RATE("No action -- success_ratio [%d] < " + "SUCCESS UP\n", window->success_ratio); + scale_action = 0; + } } switch (scale_action) { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 6150004..d95a15f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -337,7 +337,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; - int fail, i; + int fail; if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -356,27 +356,9 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, rate_idx -= IWL_FIRST_OFDM_RATE; fail = tx_resp->failure_frame; - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - int next = iwl3945_rs_next_rate(priv, rate_idx); - info->status.rates[i].idx = rate_idx; - - /* - * Put remaining into the last count as best approximation - * of saying exactly what the hardware would have done... - */ - if ((rate_idx == next) || (i == IEEE80211_TX_MAX_RATES - 1)) { - info->status.rates[i].count = fail; - break; - } - - info->status.rates[i].count = priv->retry_rate; - fail -= priv->retry_rate; - rate_idx = next; - if (fail <= 0) - break; - } - info->status.rates[i].count++; /* add final attempt */ + info->status.rates[0].idx = rate_idx; + info->status.rates[0].count = fail + 1; /* add final attempt */ /* tx_status->rts_retry_count = tx_resp->failure_rts; */ info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? -- cgit v1.1 From f3f911d1773d31f11038d90b04244bc3986c4ccd Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 2 Dec 2008 12:14:04 -0800 Subject: iwlwifi: fix DMA channel number in iwl_txq_ctx_stop The patch fixes the misuse of DMA channel number by Tx queue number in iwl_tx_ctx_stop(). The problem was originally reported by Wu Fengguang who complains iwlagn driver takes too long time when issuing `ifconfig wlan0 down`. The patch now decreases the interface bring down time from 2 seconds to 0.8 second. This fixes bugs: http://bugzilla.kernel.org/show_bug.cgi?id=11956 http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1790 Signed-off-by: Zhu Yi Tested-by: Fengguang Wu Acked-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +++- drivers/net/wireless/iwlwifi/iwl-tx.c | 11 +++++------ 4 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f90c9e9..93d3df8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -816,6 +816,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.max_stations = IWL4965_STATION_COUNT; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b6c57cb..f7a8df8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -827,6 +827,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.max_stations = IWL5000_STATION_COUNT; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 846b8b0..5f6805b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -508,6 +508,7 @@ struct iwl_sensitivity_ranges { /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported + * @dma_chnl_num: Number of Tx DMA/FIFO channels * @scd_bc_tbls_size: size of scheduler byte count tables * @tx/rx_chains_num: Number of TX/RX chains * @valid_tx/rx_ant: usable antennas @@ -525,7 +526,8 @@ struct iwl_sensitivity_ranges { * @struct iwl_sensitivity_ranges: range of sensitivity values */ struct iwl_hw_params { - u16 max_txq_num; + u8 max_txq_num; + u8 dma_chnl_num; u16 scd_bc_tbls_size; u8 tx_chains_num; u8 rx_chains_num; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index e045dfe..18d6cf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -611,7 +611,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) */ void iwl_txq_ctx_stop(struct iwl_priv *priv) { - int txq_id; + int ch; unsigned long flags; /* Turn off all Tx DMA fifos */ @@ -624,12 +624,11 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) priv->cfg->ops->lib->txq_set_sched(priv, 0); /* Stop each Tx DMA channel, and wait for it to be idle */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - iwl_write_direct32(priv, - FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) { + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE - (txq_id), 200); + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), + 200); } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.1 From c02b3acd29766c6f79c2411cb5b85e1ee72c4c8f Mon Sep 17 00:00:00 2001 From: "Chatre, Reinette" Date: Tue, 2 Dec 2008 12:14:05 -0800 Subject: iwlwifi: store ucode version number We store the ucode version number as part of iwl_priv/iwl3945_priv. This enables us to determine if particular ucode has support for features in order to have driver support more than one ucode API. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-commands.h | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-3945.h | 4 +++- drivers/net/wireless/iwlwifi/iwl-agn.c | 12 +++++++++--- drivers/net/wireless/iwlwifi/iwl-commands.h | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 12 +++++++++--- 6 files changed, 36 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 735891a..daf99ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -69,6 +69,12 @@ #ifndef __iwl_3945_commands_h__ #define __iwl_3945_commands_h__ +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) + enum { REPLY_ALIVE = 0x1, REPLY_ERROR = 0x2, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 2a924c1..972c454 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -505,7 +505,7 @@ struct fw_desc { /* uCode file layout */ struct iwl3945_ucode { - __le32 ver; /* major/minor/subminor */ + __le32 ver; /* major/minor/API/serial */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ __le32 init_size; /* bytes of initialization instructions */ @@ -762,6 +762,8 @@ struct iwl3945_priv { void __iomem *hw_base; /* uCode images, save to reload in case of failure */ + u32 ucode_ver; /* ucode version, copy of + iwl3945_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_data_backup; /* runtime data save/restore */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e8368b6..5912cde 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1575,7 +1575,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) const char *name = priv->cfg->fw_name; u8 *src; size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ @@ -1599,14 +1599,20 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Data from ucode file: header followed by uCode images */ ucode = (void *)ucode_raw->data; - ver = le32_to_cpu(ucode->ver); + priv->ucode_ver = le32_to_cpu(ucode->ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); + IWL_DEBUG_INFO("f/w package hdr ucode version = %u.%u.%u.%u\n", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 9c786db..528bcab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -69,6 +69,12 @@ #ifndef __iwl_commands_h__ #define __iwl_commands_h__ +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) + enum { REPLY_ALIVE = 0x1, REPLY_ERROR = 0x2, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5f6805b..a19fbb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -462,7 +462,7 @@ struct fw_desc { /* uCode file layout */ struct iwl_ucode { - __le32 ver; /* major/minor/subminor */ + __le32 ver; /* major/minor/API/serial */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ __le32 init_size; /* bytes of initialization instructions */ @@ -843,6 +843,8 @@ struct iwl_priv { u8 rev_id; /* uCode images, save to reload in case of failure */ + u32 ucode_ver; /* version of ucode, copy of + iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_data_backup; /* runtime data save/restore */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 12ff112..03ff87f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5302,7 +5302,7 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) const char *name = priv->cfg->fw_name; u8 *src; size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ @@ -5326,14 +5326,20 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) /* Data from ucode file: header followed by uCode images */ ucode = (void *)ucode_raw->data; - ver = le32_to_cpu(ucode->ver); + priv->ucode_ver = le32_to_cpu(ucode->ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); + IWL_DEBUG_INFO("f/w package hdr ucode version = %u.%u.%u.%u\n", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size); IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size); -- cgit v1.1 From a0987a8d68c86562f267efa97be01314c490c496 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Tue, 2 Dec 2008 12:14:06 -0800 Subject: iwlwifi: rely on API version read from firmware This adds the infrastructure to support older firmware APIs. The API version number is stored as part of the filename, we first try to load the most recent firmware and progressively try lower versions. The API version is also read from the firmware self and stored as part of the iwl_priv structure. Only firmware that is supported by driver will be loaded. The version number read from firmware is compared to supported versions in the driver not the API version used as part of filename. An example using this new infrastrucure: if (IWL_UCODE_API(priv->ucode_ver) >= 2) { Driver interacts with Firmware API version >= 2. } else { Driver interacts with Firmware API version 1. } Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-core.h | 26 ++++++++++- drivers/net/wireless/iwlwifi/iwl-3945.c | 8 +++- drivers/net/wireless/iwlwifi/iwl-3945.h | 14 +++--- drivers/net/wireless/iwlwifi/iwl-4965.c | 21 +++++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 46 ++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-agn.c | 62 +++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 32 +++++++++++++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 64 ++++++++++++++++++++++------ 8 files changed, 217 insertions(+), 56 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h index bc12f97..edac6c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h @@ -71,9 +71,33 @@ #define IWL_SKU_G 0x1 #define IWL_SKU_A 0x2 +/** + * struct iwl_3945_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. The firmware's API version will be + * stored in @iwl_priv, enabling the driver to make runtime changes based + * on firmware version used. + * + * For example, + * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + * Driver interacts with Firmware API version >= 2. + * } else { + * Driver interacts with Firmware API version 1. + * } + */ struct iwl_3945_cfg { const char *name; - const char *fw_name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_min; unsigned int sku; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index d95a15f..4e6b715 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2508,13 +2508,17 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv) static struct iwl_3945_cfg iwl3945_bg_cfg = { .name = "3945BG", - .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_G, }; static struct iwl_3945_cfg iwl3945_abg_cfg = { .name = "3945ABG", - .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 972c454..d6502b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -50,11 +50,15 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-3945-debug.h" #include "iwl-3945-led.h" -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL3945_UCODE_API "-1" +/* Highest firmware API version supported */ +#define IWL3945_UCODE_API_MAX 1 + +/* Lowest firmware API version supported */ +#define IWL3945_UCODE_API_MIN 1 + +#define IWL3945_FW_PRE "iwlwifi-3945-" +#define _IWL3945_MODULE_FIRMWARE(api) IWL3945_FW_PRE #api ".ucode" +#define IWL3945_MODULE_FIRMWARE(api) _IWL3945_MODULE_FIRMWARE(api) /* Default noise level to report when noise measurement is not available. * This may be because we're: diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 93d3df8..87c7bb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -48,12 +48,15 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv); static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL4965_UCODE_API "-2" -#define IWL4965_MODULE_FIRMWARE "iwlwifi-4965" IWL4965_UCODE_API ".ucode" +/* Highest firmware API version supported */ +#define IWL4965_UCODE_API_MAX 2 + +/* Lowest firmware API version supported */ +#define IWL4965_UCODE_API_MIN 2 + +#define IWL4965_FW_PRE "iwlwifi-4965-" +#define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode" +#define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api) /* module parameters */ @@ -2336,7 +2339,9 @@ static struct iwl_ops iwl4965_ops = { struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", - .fw_name = IWL4965_MODULE_FIRMWARE, + .fw_name_pre = IWL4965_FW_PRE, + .ucode_api_max = IWL4965_UCODE_API_MAX, + .ucode_api_min = IWL4965_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .eeprom_size = IWL4965_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_4965_EEPROM_VERSION, @@ -2346,7 +2351,7 @@ struct iwl_cfg iwl4965_agn_cfg = { }; /* Module firmware */ -MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE); +MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f7a8df8..438e4bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -44,11 +44,21 @@ #include "iwl-helpers.h" #include "iwl-5000-hw.h" -#define IWL5000_UCODE_API "-1" -#define IWL5150_UCODE_API "-1" +/* Highest firmware API version supported */ +#define IWL5000_UCODE_API_MAX 1 +#define IWL5150_UCODE_API_MAX 1 -#define IWL5000_MODULE_FIRMWARE "iwlwifi-5000" IWL5000_UCODE_API ".ucode" -#define IWL5150_MODULE_FIRMWARE "iwlwifi-5150" IWL5150_UCODE_API ".ucode" +/* Lowest firmware API version supported */ +#define IWL5000_UCODE_API_MIN 1 +#define IWL5150_UCODE_API_MIN 1 + +#define IWL5000_FW_PRE "iwlwifi-5000-" +#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" +#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) + +#define IWL5150_FW_PRE "iwlwifi-5150-" +#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" +#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC3, @@ -1532,7 +1542,9 @@ static struct iwl_mod_params iwl50_mod_params = { struct iwl_cfg iwl5300_agn_cfg = { .name = "5300AGN", - .fw_name = IWL5000_MODULE_FIRMWARE, + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1543,7 +1555,9 @@ struct iwl_cfg iwl5300_agn_cfg = { struct iwl_cfg iwl5100_bg_cfg = { .name = "5100BG", - .fw_name = IWL5000_MODULE_FIRMWARE, + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1554,7 +1568,9 @@ struct iwl_cfg iwl5100_bg_cfg = { struct iwl_cfg iwl5100_abg_cfg = { .name = "5100ABG", - .fw_name = IWL5000_MODULE_FIRMWARE, + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1565,7 +1581,9 @@ struct iwl_cfg iwl5100_abg_cfg = { struct iwl_cfg iwl5100_agn_cfg = { .name = "5100AGN", - .fw_name = IWL5000_MODULE_FIRMWARE, + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1576,7 +1594,9 @@ struct iwl_cfg iwl5100_agn_cfg = { struct iwl_cfg iwl5350_agn_cfg = { .name = "5350AGN", - .fw_name = IWL5000_MODULE_FIRMWARE, + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1587,7 +1607,9 @@ struct iwl_cfg iwl5350_agn_cfg = { struct iwl_cfg iwl5150_agn_cfg = { .name = "5150AGN", - .fw_name = IWL5150_MODULE_FIRMWARE, + .fw_name_pre = IWL5150_FW_PRE, + .ucode_api_max = IWL5150_UCODE_API_MAX, + .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, @@ -1596,8 +1618,8 @@ struct iwl_cfg iwl5150_agn_cfg = { .mod_params = &iwl50_mod_params, }; -MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE); -MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE); +MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 5912cde..b3c263d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1570,24 +1570,40 @@ static void iwl_nic_start(struct iwl_priv *priv) static int iwl_read_ucode(struct iwl_priv *priv) { struct iwl_ucode *ucode; - int ret; + int ret = -EINVAL, index; const struct firmware *ucode_raw; - const char *name = priv->cfg->fw_name; + const char *name_pre = priv->cfg->fw_name_pre; + const unsigned int api_max = priv->cfg->ucode_api_max; + const unsigned int api_min = priv->cfg->ucode_api_min; + char buf[25]; u8 *src; size_t len; - u32 inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; + for (index = api_max; index >= api_min; index--) { + sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); + ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + buf, ret); + if (ret == -ENOENT) + continue; + else + goto error; + } else { + if (index < api_max) + IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", + buf, api_max); + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + buf, ucode_raw->size); + break; + } } - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); + if (ret < 0) + goto error; /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { @@ -1600,19 +1616,39 @@ static int iwl_read_ucode(struct iwl_priv *priv) ucode = (void *)ucode_raw->data; priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", - priv->ucode_ver); - IWL_DEBUG_INFO("f/w package hdr ucode version = %u.%u.%u.%u\n", + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firware header from here on forward */ + + if (api_ver < api_min || api_ver > api_max) { + IWL_ERROR("Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + priv->ucode_ver = 0; + ret = -EINVAL; + goto err_release; + } + if (api_ver != api_max) + IWL_ERROR("Firmware has old API version. Expected v%u, " + "got v%u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + + printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", IWL_UCODE_MAJOR(priv->ucode_ver), IWL_UCODE_MINOR(priv->ucode_ver), IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f68883b..81ddca0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -164,9 +164,39 @@ struct iwl_mod_params { int restart_fw; /* def: 1 = restart firmware */ }; +/** + * struct iwl_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. The firmware's API version will be + * stored in @iwl_priv, enabling the driver to make runtime changes based + * on firmware version used. + * + * For example, + * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + * Driver interacts with Firmware API version >= 2. + * } else { + * Driver interacts with Firmware API version 1. + * } + * + * The ideal usage of this infrastructure is to treat a new ucode API + * release as a new hardware revision. That is, through utilizing the + * iwl_hcmd_utils_ops etc. we accommodate different command structures + * and flows between hardware versions (4965/5000) as well as their API + * versions. + */ struct iwl_cfg { const char *name; - const char *fw_name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_min; unsigned int sku; int eeprom_size; u16 eeprom_ver; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 03ff87f..1d3efa9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5296,25 +5296,41 @@ static void iwl3945_nic_start(struct iwl3945_priv *priv) static int iwl3945_read_ucode(struct iwl3945_priv *priv) { struct iwl3945_ucode *ucode; - int ret = 0; + int ret = -EINVAL, index; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ - const char *name = priv->cfg->fw_name; + const char *name_pre = priv->cfg->fw_name_pre; + const unsigned int api_max = priv->cfg->ucode_api_max; + const unsigned int api_min = priv->cfg->ucode_api_min; + char buf[25]; u8 *src; size_t len; - u32 inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; + for (index = api_max; index >= api_min; index--) { + sprintf(buf, "%s%u%s", name_pre, index, ".ucode"); + ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + buf, ret); + if (ret == -ENOENT) + continue; + else + goto error; + } else { + if (index < api_max) + IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", + buf, api_max); + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + buf, ucode_raw->size); + break; + } } - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); + if (ret < 0) + goto error; /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { @@ -5327,25 +5343,45 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) ucode = (void *)ucode_raw->data; priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", - priv->ucode_ver); - IWL_DEBUG_INFO("f/w package hdr ucode version = %u.%u.%u.%u\n", + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firware header from here on forward */ + + if (api_ver < api_min || api_ver > api_max) { + IWL_ERROR("Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + priv->ucode_ver = 0; + ret = -EINVAL; + goto err_release; + } + if (api_ver != api_max) + IWL_ERROR("Firmware has old API version. Expected %u, " + "got %u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + + printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", IWL_UCODE_MAJOR(priv->ucode_ver), IWL_UCODE_MINOR(priv->ucode_ver), IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size); IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size); IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size); IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size); + /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size < sizeof(*ucode) + inst_size + data_size + init_size + @@ -8304,7 +8340,7 @@ static void __exit iwl3945_exit(void) iwl3945_rate_control_unregister(); } -MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); module_param_named(antenna, iwl3945_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -- cgit v1.1 From 011a03300bdd60782f465b97c3aefd58bfaae316 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Tue, 2 Dec 2008 12:14:07 -0800 Subject: iwl3945 : Fix a-band association for passive channels Patch does following things 1) This patch fixes the a-band association for passive channels with new uCode feature that it allows direct scan on passive channels after auto-switch from passive to active. This enables sending of direct probes on passive channels, as long as some traffic is detected on that channel. This improves the scanning for hidden SSIDs in A-band,which is all passive channels. This patch fixes the bug no 1748. http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1748 2) This fix will only work with uCode version 15.28.2.8 and above. Prior versions of uCode would work only if we heard the traffic within active dwell time, which is much shorter than passive dwell time and is shorter than typical beacon periods. This patch also provids full active dwell time even if we hear traffic late in passive dwell. 3) uCode API version is incremented to 2. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 30 ++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index d6502b4..5c2c15e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -51,7 +51,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-3945-led.h" /* Highest firmware API version supported */ -#define IWL3945_UCODE_API_MAX 1 +#define IWL3945_UCODE_API_MAX 2 /* Lowest firmware API version supported */ #define IWL3945_UCODE_API_MIN 1 diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 1d3efa9..1a411c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4785,17 +4785,33 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, continue; } + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* If passive , set up for auto-switch + * and use long active_dwell time. + */ if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) { scan_ch->type = 0; /* passive */ - else + if (IWL_UCODE_API(priv->ucode_ver) == 1) + scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1); + } else { scan_ch->type = 1; /* active */ + } - if ((scan_ch->type & 1) && n_probes) - scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); - - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* Set direct probe bits. These may be used both for active + * scan channels (probes gets sent right away), + * or for passive channels (probes get se sent only after + * hearing clear Rx packet).*/ + if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + if (n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + } else { + /* uCode v1 does not allow setting direct probe bits on + * passive channel. */ + if ((scan_ch->type & 1) && n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + } /* Set txpower levels to defaults */ scan_ch->tpc.dsp_atten = 110; -- cgit v1.1 From 74415edb042ef9f3b1291f978763687f35aadbb3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 2 Dec 2008 22:50:33 +0100 Subject: rt2x00: Add RXDONE_CRYPTO_IV/ICV flags Drivers should notify rt2x00lib when they provide the IV/ICV data. This adds some flexibility to drivers which can't provide all information. * rt2500usb provides ICV inside the frame * rt2800pci doesn't provide IV/ICV * rt2800usb doesn't provide IV/ICV Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 2 ++ drivers/net/wireless/rt2x00/rt2x00dev.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00queue.h | 4 ++++ drivers/net/wireless/rt2x00/rt61pci.c | 3 +++ drivers/net/wireless/rt2x00/rt73usb.c | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 90bf0b9..30028e2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1330,6 +1330,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rxdesc->cipher != CIPHER_NONE) { _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + /* ICV is located at the end of frame */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 7fc1d76..6d92542 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -636,7 +636,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * provided seperately (through hardware descriptor) * in which case we should reinsert the data into the frame. */ - if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) { + if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && + (rxdesc.flags & RX_FLAG_IV_STRIPPED)) { rt2x00crypto_rx_insert_iv(entry->skb, align, header_length, &rxdesc); } else if (align) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 7889f91..2829371 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -146,11 +146,15 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) * @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. + * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. + * @RXDONE_CRYPTO_ICV: Driver provided ICV data. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, RXDONE_SIGNAL_BITRATE = 1 << 1, RXDONE_MY_BSS = 1 << 2, + RXDONE_CRYPTO_IV = 1 << 3, + RXDONE_CRYPTO_ICV = 1 << 4, }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c1ebb65..987e890 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1951,7 +1951,10 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, if (rxdesc->cipher != CIPHER_NONE) { _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]); _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); + rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* * Hardware has stripped IV/EIV data from 802.11 frame during diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3c8b235..d638a8a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1620,7 +1620,10 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rxdesc->cipher != CIPHER_NONE) { _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* * Hardware has stripped IV/EIV data from 802.11 frame during -- cgit v1.1 From 4c7f0bc266ccccfb0ca397405af13ee3d9e0f6b2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 3 Dec 2008 00:19:04 -0800 Subject: generic swap(): ath9k: rename swap() to swap_array() In preparation for the introduction of a generic swap() macro. Signed-off-by: Wu Fengguang Cc: Sujith Manoharan Cc: Luis R. Rodriguez Cc: Vasanthakumar Thiagarajan Cc: Senthil Balasubramanian Cc: Jouni Malinen Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/regd.c | 2 +- drivers/net/wireless/ath9k/regd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 42ce1d9..64043e9 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -42,7 +42,7 @@ ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp) u8 *u = t - size; if (cmp(u, t) <= 0) break; - swap(u, t, size); + swap_array(u, t, size); } } diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 0ecd344..512d990 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h @@ -125,7 +125,7 @@ #define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) -#define swap(_a, _b, _size) { \ +#define swap_array(_a, _b, _size) { \ u8 *s = _b; \ int i = _size; \ do { \ -- cgit v1.1 From 1c02667db5eae801b8fc279fdfa618164c0efb6e Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 3 Dec 2008 17:29:21 +0100 Subject: rt2x00: Fix check for BSS info changes Fix ERP configuration, due to a too strict changes flags checking we never updated the short slot time or basic rate mask when no other changes were made at the same time. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index fa91ca5..dded680 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -634,7 +634,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ - if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) { + if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); else -- cgit v1.1 From 9c3444d33e65ade06af82d19522686c1873b953a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 3 Dec 2008 17:29:48 +0100 Subject: rt2x00: Move crypto TX descriptor handling to rt2x00crypto.c Move all code which determines the right TX descriptor fields specific to crypto support into rt2x00crypto.c. This makes the code in rt2x00queue more simpler and better concentrates all crypto code into a single location. With this we can also remove some ifdefs in rt2x00queue.c since the code inside the ifdef is either very small, or only calling empty functions (see empty function definitions in rt2x00lib.h). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00crypto.c | 23 +++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00lib.h | 9 ++++++++- drivers/net/wireless/rt2x00/rt2x00queue.c | 29 +++++------------------------ 3 files changed, 36 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index c6709b3..37ad0d2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -46,6 +46,29 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) } } +void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + + __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); + + txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); + + if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); + + txdesc->key_idx = hw_key->hw_key_idx; + txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); +} + unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) { struct ieee80211_key_conf *key = tx_info->control.hw_key; diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 1e189377..0302432 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -218,6 +218,8 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, */ #ifdef CONFIG_RT2X00_LIB_CRYPTO enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); +void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); @@ -231,6 +233,11 @@ static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf * return CIPHER_NONE; } +static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ +} + static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) { return 0; @@ -256,7 +263,7 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc) { } -#endif +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * RFkill handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e4a1dbe..eaec6bd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -55,14 +55,12 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, /* * For IV/EIV/ICV assembly we must make sure there is * at least 8 bytes bytes available in headroom for IV/EIV - * and 4 bytes for ICV data as tailroon. + * and 8 bytes for ICV data as tailroon. */ -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { head_size += 8; - tail_size += 4; + tail_size += 8; } -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Allocate skbuffer. @@ -174,7 +172,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; - /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */ + /* Data length + CRC */ data_length = entry->skb->len + 4; /* @@ -183,34 +181,17 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) __set_bit(ENTRY_TXD_ACK, &txdesc->flags); -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) && !entry->skb->do_not_encrypt) { - struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - - __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); - - txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); - - if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) - __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); - - txdesc->key_idx = hw_key->hw_key_idx; - txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + /* Apply crypto specific descriptor information */ + rt2x00crypto_create_tx_descriptor(entry, txdesc); /* * Extend frame length to include all encryption overhead * that will be added by the hardware. */ data_length += rt2x00crypto_tx_overhead(tx_info); - - if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) - __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); - - if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) - __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); } -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Check if this is a RTS/CTS frame -- cgit v1.1 From 73a5267087b5acd4a4288e0a1b809f09ca578d49 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 3 Dec 2008 17:30:22 +0100 Subject: rt2x00: Correctly initialize AID during set_key() Request the AID from hardware and provide this id to the driver (in case they need it). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index dded680..38edee5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -487,6 +487,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_sta *sta; int (*set_key) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); @@ -537,6 +538,17 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, memcpy(&crypto.key, &key->key[0], key->keylen); /* + * Discover the Association ID from mac80211. + * Some drivers need this information when updating the + * hardware key (either adding or removing). + */ + rcu_read_lock(); + sta = ieee80211_find_sta(hw, address); + if (sta) + crypto.aid = sta->aid; + rcu_read_unlock(); + + /* * Each BSS has a maximum of 4 shared keys. * Shared key index values: * 0) BSS0 key0 -- cgit v1.1 From f8316df10c4e3bec5b4c3a5a8e026c577640c3a6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 3 Dec 2008 03:35:29 -0800 Subject: ath9k: Check for pci_map_single() errors pci_map_single() can fail so detect those errors with pci_dma_mapping_error() and deal with them accordingly. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 16 +++++++++++++++- drivers/net/wireless/ath9k/recv.c | 17 +++++++++++++++++ drivers/net/wireless/ath9k/xmit.c | 23 +++++++++++++++++++++-- 3 files changed, 53 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index fe6929d..507299b 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -190,6 +190,13 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on beaconing\n"); + return NULL; + } skb = ieee80211_get_buffered_bc(sc->hw, vif); @@ -392,11 +399,18 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) memcpy(&hdr[1], &val, sizeof(val)); } + bf->bf_mpdu = skb; bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - bf->bf_mpdu = skb; + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on beacon alloc\n"); + return -ENOMEM; + } return 0; } diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 51e0587..7a45546 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -304,6 +304,15 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, sc->sc_rxbufsize, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on RX init\n"); + error = -ENOMEM; + break; + } bf->bf_dmacontext = bf->bf_buf_addr; } sc->sc_rxlink = NULL; @@ -589,6 +598,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data, sc->sc_rxbufsize, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(requeue_skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on RX\n"); + break; + } bf->bf_dmacontext = bf->bf_buf_addr; /* diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 5cf8311..17fd05e 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1642,7 +1642,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, } } -static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, +static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb, struct ath_tx_control *txctl) { @@ -1701,9 +1701,18 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, /* DMA setup */ bf->bf_mpdu = skb; + bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) { + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on TX\n"); + return -ENOMEM; + } + bf->bf_buf_addr = bf->bf_dmacontext; + return 0; } /* FIXME: tx power */ @@ -1775,10 +1784,12 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, spin_unlock_bh(&txctl->txq->axq_lock); } +/* Upon failure caller should free skb */ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, struct ath_tx_control *txctl) { struct ath_buf *bf; + int r; /* Check if a tx buffer is available */ @@ -1788,7 +1799,15 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, return -1; } - ath_tx_setup_buffer(sc, bf, skb, txctl); + r = ath_tx_setup_buffer(sc, bf, skb, txctl); + if (unlikely(r)) { + spin_lock_bh(&sc->sc_txbuflock); + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); + list_add_tail(&bf->list, &sc->sc_txbuf); + spin_unlock_bh(&sc->sc_txbuflock); + return r; + } + ath_tx_start_dma(sc, bf, txctl); return 0; -- cgit v1.1 From c112d0c5b89037dd618083b5fdf4bb36b0c51d77 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 3 Dec 2008 03:35:30 -0800 Subject: ath9k: Use GFP_ATOMIC when allocating TX private area Using GFP_KERNEL was wrong and produces a 'scheduling while atomic' bug as we're in a tasklet. Also, check for proper return values now, in case allocation fails and be sure to stop the TX queue in case of memory issues but gaurantee the TX queue will eventually be woken up. Signed-off-by: Senthil Balasubramanian Signed-off-by: Sujith Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 17fd05e..9de27c6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1652,7 +1652,9 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, int hdrlen; __le16 fc; - tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_KERNEL); + tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + if (unlikely(!tx_info_priv)) + return -ENOMEM; tx_info->rate_driver_data[0] = tx_info_priv; hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; @@ -1801,10 +1803,26 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, r = ath_tx_setup_buffer(sc, bf, skb, txctl); if (unlikely(r)) { - spin_lock_bh(&sc->sc_txbuflock); + struct ath_txq *txq = txctl->txq; + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); + + /* upon ath_tx_processq() this TX queue will be resumed, we + * guarantee this will happen by knowing beforehand that + * we will at least have to run TX completionon one buffer + * on the queue */ + spin_lock_bh(&txq->axq_lock); + if (ath_txq_depth(sc, txq->axq_qnum) > 1) { + ieee80211_stop_queue(sc->hw, + skb_get_queue_mapping(skb)); + txq->stopped = 1; + } + spin_unlock_bh(&txq->axq_lock); + + spin_lock_bh(&sc->sc_txbuflock); list_add_tail(&bf->list, &sc->sc_txbuf); spin_unlock_bh(&sc->sc_txbuflock); + return r; } -- cgit v1.1 From 8a1ec21e6c856b996cffcd4b33f037f6748a3ab4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 5 Dec 2008 22:31:52 -0800 Subject: tty: Flags should be accessed via the foo_bit interfaces We have various drivers that poke around directly and we need to clean this up before it causes problems. Signed-off-by: Alan Cox Signed-off-by: David S. Miller --- drivers/net/wireless/strip.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index cf0d070..f93caf4 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1252,7 +1252,7 @@ static void strip_write_some_more(struct tty_struct *tty) #endif } else { /* Else start transmission of another packet */ - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); strip_unlock(strip_info); } } @@ -1455,8 +1455,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) */ strip_info->tx_head = strip_info->tx_buff; strip_info->tx_left = ptr - strip_info->tx_buff; - strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - + set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); /* * 4. Debugging check to make sure we're not overflowing the buffer. */ @@ -2454,8 +2453,7 @@ static int strip_close_low(struct net_device *dev) if (strip_info->tty == NULL) return -EBUSY; - strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - + clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); netif_stop_queue(dev); /* -- cgit v1.1 From d2b88814c6a63e4018cd299826907a12068ffdb7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 5 Dec 2008 22:32:22 -0800 Subject: tty: driverdata and discdata are void * Remove all the extra casting while we are cleaning up Signed-off-by: Alan Cox Signed-off-by: David S. Miller --- drivers/net/wireless/strip.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index f93caf4..692e6c5 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1234,7 +1234,7 @@ static void ResetRadio(struct strip *strip_info) static void strip_write_some_more(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* First make sure we're connected. */ if (!strip_info || strip_info->magic != STRIP_MAGIC || @@ -2259,7 +2259,7 @@ static void process_message(struct strip *strip_info) static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; const unsigned char *end = cp + count; if (!strip_info || strip_info->magic != STRIP_MAGIC @@ -2594,7 +2594,7 @@ static struct strip *strip_alloc(void) static int strip_open(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're not already connected. @@ -2665,7 +2665,7 @@ static int strip_open(struct tty_struct *tty) static void strip_close(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're connected. @@ -2691,7 +2691,7 @@ static void strip_close(struct tty_struct *tty) static int strip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're connected. -- cgit v1.1 From b74ca3a896b9ab5f952bc440154758e708c48884 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Mon, 8 Dec 2008 01:14:16 -0800 Subject: netdevice: Kill netdev->priv This is the last shoot of this series. After I removing all directly reference of netdev->priv, I am killing "priv" of "struct net_device" and fixing relative comments/docs. Anyone will not be allowed to reference netdev->priv directly. If you want to reference the memory of private data, use netdev_priv() instead. If the private data is not allocted when alloc_netdev(), use netdev->ml_priv to point that memory after you creating that private data. Signed-off-by: Wang Chen Signed-off-by: David S. Miller --- drivers/net/wireless/strip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 692e6c5..dd0de3a 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2494,7 +2494,7 @@ static void strip_dev_setup(struct net_device *dev) dev->type = ARPHRD_METRICOM; /* dtang */ dev->hard_header_len = sizeof(STRIP_Header); /* - * dev->priv Already holds a pointer to our struct strip + * netdev_priv(dev) Already holds a pointer to our struct strip */ *(MetricomAddress *) & dev->broadcast = broadcast_address; -- cgit v1.1 From a7db74f4be3835fd16c6c582d320f692ccccc622 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 3 Dec 2008 22:21:20 -0600 Subject: rtl8187: Improve wireless statistics for RTL8187 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current wireless statistics for the RTL8187 poorly indicate the signal strength and quality. With testing, I found that the AGC value is inversely correlated with the strength as in the RTL8187B. By implementing a similar calculation, much more code becomes common to the two devices. Signed-off-by: Larry Finger Tested by: Martín Ernesto Barreyro Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 49 +++++++++--------------------- 1 file changed, 15 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index dbf52e8..417a2d7 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -313,29 +313,14 @@ static void rtl8187_rx_cb(struct urb *urb) struct rtl8187_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); flags = le32_to_cpu(hdr->flags); - signal = hdr->signal & 0x7f; + /* As with the RTL8187B below, the AGC is used to calculate + * signal strength and quality. In this case, the scaling + * constants are derived from the output of p54usb. + */ + quality = 130 - ((41 * hdr->agc) >> 6); + signal = -4 - ((27 * hdr->agc) >> 6); rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.noise = hdr->noise; rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->quality = signal; - rx_status.qual = priv->quality; - priv->noise = hdr->noise; - rate = (flags >> 20) & 0xF; - if (rate > 3) { /* OFDM rate */ - if (signal > 90) - signal = 90; - else if (signal < 25) - signal = 25; - signal = 90 - signal; - } else { /* CCK rate */ - if (signal > 95) - signal = 95; - else if (signal < 30) - signal = 30; - signal = 95 - signal; - } - rx_status.signal = signal; - priv->signal = signal; } else { struct rtl8187b_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); @@ -353,18 +338,18 @@ static void rtl8187_rx_cb(struct urb *urb) */ flags = le32_to_cpu(hdr->flags); quality = 170 - hdr->agc; - if (quality > 100) - quality = 100; signal = 14 - hdr->agc / 2; - rx_status.qual = quality; - priv->quality = quality; - rx_status.signal = signal; - priv->signal = signal; rx_status.antenna = (hdr->rssi >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); - rate = (flags >> 20) & 0xF; } + if (quality > 100) + quality = 100; + rx_status.qual = quality; + priv->quality = quality; + rx_status.signal = signal; + priv->signal = signal; + rate = (flags >> 20) & 0xF; skb_trim(skb, flags & 0x0FFF); rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; @@ -1293,6 +1278,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS; eeprom.data = dev; @@ -1408,13 +1394,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr >> 8; } - if (priv->is_rtl8187b) { + if (priv->is_rtl8187b) printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); - dev->flags |= IEEE80211_HW_SIGNAL_DBM; - } else { - dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; - dev->max_signal = 65; - } /* * XXX: Once this driver supports anything that requires -- cgit v1.1 From 00e540b3768c96a5e2a9d5d39524fef98b2cd981 Mon Sep 17 00:00:00 2001 From: "Halperin, Daniel C" Date: Fri, 5 Dec 2008 07:58:36 -0800 Subject: iwlwifi: implement iwl_debug_report_frame for iwlagn The old version of this code was copied from 3945 and never updated. This patch cleans up structs that do not apply and accounts for other changes from 3945->iwlagn (e.g., PHY info can come in a separate cmd response from the ucode.) Signed-off-by: Daniel Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 42 -------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 9 --- drivers/net/wireless/iwlwifi/iwl-rx.c | 85 +++++++++++------------------ 3 files changed, 31 insertions(+), 105 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 528bcab..45656f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1023,25 +1023,6 @@ struct iwl_wep_cmd { * *****************************************************************************/ -struct iwl4965_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __attribute__ ((packed)); - -struct iwl4965_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __attribute__ ((packed)); - #define RX_RES_STATUS_NO_CRC32_ERROR cpu_to_le32(1 << 0) #define RX_RES_STATUS_NO_RXE_OVERFLOW cpu_to_le32(1 << 1) @@ -1072,26 +1053,6 @@ struct iwl4965_rx_frame_hdr { #define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl4965_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __attribute__ ((packed)); - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl4965_rx_frame { - struct iwl4965_rx_frame_stats stats; - struct iwl4965_rx_frame_hdr hdr; - struct iwl4965_rx_frame_end end; -} __attribute__ ((packed)); - /* Fixed (non-configurable) rx data from phy */ #define IWL49_RX_RES_PHY_CNT 14 @@ -3049,7 +3010,6 @@ struct iwl_rx_packet { struct iwl_cmd_header hdr; union { struct iwl_alive_resp alive_frame; - struct iwl4965_rx_frame rx_frame; struct iwl4965_tx_resp tx_resp; struct iwl4965_spectrum_notification spectrum_notif; struct iwl4965_csa_notification csa_notif; @@ -3068,8 +3028,6 @@ struct iwl_rx_packet { } u; } __attribute__ ((packed)); -#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) - int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon); #endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a19fbb5..9d678d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -553,15 +553,6 @@ struct iwl_hw_params { #define HT_SHORT_GI_40MHZ (1 << 1) -#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ - x->u.rx_frame.stats.payload + \ - x->u.rx_frame.stats.phy_count)) -#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\ - IWL_RX_HDR(x)->payload + \ - le16_to_cpu(IWL_RX_HDR(x)->len))) -#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) -#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) - /****************************************************************************** * * Functions implemented in core module which are forward declared here diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 8d2b73e..6dd16c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -622,20 +622,24 @@ static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) return sig_qual; } -#ifdef CONFIG_IWLWIFI_DEBUG +/* Calc max signal level (dBm) among 3 possible receivers */ +static inline int iwl_calc_rssi(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp) +{ + return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); +} +#ifdef CONFIG_IWLWIFI_DEBUG /** * iwl_dbg_report_frame - dump frame to syslog during debug sessions * * You may hack this function to show different aspects of received frames, * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: This was originally written for 3945, need to audit for - * proper operation with 4965. + * group100 parameter selects whether to show 1 out of 100 good data frames. + * All beacon and probe response frames are printed. */ static void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, + struct iwl_rx_phy_res *phy_res, u16 length, struct ieee80211_hdr *header, int group100) { u32 to_us; @@ -647,20 +651,9 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u16 seq_ctl; u16 channel; u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; + u32 rate_n_flags; u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); + int rssi; if (likely(!(priv->debug_level & IWL_DL_RX))) return; @@ -670,22 +663,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, seq_ctl = le16_to_cpu(header->seq_ctrl); /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); + channel = le16_to_cpu(phy_res->channel); + phy_flags = le16_to_cpu(phy_res->phy_flags); + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); + rssi = iwl_calc_rssi(priv, phy_res); + tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; to_us = !compare_ether_addr(header->addr1, priv->mac_addr); @@ -739,11 +723,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, else title = "Frame"; - rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); - if (unlikely(rate_idx == -1)) + rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); + if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { bitrate = 0; - else + WARN_ON_ONCE(1); + } else { bitrate = iwl_rates[rate_idx].ieee / 2; + } /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -755,23 +741,22 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, length, rssi, channel, bitrate); else { /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, src=0x%02x, " + "len=%u, rssi=%d, tim=%lu usec, " "phy=0x%02x, chnl=%d\n", title, le16_to_cpu(fc), header->addr1[5], - header->addr3[5], rssi, + header->addr3[5], length, rssi, tsf_low - priv->scan_start_tsf, phy_flags, channel); } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, data, length); + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #else -static inline void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) +static void iwl_dbg_report_frame(struct iwl_priv *priv, + struct iwl_rx_phy_res *phy_res, u16 length, + struct ieee80211_hdr *header, int group100) { } #endif @@ -966,14 +951,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, rxb->skb = NULL; } -/* Calc max signal level (dBm) among 3 possible receivers */ -static inline int iwl_calc_rssi(struct iwl_priv *priv, - struct iwl_rx_phy_res *rx_resp) -{ - return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); -} - - /* This is necessary only for a number of statistics, see the caller. */ static int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) @@ -1096,8 +1073,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; /* Set "1" to report good data frames in groups of 100 */ - /* FIXME: need to optimize the call: */ - iwl_dbg_report_frame(priv, pkt, header, 1); + if (unlikely(priv->debug_level & IWL_DL_RX)) + iwl_dbg_report_frame(priv, rx_start, len, header, 1); IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.signal, -- cgit v1.1 From 7262796ab726fcefad9b588a44d1d5a9f221051f Mon Sep 17 00:00:00 2001 From: "Abbas, Mohamed" Date: Fri, 5 Dec 2008 07:58:37 -0800 Subject: iwl3945: Fix rate scale for B-mode connection This patch make sure we use only CCK rate for B only network. For 3945 driver, it sets REPLY_RATE_SCALE command every time we connect to a new network. In this command we set for every rate the number of try and next rate. The problem mac80211 reports same mode for both B and G mode as IEEE80211_BAND_2GHZ which will cause using invalid rate other than CCK in B only network. THis patch on association will examine sta valid rate on association, if no OFDM rate in valid available rates it considers it as B only mode so we can set REPLY_RATE_SCALE command with valid B only network and only choose CCK rate in rate scaling. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 12 ++++++--- drivers/net/wireless/iwlwifi/iwl-3945.c | 41 ++++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 ++ 3 files changed, 39 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index b03dd06..047317f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -335,10 +335,11 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, } -static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, +static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { struct iwl3945_rs_sta *rs_sta = priv_sta; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; int i; IWL_DEBUG_RATE("enter\n"); @@ -348,16 +349,21 @@ static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { + for (i = sband->n_bitrates - 1; i >= 0; i--) { if (sta->supp_rates[sband->band] & (1 << i)) { rs_sta->last_txrate_idx = i; break; } } + priv->sta_supp_rates = sta->supp_rates[sband->band]; /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ - if (sband->band == IEEE80211_BAND_5GHZ) + if (sband->band == IEEE80211_BAND_5GHZ) { rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + priv->sta_supp_rates = priv->sta_supp_rates << + IWL_FIRST_OFDM_RATE; + } + IWL_DEBUG_RATE("leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4e6b715..4e9e592 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -277,12 +277,14 @@ int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate) else if (rate == IWL_RATE_6M_INDEX) next_rate = IWL_RATE_6M_INDEX; break; -/* XXX cannot be invoked in current mac80211 so not a regression - case MODE_IEEE80211B: - if (rate == IWL_RATE_11M_INDEX_TABLE) - next_rate = IWL_RATE_5M_INDEX_TABLE; + case IEEE80211_BAND_2GHZ: + if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) && + iwl3945_is_associated(priv)) { + if (rate == IWL_RATE_11M_INDEX) + next_rate = IWL_RATE_5M_INDEX; + } break; - */ + default: break; } @@ -2378,7 +2380,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0); table[index].try_cnt = priv->retry_rate; prev_index = iwl3945_get_prev_ieee_rate(i); - table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index; + table[index].next_rate_index = + iwl3945_rates[prev_index].table_rs_index; } switch (priv->band) { @@ -2386,11 +2389,14 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) IWL_DEBUG_RATE("Select A mode rate scale\n"); /* If one of the following CCK rates is used, * have it fall back to the 6M OFDM rate */ - for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; + for (i = IWL_RATE_1M_INDEX_TABLE; + i <= IWL_RATE_11M_INDEX_TABLE; i++) + table[i].next_rate_index = + iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; /* Don't fall back to CCK rates */ - table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE; + table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = + IWL_RATE_9M_INDEX_TABLE; /* Don't drop out of OFDM rates */ table[IWL_RATE_6M_INDEX_TABLE].next_rate_index = @@ -2401,11 +2407,20 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) IWL_DEBUG_RATE("Select B/G mode rate scale\n"); /* If an OFDM rate is used, have it fall back to the * 1M CCK rates */ - for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index; - /* CCK shouldn't fall back to OFDM... */ - table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE; + if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) && + iwl3945_is_associated(priv)) { + + index = IWL_FIRST_CCK_RATE; + for (i = IWL_RATE_6M_INDEX_TABLE; + i <= IWL_RATE_54M_INDEX_TABLE; i++) + table[i].next_rate_index = + iwl3945_rates[index].table_rs_index; + + index = IWL_RATE_11M_INDEX_TABLE; + /* CCK shouldn't fall back to OFDM... */ + table[index].next_rate_index = IWL_RATE_5M_INDEX_TABLE; + } break; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 5c2c15e..d7d13a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -810,6 +810,8 @@ struct iwl3945_priv { u16 active_rate; u16 active_rate_basic; + u32 sta_supp_rates; + u8 call_post_assoc_from_beacon; /* Rate scaling data */ s8 data_retry_limit; -- cgit v1.1 From f056658bb9c3085d5ec52fbdd45b38d55b899cc9 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Fri, 5 Dec 2008 07:58:38 -0800 Subject: iwlwifi: fix time interval misuse in iwl_poll_{direct_}bit The patch fixes the misuse of microsecond with millisecond in the polling mechanism of the iwlwifi driver. The impact of this problem is the unacceptable latency for the whole system (especially during bringing down the wlan interface). Signed-off-by: Zhu Yi Acked-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-io.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 7dea155..2f74943 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -93,7 +93,7 @@ static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr, do { if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask)) return i; - mdelay(10); + udelay(10); i += 10; } while (i < timeout); @@ -276,7 +276,7 @@ static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv, do { if ((_iwl3945_read_direct32(priv, addr) & mask) == mask) return i; - mdelay(10); + udelay(10); i += 10; } while (i < timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index bc10435..a5c489af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -95,7 +95,7 @@ static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, do { if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) return i; - mdelay(10); + udelay(10); i += 10; } while (i < timeout); @@ -277,7 +277,7 @@ static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, do { if ((_iwl_read_direct32(priv, addr) & mask) == mask) return i; - mdelay(10); + udelay(10); i += 10; } while (i < timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 18d6cf6..9d7e45f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -628,7 +628,7 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), - 200); + 1000); } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.1 From 42802d71dd14dd0e435a8da59d817d0c6f8a2866 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Fri, 5 Dec 2008 07:58:39 -0800 Subject: iwlwifi: fix "MAC in deep sleep" error This patch fixes the misue of CSR_GP_CNTRL with CSR_RESET address in polling the CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY bit in iwl4965_apm_reset(). This causes "MAC in deep sleep" error sometimes. The patch also fixes the timeout value and the iwl_poll_bit() return value check. Signed-off-by: Zhu Yi Acked-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 87c7bb0..c961e2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -482,11 +482,11 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_bit(priv, CSR_RESET, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret) + if (ret < 0) goto out; udelay(10); -- cgit v1.1 From 73d7b5acc461bdc99e0135779d15e1874c6e00a6 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Fri, 5 Dec 2008 07:58:40 -0800 Subject: iwlwifi: iwl_poll_{direct_}bit cleanup The patch merges implementation of iwl_poll_bit() and iwl_poll_direct_bit() by letting the latter be a special case of the former. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 1 + drivers/net/wireless/iwlwifi/iwl-3945-io.h | 11 +---------- drivers/net/wireless/iwlwifi/iwl-3945.c | 16 +++++++--------- drivers/net/wireless/iwlwifi/iwl-4965.c | 16 ++++++---------- drivers/net/wireless/iwlwifi/iwl-5000.c | 13 +++++-------- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 7 +++---- drivers/net/wireless/iwlwifi/iwl-io.h | 15 +++------------ drivers/net/wireless/iwlwifi/iwl-rx.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ++--- 9 files changed, 30 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 644bd9e..f0f7dc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -321,6 +321,7 @@ struct iwl3945_eeprom { /* RSSR */ #define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) #define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) +#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) /* TCSR */ #define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) #define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 2f74943..994f8ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -271,16 +271,7 @@ static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv, static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv, u32 addr, u32 mask, int timeout) { - int i = 0; - - do { - if ((_iwl3945_read_direct32(priv, addr) & mask) == mask) - return i; - udelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl3945_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWL3945_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4e9e592..1c35fa8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1103,9 +1103,8 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + rc = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); @@ -1286,8 +1285,7 @@ int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { - rc = iwl3945_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + rc = iwl3945_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); @@ -1312,9 +1310,8 @@ int iwl3945_hw_nic_reset(struct iwl3945_priv *priv) iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); rc = iwl3945_grab_nic_access(priv); if (!rc) { @@ -2311,7 +2308,8 @@ int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv) } iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0); - rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); + rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c961e2c..324825e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -352,9 +352,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out; @@ -436,9 +435,8 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + ret = iwl_poll_direct_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (ret < 0) goto out; @@ -482,10 +480,8 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 438e4bd..1b82742 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -81,8 +81,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + ret = iwl_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (ret < 0) goto out; @@ -120,9 +119,8 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); return ret; @@ -189,9 +187,8 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 792a3c1..ae04327 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -169,10 +169,9 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); + ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); if (ret >= 0) { IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", count+1); diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index a5c489af..c56dc21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -269,19 +269,10 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv, } } -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) +static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, + u32 mask, int timeout) { - int i = 0; - - do { - if ((_iwl_read_direct32(priv, addr) & mask) == mask) - return i; - udelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWLWIFI_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6dd16c7..1938e6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -467,10 +467,8 @@ int iwl_rxq_stop(struct iwl_priv *priv) /* stop Rx DMA */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, - (1 << 24), 1000); - if (ret < 0) - IWL_ERROR("Can't stop Rx DMA.\n"); + iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 1a411c2..f7fa68b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7925,9 +7925,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + err = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (err < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out_remove_sysfs; -- cgit v1.1 From a8ec42c1431e8a43f910fb27af4882416cf5d6b1 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Fri, 5 Dec 2008 07:58:41 -0800 Subject: iwlwifi: use rmb/wmb to protect indirect mmio operation This patch protects iwlwifi indirect mmio operations with rmb() and wmb(). It makes sure CPU reordering won't affect our indirect mmio access. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 5 +++++ drivers/net/wireless/iwlwifi/iwl-io.h | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 994f8ba..d381b82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -298,6 +298,7 @@ static inline int __iwl3945_poll_direct_bit(const char *f, u32 l, static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg) { _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } #ifdef CONFIG_IWL3945_DEBUG @@ -319,6 +320,7 @@ static inline void _iwl3945_write_prph(struct iwl3945_priv *priv, { _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } #ifdef CONFIG_IWL3945_DEBUG @@ -380,12 +382,14 @@ static inline void iwl3945_clear_bits_prph(struct iwl3945_priv static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT); } static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); } @@ -393,6 +397,7 @@ static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 add u32 len, u32 *values) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); for (; 0 < len; len -= sizeof(u32), values++) iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index c56dc21..10ca032 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -299,6 +299,7 @@ static inline int __iwl_poll_direct_bit(const char *f, u32 l, static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) { _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -321,6 +322,7 @@ static inline void _iwl_write_prph(struct iwl_priv *priv, { _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -383,12 +385,14 @@ static inline void iwl_clear_bits_prph(struct iwl_priv static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) { iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); } static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) { iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); } @@ -396,6 +400,7 @@ static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, u32 len, u32 *values) { iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); for (; 0 < len; len -= sizeof(u32), values++) iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); } -- cgit v1.1 From 61ff84a4ce6451c9a0b675d355e0580e53628801 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Fri, 5 Dec 2008 18:16:21 +0200 Subject: iwlwifi: cleanup (remove pm_state) This patches removes unused variable (pm_state) from iwl-dev.h and from iwl-3945.h. (wireless-testing tree) Signed-off-by: Rami Rosen Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 3 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index d7d13a9..05640a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -908,9 +908,6 @@ struct iwl3945_priv { s8 user_txpower_limit; s8 max_channel_txpower_limit; -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif #ifdef CONFIG_IWL3945_DEBUG /* debugging info */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9d678d1..25e8714 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -994,9 +994,6 @@ struct iwl_priv { s8 tx_power_user_lmt; s8 tx_power_channel_lmt; -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ -- cgit v1.1 From 3fbb9d95a96c6a03f2e484bb1665d089412640dc Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 5 Dec 2008 20:42:45 +0200 Subject: ath9k: Free Beacon skbs in AP mode Fix a memory leak where AP mode did not free transmitted Beacon frame skbs. Signed-off-by: Jouni Malinen Acked-by: Pat Erley Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 507299b..d874223 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -167,6 +167,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) pci_unmap_single(sc->pdev, bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); } skb = ieee80211_beacon_get(sc->hw, vif); -- cgit v1.1 From 6b3aa6ab787fe545c58554b7ce5c94de53526b83 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 5 Dec 2008 20:43:27 +0200 Subject: ath9k: Disable staggered Beacon frame scheduling It looks like there are some issues in the current ath9k version as far as staggered Beacon frame scheduling is concerned. This results in Beacon frame timestamp being off by 25 milliseconds or so which can cause issues with multicast power save buffering in AP mode. Some client stations fail to receive multicast frames when there is this large an offset between TBTT and actual Beacon transmission time. Since ath9k does not yet support multiple BSSes anyway, the staggered Beacon frame scheduling is just increasing the number of interrupts at this point. The easiest fix for the timestamp offset is to disable staggered Beacon frames for now. We need to redesign beacon.c anyway when adding multi-BSS support with mac80211 since the existing code depends on different mechanism for Beacon frame transmission. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index a500d17..ca8ed7d 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -489,7 +489,7 @@ struct ath_vap { * number of beacon intervals, the game's up. */ #define BSTUCK_THRESH (9 * ATH_BCBUF) -#define ATH_BCBUF 4 +#define ATH_BCBUF 1 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) -- cgit v1.1 From 40990ec01fcca0b86a19c13a5d3deb77da1913a7 Mon Sep 17 00:00:00 2001 From: Sujith Date: Sun, 7 Dec 2008 21:41:37 +0530 Subject: ath9k: Fix bug in rate table management The proper rate table wouldn't be used if a disassoc happens and a new attempt is made to associate using wpa_supplicant. This patch fixes it by storing the rate table to be used on association. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 + drivers/net/wireless/ath9k/rc.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index ca8ed7d..726d0a3 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -702,6 +702,7 @@ struct ath_softc { /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + struct ath_rate_table *cur_rate_table; u8 sc_protrix; /* Channel, Band */ diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 76acd2b..8eec667 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -817,7 +817,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, struct ath_rate_table *rate_table; struct ieee80211_tx_rate *rates = tx_info->control.rates; - rate_table = sc->hw_rate_table[sc->sc_curmode]; + rate_table = sc->cur_rate_table; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1, is_probe, is_retry); nrix = rix; @@ -877,7 +877,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { - u8 dot11rate = rate_table->info[rix].dot11rate; + 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) || @@ -1094,7 +1094,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, int rate; u8 last_per; bool state_change = false; - struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; + struct ath_rate_table *rate_table = sc->cur_rate_table; int size = ath_rc_priv->rate_table_size; if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) @@ -1254,7 +1254,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, u8 flags; u32 i = 0, rix; - rate_table = sc->hw_rate_table[sc->sc_curmode]; + rate_table = sc->cur_rate_table; /* * If the first rate is not the final index, there @@ -1432,6 +1432,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + sc->cur_rate_table = rate_table; } /* Rate Control callbacks */ -- cgit v1.1 From 3706de6f58962ba74c18eb4cb1ebe034ff723037 Mon Sep 17 00:00:00 2001 From: Sujith Date: Sun, 7 Dec 2008 21:42:10 +0530 Subject: ath9k: Maintain rate table choice after association A scan run after association would change sc_curmode which is used to get the current rate table. This patch fixes it by removing sc_curmode and setting the rate table in usage in cur_rate_table on association. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 2 +- drivers/net/wireless/ath9k/core.h | 1 - drivers/net/wireless/ath9k/main.c | 3 ++- drivers/net/wireless/ath9k/rc.c | 9 ++++----- drivers/net/wireless/ath9k/recv.c | 2 +- drivers/net/wireless/ath9k/xmit.c | 8 ++++---- 6 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index d874223..9e5c0c0 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -106,7 +106,7 @@ static void ath_beacon_setup(struct ath_softc *sc, * XXX everything at min xmit rate */ rix = 0; - rt = sc->hw_rate_table[sc->sc_curmode]; + rt = sc->cur_rate_table; rate = rt->info[rix].ratecode; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= rt->info[rix].short_preamble; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 726d0a3..23844e0 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -646,7 +646,6 @@ struct ath_softc { u8 sc_tx_chainmask; u8 sc_rx_chainmask; enum ath9k_int sc_imask; - enum wireless_mode sc_curmode; enum PROT_MODE sc_protmode; u8 sc_nbcnvaps; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 26c47577..ade92d5 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -60,7 +60,8 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz) static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { - sc->sc_curmode = mode; + if (!sc->sc_curaid) + sc->cur_rate_table = sc->hw_rate_table[mode]; /* * All protection frames are transmited at 2Mb/s for * 11g, otherwise at 1Mb/s. diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 8eec667..0ae5988 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -874,9 +874,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, * So, set fourth rate in series to be same as third one for * above conditions. */ - if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { + if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) && + (sc->hw->conf.ht.enabled)) { u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && @@ -1354,8 +1353,8 @@ static void ath_rc_init(struct ath_softc *sc, sta->ht_cap.ht_supported, is_cw_40); } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { - /* sc_curmode would be set on init through config() */ - rate_table = sc->hw_rate_table[sc->sc_curmode]; + /* cur_rate_table would be set on init through config() */ + rate_table = sc->cur_rate_table; } if (!rate_table) { diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 7a45546..b182ef5 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -148,7 +148,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, struct ieee80211_rx_status *rx_status, bool *decrypt_error, struct ath_softc *sc) { - struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; + struct ath_rate_table *rate_table = sc->cur_rate_table; struct ieee80211_hdr *hdr; int ratekbps, rix; u8 ratecode; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 9de27c6..353b7ed 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -493,7 +493,7 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, int width, int half_gi, bool shortPreamble) { - struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; + struct ath_rate_table *rate_table = sc->cur_rate_table; u32 nbits, nsymbits, duration, nsymbols; u8 rc; int streams, pktlen; @@ -557,7 +557,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) } /* get the cix for the lowest valid rix */ - rt = sc->hw_rate_table[sc->sc_curmode]; + rt = sc->cur_rate_table; for (i = 3; i >= 0; i--) { if (rates[i].count && (rates[i].idx >= 0)) { rix = rates[i].idx; @@ -1240,7 +1240,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) { - struct ath_rate_table *rate_table = sc->hw_rate_table[sc->sc_curmode]; + struct ath_rate_table *rate_table = sc->cur_rate_table; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -1308,7 +1308,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *bf, u16 frmlen) { - struct ath_rate_table *rt = sc->hw_rate_table[sc->sc_curmode]; + struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; -- cgit v1.1 From 817e11de2d3392041a70c80a6d5b353ad210f276 Mon Sep 17 00:00:00 2001 From: Sujith Date: Sun, 7 Dec 2008 21:42:44 +0530 Subject: ath9k: Add a debugfs file to show interrupt statistics Location: ath9k//interrupt Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 55 ++++++++++++++++++++ drivers/net/wireless/ath9k/debug.c | 102 +++++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath9k/main.c | 2 + 3 files changed, 159 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 23844e0..9abdbd8 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -88,16 +88,66 @@ enum ATH_DEBUG { #ifdef CONFIG_ATH9K_DEBUG +/** + * struct ath_interrupt_stats - Contains statistics about interrupts + * @total: Total no. of interrupts generated so far + * @rxok: RX with no errors + * @rxeol: RX with no more RXDESC available + * @rxorn: RX FIFO overrun + * @txok: TX completed at the requested rate + * @txurn: TX FIFO underrun + * @mib: MIB regs reaching its threshold + * @rxphyerr: RX with phy errors + * @rx_keycache_miss: RX with key cache misses + * @swba: Software Beacon Alert + * @bmiss: Beacon Miss + * @bnr: Beacon Not Ready + * @cst: Carrier Sense TImeout + * @gtt: Global TX Timeout + * @tim: RX beacon TIM occurrence + * @cabend: RX End of CAB traffic + * @dtimsync: DTIM sync lossage + * @dtim: RX Beacon with DTIM + */ +struct ath_interrupt_stats { + u32 total; + u32 rxok; + u32 rxeol; + u32 rxorn; + u32 txok; + u32 txeol; + u32 txurn; + u32 mib; + u32 rxphyerr; + u32 rx_keycache_miss; + u32 swba; + u32 bmiss; + u32 bnr; + u32 cst; + u32 gtt; + u32 tim; + u32 cabend; + u32 dtimsync; + u32 dtim; +}; + +struct ath_stats { + struct ath_interrupt_stats istats; +}; + struct ath9k_debug { int debug_mask; struct dentry *debugfs_root; struct dentry *debugfs_phy; struct dentry *debugfs_dma; + struct dentry *debugfs_interrupt; + struct ath_stats stats; }; void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); int ath9k_init_debug(struct ath_softc *sc); void ath9k_exit_debug(struct ath_softc *sc); +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); #else @@ -115,6 +165,11 @@ static inline void ath9k_exit_debug(struct ath_softc *sc) { } +static inline void ath_debug_stat_interrupt(struct ath_softc *sc, + enum ath9k_int status) +{ +} + #endif /* CONFIG_ATH9K_DEBUG */ struct ath_config { diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index da52812..a80ed57 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c @@ -128,6 +128,100 @@ static const struct file_operations fops_dma = { .owner = THIS_MODULE }; + +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) +{ + if (status) + sc->sc_debug.stats.istats.total++; + if (status & ATH9K_INT_RX) + sc->sc_debug.stats.istats.rxok++; + if (status & ATH9K_INT_RXEOL) + sc->sc_debug.stats.istats.rxeol++; + if (status & ATH9K_INT_RXORN) + sc->sc_debug.stats.istats.rxorn++; + if (status & ATH9K_INT_TX) + sc->sc_debug.stats.istats.txok++; + if (status & ATH9K_INT_TXURN) + sc->sc_debug.stats.istats.txurn++; + if (status & ATH9K_INT_MIB) + sc->sc_debug.stats.istats.mib++; + if (status & ATH9K_INT_RXPHY) + sc->sc_debug.stats.istats.rxphyerr++; + if (status & ATH9K_INT_RXKCM) + sc->sc_debug.stats.istats.rx_keycache_miss++; + if (status & ATH9K_INT_SWBA) + sc->sc_debug.stats.istats.swba++; + if (status & ATH9K_INT_BMISS) + sc->sc_debug.stats.istats.bmiss++; + if (status & ATH9K_INT_BNR) + sc->sc_debug.stats.istats.bnr++; + if (status & ATH9K_INT_CST) + sc->sc_debug.stats.istats.cst++; + if (status & ATH9K_INT_GTT) + sc->sc_debug.stats.istats.gtt++; + if (status & ATH9K_INT_TIM) + sc->sc_debug.stats.istats.tim++; + if (status & ATH9K_INT_CABEND) + sc->sc_debug.stats.istats.cabend++; + if (status & ATH9K_INT_DTIMSYNC) + sc->sc_debug.stats.istats.dtimsync++; + if (status & ATH9K_INT_DTIM) + sc->sc_debug.stats.istats.dtim++; +} + +static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_interrupt = { + .read = read_file_interrupt, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + int ath9k_init_debug(struct ath_softc *sc) { sc->sc_debug.debug_mask = ath9k_debug; @@ -146,6 +240,13 @@ int ath9k_init_debug(struct ath_softc *sc) if (!sc->sc_debug.debugfs_dma) goto err; + sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt", + S_IRUGO, + sc->sc_debug.debugfs_phy, + sc, &fops_interrupt); + if (!sc->sc_debug.debugfs_interrupt) + goto err; + return 0; err: ath9k_exit_debug(sc); @@ -154,6 +255,7 @@ err: void ath9k_exit_debug(struct ath_softc *sc) { + debugfs_remove(sc->sc_debug.debugfs_interrupt); debugfs_remove(sc->sc_debug.debugfs_dma); debugfs_remove(sc->sc_debug.debugfs_phy); debugfs_remove(sc->sc_debug.debugfs_root); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index ade92d5..272f806 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -598,6 +598,8 @@ static irqreturn_t ath_isr(int irq, void *dev) } } while (0); + ath_debug_stat_interrupt(sc, status); + if (sched) { /* turn off every interrupt except SWBA */ ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); -- cgit v1.1 From f6688cd8af6260ad4717ce45d2a614633fcf5540 Mon Sep 17 00:00:00 2001 From: Sujith Date: Sun, 7 Dec 2008 21:43:10 +0530 Subject: ath9k: Remove remaining occurrences of CONFIG_SLOW_ANT_DIV Slow Antenna Diversity has been removed, these are remnants of the old code. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 3 --- drivers/net/wireless/ath9k/hw.c | 13 ++----------- drivers/net/wireless/ath9k/main.c | 8 -------- 3 files changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 9abdbd8..0e3c225 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -715,9 +715,6 @@ struct ath_softc { enum ath9k_ht_extprotspacing sc_ht_extprotspacing; enum ath9k_ht_macmode tx_chan_width; -#ifdef CONFIG_SLOW_ANT_DIV - struct ath_antdiv sc_antdiv; -#endif enum { OK, /* no change needed */ UPDATE, /* update pending */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 668865d..2176fa8 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -640,10 +640,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, struct ath_hal_5416 *ahp; struct ath_hal *ah; int ecode; -#ifndef CONFIG_SLOW_ANT_DIV - u32 i; - u32 j; -#endif + u32 i, j; ahp = ath9k_hw_newstate(devid, sc, mem, status); if (ahp == NULL) @@ -853,7 +850,6 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (AR_SREV_9280_20_OR_LATER(ah)) ath9k_hw_init_txgain_ini(ah); -#ifndef CONFIG_SLOW_ANT_DIV if (ah->ah_devid == AR9280_DEVID_PCI) { for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); @@ -867,7 +863,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } } } -#endif + if (!ath9k_hw_fill_cap_info(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n"); @@ -1294,11 +1290,6 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex); -#ifdef CONFIG_SLOW_ANT_DIV - if (ah->ah_devid == AR9280_DEVID_PCI) - val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, val); -#endif - REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 272f806..44459d7 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1513,11 +1513,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* save MISC configurations */ sc->sc_config.swBeaconProcess = 1; -#ifdef CONFIG_SLOW_ANT_DIV - /* range is 40 - 255, we use something in the middle */ - ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); -#endif - /* setup channels and rates */ sc->sbands[IEEE80211_BAND_2GHZ].channels = @@ -2129,9 +2124,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif /* Stop ANI */ del_timer_sync(&sc->sc_ani.timer); -- cgit v1.1 From 8ee5afbc9d2162f0919dd089023fb690f7cf8134 Mon Sep 17 00:00:00 2001 From: Sujith Date: Sun, 7 Dec 2008 21:43:36 +0530 Subject: ath9k: Merge structures ath_atx, ath_node_aggr with ath_node Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 160 ++++++++++++++++---------------------- drivers/net/wireless/ath9k/xmit.c | 6 +- 2 files changed, 72 insertions(+), 94 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 0e3c225..41a87b9 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -290,18 +290,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* RX / TX */ /***********/ -#define ATH_MAX_ANTENNA 3 -#define ATH_RXBUF 512 -#define WME_NUM_TID 16 - -int ath_startrecv(struct ath_softc *sc); -bool ath_stoprecv(struct ath_softc *sc); -void ath_flushrecv(struct ath_softc *sc); -u32 ath_calcrxfilter(struct ath_softc *sc); -int ath_rx_init(struct ath_softc *sc, int nbufs); -void ath_rx_cleanup(struct ath_softc *sc); -int ath_rx_tasklet(struct ath_softc *sc, int flush); - +#define ATH_MAX_ANTENNA 3 +#define ATH_RXBUF 512 +#define WME_NUM_TID 16 #define ATH_TXBUF 512 #define ATH_TXMAXTRY 13 #define ATH_11N_TXMAXTRY 10 @@ -309,19 +300,61 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush); #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) + #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ WME_AC_VO) - #define WME_AC_BE 0 #define WME_AC_BK 1 #define WME_AC_VI 2 #define WME_AC_VO 3 #define WME_NUM_AC 4 +#define ADDBA_EXCHANGE_ATTEMPTS 10 +#define ATH_AGGR_DELIM_SZ 4 +#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ +/* number of delimiters for encryption padding */ +#define ATH_AGGR_ENCRYPTDELIM 10 +/* minimum h/w qdepth to be sustained to maximize aggregation */ +#define ATH_AGGR_MIN_QDEPTH 2 +#define ATH_AMPDU_SUBFRAME_DEFAULT 32 +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +/* return whether a bit at index _n in bitmap _bm is set + * _sz is the size of the bitmap */ +#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ + ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) + +/* return block-ack bitmap index given sequence and starting sequence */ +#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) + +/* returns delimiter padding required given the packet length */ +#define ATH_AGGR_GET_NDELIM(_len) \ + (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ + (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 4095) < (_bawsz)) + +#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) +#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) +#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) +#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) + +enum ATH_AGGR_STATUS { + ATH_AGGR_DONE, + ATH_AGGR_BAW_CLOSED, + ATH_AGGR_LIMITED, + ATH_AGGR_SHORTPKT, + ATH_AGGR_8K_LIMITED, +}; + struct ath_txq { u32 axq_qnum; /* hardware q number */ u32 *axq_link; /* link ptr in last TX desc */ @@ -331,7 +364,6 @@ struct ath_txq { u32 axq_depth; /* queue depth */ u8 axq_aggr_depth; /* aggregates queued */ u32 axq_totalqueued; /* total ever queued */ - bool stopped; /* Is mac80211 queue stopped ? */ struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/ @@ -377,12 +409,6 @@ struct ath_atx_ac { struct list_head tid_q; /* queue of TIDs with buffers */ }; -/* per dest tx state */ -struct ath_atx { - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; -}; - /* per-frame tx control block */ struct ath_tx_control { struct ath_txq *txq; @@ -408,13 +434,32 @@ struct ath_tx_stat { int rateKbps; int ratecode; int flags; -/* if any of ctl,extn chain rssis are valid */ -#define ATH_TX_CHAIN_RSSI_VALID 0x01 -/* if extn chain rssis are valid */ -#define ATH_TX_RSSI_EXTN_VALID 0x02 u32 airtime; /* time on air per final tx rate */ }; +struct aggr_rifs_param { + int param_max_frames; + int param_max_len; + int param_rl; + int param_al; + struct ath_rc_series *param_rcs; +}; + +struct ath_node { + struct ath_softc *an_sc; + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; + u16 maxampdu; + u8 mpdudensity; +}; + +int ath_startrecv(struct ath_softc *sc); +bool ath_stoprecv(struct ath_softc *sc); +void ath_flushrecv(struct ath_softc *sc); +u32 ath_calcrxfilter(struct ath_softc *sc); +int ath_rx_init(struct ath_softc *sc, int nbufs); +void ath_rx_cleanup(struct ath_softc *sc); +int ath_rx_tasklet(struct ath_softc *sc, int flush); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); @@ -437,73 +482,6 @@ void ath_tx_tasklet(struct ath_softc *sc); u32 ath_txq_depth(struct ath_softc *sc, int qnum); u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); - -/**********************/ -/* Node / Aggregation */ -/**********************/ - -#define ADDBA_EXCHANGE_ATTEMPTS 10 -#define ATH_AGGR_DELIM_SZ 4 -#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ -/* number of delimiters for encryption padding */ -#define ATH_AGGR_ENCRYPTDELIM 10 -/* minimum h/w qdepth to be sustained to maximize aggregation */ -#define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 -#define IEEE80211_SEQ_SEQ_SHIFT 4 -#define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - -/* return whether a bit at index _n in bitmap _bm is set - * _sz is the size of the bitmap */ -#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ - ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) - -/* return block-ack bitmap index given sequence and starting sequence */ -#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) - -/* returns delimiter padding required given the packet length */ -#define ATH_AGGR_GET_NDELIM(_len) \ - (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ - (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) - -#define BAW_WITHIN(_start, _bawsz, _seqno) \ - ((((_seqno) - (_start)) & 4095) < (_bawsz)) - -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) -#define ATH_AN_2_TID(_an, _tidno) (&(_an)->an_aggr.tx.tid[(_tidno)]) - -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, - ATH_AGGR_SHORTPKT, - ATH_AGGR_8K_LIMITED, -}; - -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; - -/* Per-node aggregation state */ -struct ath_node_aggr { - struct ath_atx tx; -}; - -struct ath_node { - struct ath_softc *an_sc; - struct ath_node_aggr an_aggr; - u16 maxampdu; - u8 mpdudensity; -}; - void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 353b7ed..ec359c6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2405,7 +2405,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) /* * Init per tid tx state */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; + for (tidno = 0, tid = &an->tid[tidno]; tidno < WME_NUM_TID; tidno++, tid++) { tid->an = an; @@ -2419,7 +2419,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) INIT_LIST_HEAD(&tid->buf_q); acno = TID_TO_WME_AC(tidno); - tid->ac = &an->an_aggr.tx.ac[acno]; + tid->ac = &an->ac[acno]; /* ADDBA state */ tid->state &= ~AGGR_ADDBA_COMPLETE; @@ -2430,7 +2430,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) /* * Init per ac tx state */ - for (acno = 0, ac = &an->an_aggr.tx.ac[acno]; + for (acno = 0, ac = &an->ac[acno]; acno < WME_NUM_AC; acno++, ac++) { ac->sched = false; INIT_LIST_HEAD(&ac->tid_q); -- cgit v1.1 From 02e90d627c80127933ee56ae0e9bf727fde66105 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 8 Dec 2008 19:43:46 +0530 Subject: ath9k: Adding AR9285 chipset register information. Adding AR9285 register information. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/reg.h | 109 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 60617ae..9fedb49 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -671,7 +671,11 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA 0x4004 +#define AR_WA 0x4004 +#define AR9285_WA_DEFAULT 0x004a05cb +#define AR9280_WA_DEFAULT 0x0040073f +#define AR_WA_DEFAULT 0x0000073f + #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 @@ -738,6 +742,8 @@ #define AR_SREV_REVISION_9280_21 2 #define AR_SREV_VERSION_9285 0xC0 #define AR_SREV_REVISION_9285_10 0 +#define AR_SREV_REVISION_9285_11 1 +#define AR_SREV_REVISION_9285_12 2 #define AR_SREV_9100_OR_LATER(_ah) \ (((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE)) @@ -768,6 +774,16 @@ #define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285)) #define AR_SREV_9285_10_OR_LATER(_ah) \ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9285)) +#define AR_SREV_9285_11(_ah) \ + (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11)) +#define AR_SREV_9285_11_OR_LATER(_ah) \ + (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11))) +#define AR_SREV_9285_12(_ah) \ + (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12)) +#define AR_SREV_9285_12_OR_LATER(_ah) \ + (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12))) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 @@ -1017,6 +1033,97 @@ enum { #define AR_AN_SYNTH9_REFDIVA 0xf8000000 #define AR_AN_SYNTH9_REFDIVA_S 27 +#define AR9285_AN_RF2G1 0x7820 +#define AR9285_AN_RF2G1_ENPACAL 0x00000800 +#define AR9285_AN_RF2G1_ENPACAL_S 11 +#define AR9285_AN_RF2G1_PDPADRV1 0x02000000 +#define AR9285_AN_RF2G1_PDPADRV1_S 25 +#define AR9285_AN_RF2G1_PDPADRV2 0x01000000 +#define AR9285_AN_RF2G1_PDPADRV2_S 24 +#define AR9285_AN_RF2G1_PDPAOUT 0x00800000 +#define AR9285_AN_RF2G1_PDPAOUT_S 23 + + +#define AR9285_AN_RF2G2 0x7824 +#define AR9285_AN_RF2G2_OFFCAL 0x00001000 +#define AR9285_AN_RF2G2_OFFCAL_S 12 + +#define AR9285_AN_RF2G3 0x7828 +#define AR9285_AN_RF2G3_PDVCCOMP 0x02000000 +#define AR9285_AN_RF2G3_PDVCCOMP_S 25 +#define AR9285_AN_RF2G3_OB_0 0x00E00000 +#define AR9285_AN_RF2G3_OB_0_S 21 +#define AR9285_AN_RF2G3_OB_1 0x001C0000 +#define AR9285_AN_RF2G3_OB_1_S 18 +#define AR9285_AN_RF2G3_OB_2 0x00038000 +#define AR9285_AN_RF2G3_OB_2_S 15 +#define AR9285_AN_RF2G3_OB_3 0x00007000 +#define AR9285_AN_RF2G3_OB_3_S 12 +#define AR9285_AN_RF2G3_OB_4 0x00000E00 +#define AR9285_AN_RF2G3_OB_4_S 9 + +#define AR9285_AN_RF2G3_DB1_0 0x000001C0 +#define AR9285_AN_RF2G3_DB1_0_S 6 +#define AR9285_AN_RF2G3_DB1_1 0x00000038 +#define AR9285_AN_RF2G3_DB1_1_S 3 +#define AR9285_AN_RF2G3_DB1_2 0x00000007 +#define AR9285_AN_RF2G3_DB1_2_S 0 +#define AR9285_AN_RF2G4 0x782C +#define AR9285_AN_RF2G4_DB1_3 0xE0000000 +#define AR9285_AN_RF2G4_DB1_3_S 29 +#define AR9285_AN_RF2G4_DB1_4 0x1C000000 +#define AR9285_AN_RF2G4_DB1_4_S 26 + +#define AR9285_AN_RF2G4_DB2_0 0x03800000 +#define AR9285_AN_RF2G4_DB2_0_S 23 +#define AR9285_AN_RF2G4_DB2_1 0x00700000 +#define AR9285_AN_RF2G4_DB2_1_S 20 +#define AR9285_AN_RF2G4_DB2_2 0x000E0000 +#define AR9285_AN_RF2G4_DB2_2_S 17 +#define AR9285_AN_RF2G4_DB2_3 0x0001C000 +#define AR9285_AN_RF2G4_DB2_3_S 14 +#define AR9285_AN_RF2G4_DB2_4 0x00003800 +#define AR9285_AN_RF2G4_DB2_4_S 11 + +#define AR9285_AN_RF2G6 0x7834 +#define AR9285_AN_RF2G6_CCOMP 0x00007800 +#define AR9285_AN_RF2G6_CCOMP_S 11 +#define AR9285_AN_RF2G6_OFFS 0x03f00000 +#define AR9285_AN_RF2G6_OFFS_S 20 + +#define AR9285_AN_RF2G7 0x7838 +#define AR9285_AN_RF2G7_PWDDB 0x00000002 +#define AR9285_AN_RF2G7_PWDDB_S 1 +#define AR9285_AN_RF2G7_PADRVGN2TAB0 0xE0000000 +#define AR9285_AN_RF2G7_PADRVGN2TAB0_S 29 + +#define AR9285_AN_RF2G8 0x783C +#define AR9285_AN_RF2G8_PADRVGN2TAB0 0x0001C000 +#define AR9285_AN_RF2G8_PADRVGN2TAB0_S 14 + + +#define AR9285_AN_RF2G9 0x7840 +#define AR9285_AN_RXTXBB1 0x7854 +#define AR9285_AN_RXTXBB1_PDRXTXBB1 0x00000020 +#define AR9285_AN_RXTXBB1_PDRXTXBB1_S 5 +#define AR9285_AN_RXTXBB1_PDV2I 0x00000080 +#define AR9285_AN_RXTXBB1_PDV2I_S 7 +#define AR9285_AN_RXTXBB1_PDDACIF 0x00000100 +#define AR9285_AN_RXTXBB1_PDDACIF_S 8 +#define AR9285_AN_RXTXBB1_SPARE9 0x00000001 +#define AR9285_AN_RXTXBB1_SPARE9_S 0 + +#define AR9285_AN_TOP2 0x7868 + +#define AR9285_AN_TOP3 0x786c +#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C +#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 +#define AR9285_AN_TOP3_PWDDAC 0x00800000 +#define AR9285_AN_TOP3_PWDDAC_S 23 + +#define AR9285_AN_TOP4 0x7870 +#define AR9285_AN_TOP4_DEFAULT 0x10142c00 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF -- cgit v1.1 From e8fbc99edfe0efa0b42f04587a79a6b3371f961a Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 8 Dec 2008 19:43:47 +0530 Subject: ath9k: Adding initvalues for Atheros AR9285 chipset. This patch adds the initvalues required for AR9285 chipset. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/initvals.h | 1363 +++++++++++++++++++++++++++++++++ 1 file changed, 1363 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h index 1b08b54..f3cfa16 100644 --- a/drivers/net/wireless/ath9k/initvals.h +++ b/drivers/net/wireless/ath9k/initvals.h @@ -3437,3 +3437,1366 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, }; + +/* AR9285 */ +static const u_int32_t ar9285Modes_9285[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x1927b515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0a00 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x39ce739c }, + { 0x0000a27c, 0x050e039c }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x39ce739c }, + { 0x0000a398, 0x0000039c }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96c }, + { 0x00007834, 0x71400086 }, + { 0x00007838, 0xfac68800 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285Modes_9285_1_2[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00000057, 0x00000057, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285_1_2[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def1000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x318c6318 }, + { 0x0000a27c, 0x050c0318 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x318c6318 }, + { 0x0000a398, 0x00000318 }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x318c6318 }, + { 0x0000a3e0, 0x00000318 }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96e }, + { 0x00007834, 0x71400087 }, + { 0x00007838, 0xfac68801 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; -- cgit v1.1 From e7594072a5b918510c937c1ab0acad4e8a931bc7 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 8 Dec 2008 19:43:48 +0530 Subject: ath9k: Adding support for Atheros AR9285 chipset. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 1 + drivers/net/wireless/ath9k/calib.c | 98 ++ drivers/net/wireless/ath9k/eeprom.c | 1980 ++++++++++++++++++++++++++++------- drivers/net/wireless/ath9k/hw.c | 90 +- drivers/net/wireless/ath9k/hw.h | 135 ++- drivers/net/wireless/ath9k/mac.c | 4 +- drivers/net/wireless/ath9k/main.c | 1 + drivers/net/wireless/ath9k/phy.h | 5 + 8 files changed, 1904 insertions(+), 410 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 9520aa0..d278135 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -26,6 +26,7 @@ #define AR9160_DEVID_PCI 0x0027 #define AR9280_DEVID_PCI 0x0029 #define AR9280_DEVID_PCIE 0x002a +#define AR9285_DEVID_PCIE 0x002b #define AR5416_AR9100_DEVID 0x000b diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c index 51c8a3c..3c7454f 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath9k/calib.c @@ -818,6 +818,101 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, return true; } +static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) +{ + + u32 regVal; + int i, offset, offs_6_1, offs_0; + u32 ccomp_org, reg_field; + u32 regList[][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 }, + }; + + if (AR_SREV_9285_11(ah)) { + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + udelay(10); + } + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); + + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); + + for (i = 6; i > 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (19 + i))); + reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); + regVal |= (reg_field << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); + udelay(1); + reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); + offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); + offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); + + offset = (offs_6_1<<1) | offs_0; + offset = offset - 0; + offs_6_1 = offset>>1; + offs_0 = offset & 1; + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + +} + bool ath9k_hw_init_cal(struct ath_hal *ah, struct ath9k_channel *chan) { @@ -835,6 +930,9 @@ bool ath9k_hw_init_cal(struct ath_hal *ah, return false; } + if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + ath9k_hw_9285_pa_cal(ah); + REG_WRITE(ah, AR_PHY_AGC_CONTROL, REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index e180c90..d4e51dd 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -140,61 +140,97 @@ static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data) return ath9k_hw_eeprom_read(ah, off, data); } -static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah) { +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; u16 *eep_data; - int addr, ar5416_eep_start_loc = 0; + int addr, eep_start_loc = 0; + + eep_start_loc = 64; if (!ath9k_hw_use_flash(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "Reading from EEPROM, not flash\n"); - ar5416_eep_start_loc = 256; } - if (AR_SREV_9100(ah)) - ar5416_eep_start_loc = 256; + eep_data = (u16 *)eep; + + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_4K +} + +static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + u16 *eep_data; + int addr, ar5416_eep_start_loc = 0x100; eep_data = (u16 *)eep; - for (addr = 0; addr < sizeof(struct ar5416_eeprom) / sizeof(u16); addr++) { + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, eep_data)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region\n"); return false; } eep_data++; } return true; +#undef SIZE_EEPROM_DEF +} + +bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = { + ath9k_hw_fill_def_eeprom, + ath9k_hw_fill_4k_eeprom +}; + +static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_fill_eeprom[ahp->ah_eep_map](ah); } -static int ath9k_hw_check_eeprom(struct ath_hal *ah) +static int ath9k_hw_check_def_eeprom(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ahp->ah_eeprom.def; u16 *eepdata, temp, magic, magic2; u32 sum = 0, el; bool need_swap = false; int i, addr, size; + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading Magic # failed\n"); + return false; + } + if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading Magic # failed\n"); - return false; - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom); + size = sizeof(struct ar5416_eeprom_def); need_swap = true; eepdata = (u16 *) (&ahp->ah_eeprom); @@ -223,12 +259,12 @@ static int ath9k_hw_check_eeprom(struct ath_hal *ah) need_swap ? "True" : "False"); if (need_swap) - el = swab16(ahp->ah_eeprom.baseEepHeader.length); + el = swab16(ahp->ah_eeprom.def.baseEepHeader.length); else - el = ahp->ah_eeprom.baseEepHeader.length; + el = ahp->ah_eeprom.def.baseEepHeader.length; - if (el > sizeof(struct ar5416_eeprom)) - el = sizeof(struct ar5416_eeprom) / sizeof(u16); + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); else el = el / sizeof(u16); @@ -297,6 +333,145 @@ static int ath9k_hw_check_eeprom(struct ath_hal *ah) return 0; } +static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) +{ +#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = + (struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr; + + + if (!ath9k_hw_use_flash(ah)) { + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *) (&ahp->ah_eeprom); + + for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "0x%04X ", *eepdata); + + if (((addr + 1) % 6) == 0) + DPRINTF(ah->ah_sc, + ATH_DBG_EEPROM, "\n"); + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length); + else + el = ahp->ah_eeprom.map4k.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ahp->ah_eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing \n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER || + ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ar5416_get_eep4k_ver(ahp)); + return -EINVAL; + } + + return 0; +#undef EEPROM_4K_SIZE +} + +int (*ath9k_check_eeprom[]) (struct ath_hal *) = { + ath9k_hw_check_def_eeprom, + ath9k_hw_check_4k_eeprom +}; + +static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_check_eeprom[ahp->ah_eep_map](ah); +} + static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList) @@ -326,33 +501,36 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, return true; } -static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, + struct cal_data_per_freq_4k *pRawDataSet, u8 *bChans, u16 availPiers, u16 tPdGainOverlap, int16_t *pMinCalPower, u16 *pPdGainBoundaries, u8 *pPDADCValues, u16 numXpdGains) { +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); int i, j, k; int16_t ss; u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; int16_t vpdStep; int16_t tmpVal; u16 sizeCurrVpdTable, maxIndex, tgtIndex; bool match; int16_t minDelta = 0; struct chan_centers centers; +#define PD_GAIN_BOUNDARY_DEFAULT 58; ath9k_hw_get_channel_centers(ah, chan, ¢ers); @@ -361,9 +539,10 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, break; } - match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), - bChans, numPiers, &idxL, &idxR); + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); if (match) { for (i = 0; i < numXpdGains; i++) { @@ -372,7 +551,7 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], pRawDataSet[idxL].pwrPdg[i], pRawDataSet[idxL].vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, + AR5416_EEP4K_PD_GAIN_ICEPTS, vpdTableI[i]); } } else { @@ -385,17 +564,17 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, minPwrT4[i] = max(pPwrL[0], pPwrR[0]); maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, + AR5416_EEP4K_PD_GAIN_ICEPTS, vpdTableL[i]); ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, + AR5416_EEP4K_PD_GAIN_ICEPTS, vpdTableR[i]); for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { @@ -458,9 +637,8 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) pPDADCValues[k++] = vpdTableI[i][ss++]; - } vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); @@ -469,8 +647,7 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, if (tgtIndex > maxIndex) { while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + - (ss - maxIndex + 1) * vpdStep)); + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; pPDADCValues[k++] = (u8)((tmpVal > 255) ? 255 : tmpVal); ss++; @@ -478,8 +655,8 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, } } - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; i++; } @@ -489,69 +666,235 @@ static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, } return; +#undef TMP_VAL_VPD_TABLE } -static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, bool isExtTarget) +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) { + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; struct chan_centers centers; - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) && - (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; } - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8)ath9k_hw_interpolate(freq, clo, chi, - powInfo[lowIndex].tPow2x[i], - powInfo[lowIndex + 1].tPow2x[i]); + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); } - } -} + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; -static void ath9k_hw_get_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, bool isHt40Target) + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = + (u8)ath9k_hw_interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static void ath9k_hw_get_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) { struct chan_centers centers; u16 clo, chi; @@ -603,12 +946,12 @@ static void ath9k_hw_get_target_powers(struct ath_hal *ah, static u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz) + bool is2GHz, int num_band_edges) { u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; int i; - for (i = 0; (i < AR5416_NUM_BAND_EDGES) && + for (i = 0; (i < num_band_edges) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { twiceMaxEdgePower = pRdEdgesPower[i].tPower; @@ -629,207 +972,269 @@ static u16 ath9k_hw_get_max_edge_power(u16 freq, return twiceMaxEdgePower; } -int ath9k_hw_set_txpower(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) +static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; - memset(ratesArray, 0, sizeof(ratesArray)); + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); } - if (!ath9k_hw_set_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; } - if (!ath9k_hw_set_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } + numXpdGain = 0; - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } } - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); - i = rate6mb; + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; + regOffset += 4; + } + } + } - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->ah_maxPowerLevel = ratesArray[i]; + *pTxPowerIndexOffset = 0; - return 0; + return true; } -void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) +static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) { - struct modal_eep_header *pModal; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 biaslevel; + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct cal_data_per_freq_4k *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; - if (ah->ah_macVersion != AR_SREV_VERSION_9160) - return; + xpdMask = pEepData->modalHeader.xpdGain; - if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) - return; + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader.pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; + numXpdGain = 0; - ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); - resetFreqBin = FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)); - freqBin = pModal->xpaBiasLvlFreq[0] & 0xff; - biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14); + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; - freqCount++; + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDataset = pEepData->calPierData2G[i]; - while (freqCount < 3) { - if (pModal->xpaBiasLvlFreq[freqCount] == 0x0) - break; + ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); - freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff; - if (resetFreqBin >= freqBin) { - biaslevel = (u8)(pModal->xpaBiasLvlFreq[freqCount] >> 14); - } else { - break; + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; } - freqCount++; } } - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ahp->ah_iniAddac, 7, 1) = - (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; - } else { - INI_RA(&ahp->ah_iniAddac, 6, 1) = - (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel << 6; - } + *pTxPowerIndexOffset = 0; + + return true; } -bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, +bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, - u8 AntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) { +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; - u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; int i; - int8_t twiceLargestAntenna; + int16_t twiceLargestAntenna; struct cal_ctl_data *rep; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { 0, { 0, 0, 0, 0} @@ -841,7 +1246,7 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { 0, {0, 0, 0, 0} }; - u8 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; u16 ctlModesFor11a[] = { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; u16 ctlModesFor11g[] = @@ -851,7 +1256,7 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, u16 numCtlModes, *pCtlMode, ctlMode, freq; struct chan_centers centers; int tx_chainmask; - u8 twiceMinEdgePower; + u16 twiceMinEdgePower; tx_chainmask = ahp->ah_txchainmask; @@ -867,7 +1272,8 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, pEepData->modalHeader [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - twiceLargestAntenna = (int8_t)min(AntennaReduction - twiceLargestAntenna, 0); + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; @@ -882,16 +1288,14 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, case 1: break; case 2: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain; + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; break; case 3: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain; + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; break; } - scaledPower = max(0, (int32_t) scaledPower); + scaledPower = max((u16)0, scaledPower); if (IS_CHAN_2GHZ(chan)) { numCtlModes = ARRAY_SIZE(ctlModesFor11g) - @@ -990,7 +1394,7 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], - IS_CHAN_2GHZ(chan)); + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, " MATCH-EE_IDX %d: ch %d is2 %d " @@ -1021,7 +1425,7 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { targetPowerCck.tPow2x[i] = - min(targetPowerCck.tPow2x[i], + min((u16)targetPowerCck.tPow2x[i], minCtlPower); } break; @@ -1029,7 +1433,7 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, case CTL_11G: for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { targetPowerOfdm.tPow2x[i] = - min(targetPowerOfdm.tPow2x[i], + min((u16)targetPowerOfdm.tPow2x[i], minCtlPower); } break; @@ -1037,24 +1441,26 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, case CTL_2GHT20: for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { targetPowerHt20.tPow2x[i] = - min(targetPowerHt20.tPow2x[i], + min((u16)targetPowerHt20.tPow2x[i], minCtlPower); } break; case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = - min(targetPowerCckExt.tPow2x[0], minCtlPower); + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); break; case CTL_11A_EXT: case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = - min(targetPowerOfdmExt.tPow2x[0], minCtlPower); + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); break; case CTL_5GHT40: case CTL_2GHT40: for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { targetPowerHt40.tPow2x[i] = - min(targetPowerHt40.tPow2x[i], + min((u16)targetPowerHt40.tPow2x[i], minCtlPower); } break; @@ -1101,139 +1507,623 @@ bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, return true; } -bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) +bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *pEepData = &ahp->ah_eeprom; - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_4k *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ahp->ah_txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = max((u16)0, scaledPower); + + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ar5416_get_eep_ver(ahp) == 14 && + ar5416_get_eep_rev(ahp) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && + pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | + SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = + ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains + (tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = + min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + return true; +} + +static int ath9k_hw_def_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +static int ath9k_hw_4k_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +int (*ath9k_set_txpower[]) (struct ath_hal *, + struct ath9k_channel *, + u16, u8, u8, u8) = { + ath9k_hw_def_set_txpower, + ath9k_hw_4k_set_txpower +}; + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl, + twiceAntennaReduction, twiceMaxRegulatoryPower, + powerLimit); +} + +static void ath9k_hw_set_def_addac(struct ath_hal *ah, + struct ath9k_channel *chan) +{ +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + u8 biaslevel; + + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); - numXpdGain = 0; + freqCount++; - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; } } - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; + } +#undef XPA_LVL_FREQ +} - ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, - pRawDataset, pCalBChans, - numPiers, pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); +static void ath9k_hw_set_4k_addac(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + u8 biaslevel; - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16) | - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "PDADC: Chain %d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); + pModal = &eep->modalHeader; - regOffset += 4; - } - } + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ahp->ah_iniAddac, 7, 1) = + (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; } +} - *pTxPowerIndexOffset = 0; +void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { + ath9k_hw_set_def_addac, + ath9k_hw_set_4k_addac +}; - return true; +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + ath9k_set_addac[ahp->ah_eep_map](ah, chan); } + + /* XXX: Clean me up, make me more legible */ -bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, +static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, struct ath9k_channel *chan) { struct modal_eep_header *pModal; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; int i, regChainOffset; u8 txRxAttenLocal; u16 ant_config; @@ -1462,12 +2352,214 @@ bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, return true; } -int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, +static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + int regChainOffset; + u8 txRxAttenLocal; + u16 ant_config = 0; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + + pModal = &eep->modalHeader; + + txRxAttenLocal = 23; + + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + + regChainOffset = 0; + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + } + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version == 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); + } + + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); + + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); + + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Model version is set to 1 \n"); + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } + } + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + return true; +} + +bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *, + struct ath9k_channel *) = { + ath9k_hw_eeprom_set_def_board_values, + ath9k_hw_eeprom_set_4k_board_values +}; + +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan); +} + +static int ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah, struct ath9k_channel *chan, u8 index, u16 *config) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; struct modal_eep_header *pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); struct base_eep_header *pBase = &eep->baseEepHeader; @@ -1492,11 +2584,52 @@ int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, return -EINVAL; } -u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, +static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + + switch (index) { + case 0: + *config = pModal->antCtrlCommon & 0xFFFF; + return 0; + default: + break; + } + + return -EINVAL; +} + +int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *, struct ath9k_channel *, + u8, u16 *) = { + ath9k_hw_get_def_eeprom_antenna_cfg, + ath9k_hw_get_4k_eeprom_antenna_cfg +}; + +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan, + index, config); +} + +u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, enum ieee80211_band freq_band) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; struct modal_eep_header *pModal = &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); struct base_eep_header *pBase = &eep->baseEepHeader; @@ -1511,11 +2644,26 @@ u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, return num_ant_config; } +u8 (*ath9k_get_num_ant_config[])(struct ath_hal *, enum ieee80211_band) = { + ath9k_hw_get_def_num_ant_config, + ath9k_hw_get_4k_num_ant_config +}; + +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band); +} + u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) { +#define EEP_MAP4K_SPURCHAN \ + (ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan) +#define EEP_DEF_SPURCHAN \ + (ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; u16 spur_val = AR_NO_SPUR; DPRINTF(ah->ah_sc, ATH_DBG_ANI, @@ -1531,19 +2679,66 @@ u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: - spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan; + if (ahp->ah_eep_map == EEP_MAP_4KBITS) + spur_val = EEP_MAP4K_SPURCHAN; + else + spur_val = EEP_DEF_SPURCHAN; break; } return spur_val; +#undef EEP_DEF_SPURCHAN +#undef EEP_MAP4K_SPURCHAN } -u32 ath9k_hw_get_eeprom(struct ath_hal *ah, - enum eeprom_param param) +static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + default: + return 0; + } +} + +static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah, + enum eeprom_param param) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; struct modal_eep_header *pModal = eep->modalHeader; struct base_eep_header *pBase = &eep->baseEepHeader; @@ -1592,13 +2787,32 @@ u32 ath9k_hw_get_eeprom(struct ath_hal *ah, } } +u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = { + ath9k_hw_get_eeprom_def, + ath9k_hw_get_eeprom_4k +}; + +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_eeprom[ahp->ah_eep_map](ah, param); +} + int ath9k_hw_eeprom_attach(struct ath_hal *ah) { int status; + struct ath_hal_5416 *ahp = AH5416(ah); if (ath9k_hw_use_flash(ah)) ath9k_hw_flash_map(ah); + if (AR_SREV_9285(ah)) + ahp->ah_eep_map = EEP_MAP_4KBITS; + else + ahp->ah_eep_map = EEP_MAP_DEFAULT; + if (!ath9k_hw_fill_eeprom(ah)) return -EIO; diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 2176fa8..e95dfa0 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -37,7 +37,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type); static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode); static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, + struct ar5416_eeprom_def *pEepData, u32 reg, u32 value); static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); @@ -392,6 +392,8 @@ static const char *ath9k_hw_devname(u16 devid) case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: return "Atheros 9280"; + case AR9285_DEVID_PCIE: + return "Atheros 9285"; } return NULL; @@ -682,7 +684,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->ah_macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) { + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->ah_macVersion, ah->ah_macRev); @@ -733,7 +735,38 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, "This Mac Chip Rev 0x%02x.%x is \n", ah->ah_macVersion, ah->ah_macRev); - if (AR_SREV_9280_20_OR_LATER(ah)) { + if (AR_SREV_9285_12_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2, + ARRAY_SIZE(ar9285Modes_9285_1_2), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2, + ARRAY_SIZE(ar9285Common_9285_1_2), 2); + + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), + 2); + } + } else if (AR_SREV_9285_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285, + ARRAY_SIZE(ar9285Modes_9285), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285, + ARRAY_SIZE(ar9285Common_9285), 2); + + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); + } + } else if (AR_SREV_9280_20_OR_LATER(ah)) { INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, ARRAY_SIZE(ar9280Modes_9280_2), 6); INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, @@ -843,11 +876,11 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, goto bad; /* rxgain table */ - if (AR_SREV_9280_20_OR_LATER(ah)) + if (AR_SREV_9280_20(ah)) ath9k_hw_init_rxgain_ini(ah); /* txgain table */ - if (AR_SREV_9280_20_OR_LATER(ah)) + if (AR_SREV_9280_20(ah)) ath9k_hw_init_txgain_ini(ah); if (ah->ah_devid == AR9280_DEVID_PCI) { @@ -858,7 +891,8 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, u32 val = INI_RA(&ahp->ah_iniModes, i, j); INI_RA(&ahp->ah_iniModes, i, j) = - ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, + ath9k_hw_ini_fixup(ah, + &ahp->ah_eeprom.def, reg, val); } } @@ -1016,8 +1050,6 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) } case 0x1: case 0x2: - if (!AR_SREV_9280(ah)) - break; case 0x7: REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); @@ -1162,12 +1194,10 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, case AR9160_DEVID_PCI: case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: ah = ath9k_hw_do_attach(devid, sc, mem, error); break; default: - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "devid=0x%x not supported.\n", devid); - ah = NULL; *error = -ENXIO; break; } @@ -1189,8 +1219,8 @@ static void ath9k_hw_override_ini(struct ath_hal *ah, REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, +static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, u32 reg, u32 value) { struct base_eep_header *pBase = &(pEepData->baseEepHeader); @@ -1223,6 +1253,18 @@ static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, return value; } +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ahp->ah_eep_map == EEP_MAP_4KBITS) + return value; + else + return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); +} + static int ath9k_hw_process_ini(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -1300,10 +1342,10 @@ static int ath9k_hw_process_ini(struct ath_hal *ah, DO_DELAY(regWrites); } - if (AR_SREV_9280_20_OR_LATER(ah)) + if (AR_SREV_9280(ah)) REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites); - if (AR_SREV_9280_20_OR_LATER(ah)) + if (AR_SREV_9280(ah)) REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites); for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) { @@ -1576,10 +1618,15 @@ static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { u32 phymode; + u32 enableDacFifo = 0; struct ath_hal_5416 *ahp = AH5416(ah); + if (AR_SREV_9285_10_OR_LATER(ah)) + enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & + AR_PHY_FC_ENABLE_DAC_FIFO); + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 - | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; if (IS_CHAN_HT40(chan)) { phymode |= AR_PHY_FC_DYN2040_EN; @@ -2762,11 +2809,14 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) if (ah->ah_config.pcie_waen) { REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); } else { - if (AR_SREV_9280(ah)) - REG_WRITE(ah, AR_WA, 0x0040073f); + if (AR_SREV_9285(ah)) + REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); + else if (AR_SREV_9280(ah)) + REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); else - REG_WRITE(ah, AR_WA, 0x0000073f); + REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); } + } /**********************/ @@ -3317,7 +3367,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) else pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - if (AR_SREV_9280(ah)) + if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 02256c3..a4d5285 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -448,6 +448,17 @@ struct ar5416Stats { #define AR5416_EEP_TXGAIN_ORIGINAL 0 #define AR5416_EEP_TXGAIN_HIGH_POWER 1 +#define AR5416_EEP4K_START_LOC 64 +#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 +#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_CTLS 12 +#define AR5416_EEP4K_NUM_BAND_EDGES 4 +#define AR5416_EEP4K_NUM_PD_GAINS 2 +#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 +#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 +#define AR5416_EEP4K_MAX_CHAINS 1 enum eeprom_param { EEP_NFTHRESH_5, @@ -507,6 +518,25 @@ struct base_eep_header { u8 futureBase_3[25]; } __packed; +struct base_eep_header_4k { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 futureBase[1]; +} __packed; + + struct spur_chan { u16 spurChan; u8 spurRangeLow; @@ -559,11 +589,58 @@ struct modal_eep_header { struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; +struct modal_eep_4k_header { + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + + struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; } __packed; +struct cal_data_per_freq_4k { + u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; +} __packed; + struct cal_target_power_leg { u8 bChannel; u8 tPow2x[4]; @@ -574,6 +651,7 @@ struct cal_target_power_ht { u8 tPow2x[8]; } __packed; + #ifdef __BIG_ENDIAN_BITFIELD struct cal_ctl_edges { u8 bChannel; @@ -588,10 +666,15 @@ struct cal_ctl_edges { struct cal_ctl_data { struct cal_ctl_edges - ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; + ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +} __packed; + +struct cal_ctl_data_4k { + struct cal_ctl_edges + ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; } __packed; -struct ar5416_eeprom { +struct ar5416_eeprom_def { struct base_eep_header baseEepHeader; u8 custData[64]; struct modal_eep_header modalHeader[2]; @@ -620,6 +703,26 @@ struct ar5416_eeprom { u8 padding; } __packed; +struct ar5416_eeprom_4k { + struct base_eep_header_4k baseEepHeader; + u8 custData[20]; + struct modal_eep_4k_header modalHeader; + u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq_4k + calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; + struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; + u8 padding; +} __packed; + struct ar5416IniArray { u32 *ia_array; u32 ia_rows; @@ -687,9 +790,22 @@ struct hal_cal_list { struct hal_cal_list *calNext; }; +/* + * Enum to indentify the eeprom mappings + */ +enum hal_eep_map { + EEP_MAP_DEFAULT = 0x0, + EEP_MAP_4KBITS, + EEP_MAP_MAX +}; + + struct ath_hal_5416 { struct ath_hal ah; - struct ar5416_eeprom ah_eeprom; + union { + struct ar5416_eeprom_def def; + struct ar5416_eeprom_4k map4k; + } ah_eeprom; struct ar5416Stats ah_stats; struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; void __iomem *ah_cal_mem; @@ -813,6 +929,8 @@ struct ath_hal_5416 { struct ar5416IniArray ah_iniModesAdditional; struct ar5416IniArray ah_iniModesRxGain; struct ar5416IniArray ah_iniModesTxGain; + /* To indicate EEPROM mapping used */ + enum hal_eep_map ah_eep_map; }; #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) @@ -854,13 +972,20 @@ struct ath_hal_5416 { (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 #define AR5416_EEPROM_MAX 0xae0 #define ar5416_get_eep_ver(_ahp) \ - (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF) + (((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF) #define ar5416_get_eep_rev(_ahp) \ - (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF) + (((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF) #define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) +/* EEPROM 4K bit map definations */ +#define ar5416_get_eep4k_ver(_ahp) \ + (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF) +#define ar5416_get_eep4k_rev(_ahp) \ + (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF) + + #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index a4e9898..5254ea4 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -916,12 +916,12 @@ void ath9k_hw_rxena(struct ath_hal *ah) void ath9k_hw_startpcureceive(struct ath_hal *ah) { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); ath9k_enable_mib_counters(ah); ath9k_ani_reset(ah); + } void ath9k_hw_stoppcurecv(struct ath_hal *ah) diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 44459d7..ebd531e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -34,6 +34,7 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { 0 } }; diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 1470234..3a406a5 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -50,6 +50,9 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_FC_SHORT_GI_40 0x00000080 #define AR_PHY_FC_WALSH 0x00000100 #define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 +#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 + +#define AR_PHY_TEST2 0x9808 #define AR_PHY_TIMING2 0x9810 #define AR_PHY_TIMING3 0x9814 @@ -100,6 +103,8 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF #define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 +#define AR_PHY_TSTDAC_CONST 0x983c + #define AR_PHY_SETTLING 0x9844 #define AR_PHY_SETTLING_SWITCH 0x00003F80 #define AR_PHY_SETTLING_SWITCH_S 7 -- cgit v1.1 From 2df1bff4c5cd0b28e06e4defc3f5d90618db8d53 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 8 Dec 2008 19:43:49 +0530 Subject: ath9k: Incorrect band enum causes invalid antenna configuration. It's a regression from the patch titled "ath9k: Use mac80211's band macros and remove enum hal_freq_band". MAC80211 band macros can't be mapped directly with our hal band enum. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/eeprom.c | 2 +- drivers/net/wireless/ath9k/hw.c | 4 ++-- drivers/net/wireless/ath9k/hw.h | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index d4e51dd..14f8d40 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -2631,7 +2631,7 @@ u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; struct modal_eep_header *pModal = - &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); struct base_eep_header *pBase = &eep->baseEepHeader; u8 num_ant_config; diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index e95dfa0..58f94c3 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -3387,9 +3387,9 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah) pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; pCap->num_antcfg_5ghz = - ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_5GHZ); + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); pCap->num_antcfg_2ghz = - ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_2GHZ); + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); return true; } diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index a4d5285..91d8f594 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -495,6 +495,11 @@ enum ar5416_rates { Ar5416RateSize }; +enum ath9k_hal_freq_band { + ATH9K_HAL_FREQ_BAND_5GHZ = 0, + ATH9K_HAL_FREQ_BAND_2GHZ = 1 +}; + struct base_eep_header { u16 length; u16 checksum; -- cgit v1.1 From 8aa15e1506bb0b6b643be12baf1f2d4d2f115931 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 8 Dec 2008 19:43:50 +0530 Subject: ath9k: avoid rx frames with corrupted descriptor. Setting RX_ABORT/RX_DIS after MAC reset and clearing RX_ABORT/RX_DIS after enbling RXE/RXDP to avoid rx frames with corrupted descriptor status. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 8 ++++++++ drivers/net/wireless/ath9k/mac.c | 3 +-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 58f94c3..34474ed 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -1212,6 +1212,14 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, static void ath9k_hw_override_ini(struct ath_hal *ah, struct ath9k_channel *chan) { + /* + * Set the RX_ABORT and RX_DIS and clear if off only after + * RXE is set for MAC. This prevents frames with corrupted + * descriptor status. + */ + REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + if (!AR_SREV_5416_V20_OR_LATER(ah) || AR_SREV_9280_10_OR_LATER(ah)) return; diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index 5254ea4..af32d09 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c @@ -916,12 +916,11 @@ void ath9k_hw_rxena(struct ath_hal *ah) void ath9k_hw_startpcureceive(struct ath_hal *ah) { - REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - ath9k_enable_mib_counters(ah); ath9k_ani_reset(ah); + REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); } void ath9k_hw_stoppcurecv(struct ath_hal *ah) -- cgit v1.1 From 21a49fc674afd00db6de2f729f8c8e4fab2f1bdf Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 9 Dec 2008 08:37:28 +0200 Subject: iwlwifi: fix build error (iwl-rx.c). This patch adds #ifdef CONFIG_IWLWIFI_DEBUG in iwl_rx_reply_rx() method in iwlwifi/iwl-rx.c) to avoid build error caused by "iwlwifi: implement iwl_debug_report_frame for iwlagn". Signed-off-by: Rami Rosen Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 1938e6d..2a008b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1071,9 +1071,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; /* Set "1" to report good data frames in groups of 100 */ +#ifdef CONFIG_IWLWIFI_DEBUG if (unlikely(priv->debug_level & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); - +#endif IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); -- cgit v1.1 From e4f2a3458f451d5fb6aa55aac6aaadcf220d0da1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Dec 2008 12:26:14 +0100 Subject: ath9k: remove fragmentation workaround again Looking at the RC algorithm this is no longer necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index ebd531e..9455a69 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -2487,11 +2487,6 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, return ret; } -static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value) -{ - return -EOPNOTSUPP; -} - static struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2508,7 +2503,6 @@ static struct ieee80211_ops ath9k_ops = { .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, .ampdu_action = ath9k_ampdu_action, - .set_frag_threshold = ath9k_no_fragmentation, }; static struct { -- cgit v1.1 From a07d3619faeea3f540dd55f86685136f8928b4ad Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 9 Dec 2008 17:23:33 +0530 Subject: ath9k: BH shouldn't be enabled when hardirqs are disabled. ath_tx_complete_buf uses a BH version of spinlock and so releasing the lock enables BH which is incorrect when called from sta_notify callback as MAC80211 disables hardirqs before the driver callback is called. As ath_tx_complete_buf is shared between user and softirq context using normal spinlock may not be appropriate. Though the proper fix would be to cleanup the context properly in the driver code, this would be an interim fix to avoid kernel warning. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index ec359c6..e2e847d 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -310,6 +310,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, { struct sk_buff *skb = bf->bf_mpdu; struct ath_xmit_status tx_status; + unsigned long flags; /* * Set retry information. @@ -340,9 +341,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, /* * Return the list of ath_buf of this mpdu to free queue */ - spin_lock_bh(&sc->sc_txbuflock); + spin_lock_irqsave(&sc->sc_txbuflock, flags); list_splice_tail_init(bf_q, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_unlock_irqrestore(&sc->sc_txbuflock, flags); } /* -- cgit v1.1 From dd397dc9dddfa2149a1bbc9e52ac7d5630737cec Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 15:14:37 +0100 Subject: p54usb: rewriting rx/tx routines to make use of usb_anchor's facilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alan Stern found several flaws in p54usb's implementation and annotated: "usb_kill_urb() and similar routines do not expect an URB's completion routine to deallocate it.  This is almost obvious -- if the URB is deallocated before the completion routine returns then there's no way for usb_kill_urb to detect when the URB actually is complete." This patch addresses all known limitations in the old implementation and fixes khub's "use-after-freed" hang, when SLUB debug's poisoning option is enabled. Signed-off-by: Christian Lamparter Cc: stable@kernel.org Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 151 +++++++++++++++++++++++++------------- drivers/net/wireless/p54/p54usb.h | 1 + 2 files changed, 102 insertions(+), 50 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 2dd3cd4..c2789e5 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -86,13 +86,13 @@ static void p54u_rx_cb(struct urb *urb) struct ieee80211_hw *dev = info->dev; struct p54u_priv *priv = dev->priv; + skb_unlink(skb, &priv->rx_queue); + if (unlikely(urb->status)) { - info->urb = NULL; - usb_free_urb(urb); + dev_kfree_skb_irq(skb); return; } - skb_unlink(skb, &priv->rx_queue); skb_put(skb, urb->actual_length); if (priv->hw_type == P54U_NET2280) @@ -105,7 +105,6 @@ static void p54u_rx_cb(struct urb *urb) if (p54_rx(dev, skb)) { skb = dev_alloc_skb(priv->common.rx_mtu + 32); if (unlikely(!skb)) { - usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } @@ -115,7 +114,6 @@ static void p54u_rx_cb(struct urb *urb) info->dev = dev; urb->transfer_buffer = skb_tail_pointer(skb); urb->context = skb; - skb_queue_tail(&priv->rx_queue, skb); } else { if (priv->hw_type == P54U_NET2280) skb_push(skb, priv->common.tx_hdr_len); @@ -130,11 +128,14 @@ static void p54u_rx_cb(struct urb *urb) WARN_ON(1); urb->transfer_buffer = skb_tail_pointer(skb); } - - skb_queue_tail(&priv->rx_queue, skb); } - - usb_submit_urb(urb, GFP_ATOMIC); + skb_queue_tail(&priv->rx_queue, skb); + usb_anchor_urb(urb, &priv->submitted); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(urb); + dev_kfree_skb_irq(skb); + } } static void p54u_tx_reuse_skb_cb(struct urb *urb) @@ -144,18 +145,6 @@ static void p54u_tx_reuse_skb_cb(struct urb *urb) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv; skb_pull(skb, priv->common.tx_hdr_len); - usb_free_urb(urb); -} - -static void p54u_tx_cb(struct urb *urb) -{ - usb_free_urb(urb); -} - -static void p54u_tx_free_cb(struct urb *urb) -{ - kfree(urb->transfer_buffer); - usb_free_urb(urb); } static void p54u_tx_free_skb_cb(struct urb *urb) @@ -165,25 +154,36 @@ static void p54u_tx_free_skb_cb(struct urb *urb) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); p54_free_skb(dev, skb); - usb_free_urb(urb); +} + +static void p54u_tx_dummy_cb(struct urb *urb) { } + +static void p54u_free_urbs(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + usb_kill_anchored_urbs(&priv->submitted); } static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - struct urb *entry; + struct urb *entry = NULL; struct sk_buff *skb; struct p54u_rx_info *info; + int ret = 0; while (skb_queue_len(&priv->rx_queue) < 32) { skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL); - if (!skb) - break; + if (!skb) { + ret = -ENOMEM; + goto err; + } entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { - kfree_skb(skb); - break; + ret = -ENOMEM; + goto err; } + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), @@ -192,26 +192,25 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); + + usb_anchor_urb(entry, &priv->submitted); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(entry); + goto err; + } + usb_free_urb(entry); + entry = NULL; } return 0; -} -static void p54u_free_urbs(struct ieee80211_hw *dev) -{ - struct p54u_priv *priv = dev->priv; - struct p54u_rx_info *info; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct p54u_rx_info *) skb->cb; - if (!info->urb) - continue; - - usb_kill_urb(info->urb); - kfree_skb(skb); - } + err: + usb_free_urb(entry); + kfree_skb(skb); + p54u_free_urbs(dev); + return ret; } static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, @@ -219,6 +218,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; + int err = 0; addr_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!addr_urb) @@ -233,15 +233,31 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(addr_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &((struct p54_hdr *)skb->data)->req_id, 4, - p54u_tx_cb, dev); + p54u_tx_dummy_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), skb->data, skb->len, free_on_tx ? p54u_tx_free_skb_cb : p54u_tx_reuse_skb_cb, skb); - usb_submit_urb(addr_urb, GFP_ATOMIC); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_anchor_urb(addr_urb, &priv->submitted); + err = usb_submit_urb(addr_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(addr_urb); + goto out; + } + + usb_anchor_urb(addr_urb, &priv->submitted); + err = usb_submit_urb(data_urb, GFP_ATOMIC); + if (err) + usb_unanchor_urb(data_urb); + + out: + usb_free_urb(addr_urb); + usb_free_urb(data_urb); + + if (err) + p54_free_skb(dev, skb); } static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) @@ -281,7 +297,13 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, free_on_tx ? p54u_tx_free_skb_cb : p54u_tx_reuse_skb_cb, skb); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_anchor_urb(data_urb, &priv->submitted); + if (usb_submit_urb(data_urb, GFP_ATOMIC)) { + usb_unanchor_urb(data_urb); + skb_pull(skb, sizeof(*hdr)); + p54_free_skb(dev, skb); + } + usb_free_urb(data_urb); } static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, @@ -291,6 +313,7 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, struct urb *int_urb, *data_urb; struct net2280_tx_hdr *hdr; struct net2280_reg_write *reg; + int err = 0; reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) @@ -320,15 +343,42 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), - p54u_tx_free_cb, dev); - usb_submit_urb(int_urb, GFP_ATOMIC); + p54u_tx_dummy_cb, dev); + + /* + * This flag triggers a code path in the USB subsystem that will + * free what's inside the transfer_buffer after the callback routine + * has completed. + */ + int_urb->transfer_flags |= URB_FREE_BUFFER; usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), skb->data, skb->len, free_on_tx ? p54u_tx_free_skb_cb : p54u_tx_reuse_skb_cb, skb); - usb_submit_urb(data_urb, GFP_ATOMIC); + + usb_anchor_urb(int_urb, &priv->submitted); + err = usb_submit_urb(int_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(int_urb); + goto out; + } + + usb_anchor_urb(data_urb, &priv->submitted); + err = usb_submit_urb(data_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(data_urb); + goto out; + } + out: + usb_free_urb(int_urb); + usb_free_urb(data_urb); + + if (err) { + skb_pull(skb, sizeof(*hdr)); + p54_free_skb(dev, skb); + } } static int p54u_write(struct p54u_priv *priv, @@ -885,6 +935,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, goto err_free_dev; skb_queue_head_init(&priv->rx_queue); + init_usb_anchor(&priv->submitted); p54u_open(dev); err = p54_read_eeprom(dev); diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 5b8fe91..54ee738 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -133,6 +133,7 @@ struct p54u_priv { spinlock_t lock; struct sk_buff_head rx_queue; + struct usb_anchor submitted; }; #endif /* P54USB_H */ -- cgit v1.1 From 89fad578a61810b7fdf8edd294890f3c0cde4390 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 16:28:06 +0100 Subject: mac80211: integrate sta_notify_ps cmds into sta_notify This patch replaces the newly introduced sta_notify_ps function, which can be used to notify the driver about every power state transition for all associated stations, by integrating its functionality back into the original sta_notify callback. Signed-off-by: Christian Lamparter Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 4 ++++ drivers/net/wireless/p54/p54common.c | 18 ++++-------------- 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 530648b..fd5a537 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -522,6 +522,10 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, case STA_NOTIFY_REMOVE: hwsim_clear_sta_magic(sta); break; + case STA_NOTIFY_SLEEP: + case STA_NOTIFY_AWAKE: + /* TODO: make good use of these flags */ + break; } } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 89968a5..409ae93 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1051,19 +1051,6 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) return 0; } -static void p54_sta_notify_ps(struct ieee80211_hw *dev, - enum sta_notify_ps_cmd notify_cmd, - struct ieee80211_sta *sta) -{ - switch (notify_cmd) { - case STA_NOTIFY_AWAKE: - p54_sta_unlock(dev, sta->addr); - break; - default: - break; - } -} - static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, enum sta_notify_cmd notify_cmd, struct ieee80211_sta *sta) @@ -1078,6 +1065,10 @@ static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, p54_sta_unlock(dev, sta->addr); break; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ + p54_sta_unlock(dev, sta->addr); + break; default: break; } @@ -2027,7 +2018,6 @@ static const struct ieee80211_ops p54_ops = { .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, .set_tim = p54_set_tim, - .sta_notify_ps = p54_sta_notify_ps, .sta_notify = p54_sta_notify, .set_key = p54_set_key, .config = p54_config, -- cgit v1.1 From d070d8555fbb3b9114c6f861e5cf017ea1720b67 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Tue, 9 Dec 2008 12:32:15 -0500 Subject: airport: remove useless return in a function returning void Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/airport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index ce03a2e..28f1cae 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -279,7 +279,7 @@ init_airport(void) static void __exit exit_airport(void) { - return macio_unregister_driver(&airport_driver); + macio_unregister_driver(&airport_driver); } module_init(init_airport); -- cgit v1.1 From 759ef89fb096c4a6ef078d3cfd5682ac037bd789 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 9 Dec 2008 11:28:58 -0800 Subject: iwlwifi: change email contact information This patch replaces personal emails with hopefully always valid Intel Linux Wireless, which will be routed to a current maintainer Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-commands.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-debug.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-led.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- drivers/net/wireless/iwlwifi/iwl-calib.h | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-csr.h | 2 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 +- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 +- drivers/net/wireless/iwlwifi/iwl-fh.h | 2 +- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlwifi/iwl-helpers.h | 2 +- drivers/net/wireless/iwlwifi/iwl-io.h | 2 +- drivers/net/wireless/iwlwifi/iwl-led.c | 2 +- drivers/net/wireless/iwlwifi/iwl-led.h | 2 +- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-power.h | 2 +- drivers/net/wireless/iwlwifi/iwl-prph.h | 2 +- drivers/net/wireless/iwlwifi/iwl-rfkill.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rfkill.h | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- drivers/net/wireless/iwlwifi/iwl-spectrum.c | 2 +- drivers/net/wireless/iwlwifi/iwl-spectrum.h | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.h | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index daf99ea..c6f4eb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h index edac6c6..6f46355 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index 33016fb..85eb778 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index f0f7dc7..15570e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index d381b82..2440fd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 705c65b..4c63890 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 2fbd126..749ac03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 047317f..9b60a0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index 98b17ae..b5a6613 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1c35fa8..d0c9bdc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 05640a8..b7e366e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index fb0fd77..9873613 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 324825e..3afecf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index c6595e8..82c3859 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c index c50494a..b8137ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3a2b812..a21875d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index adcbf53..78ee83a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b3c263d..344225a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 25f4658..7956e08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 94c8e31..1abe84b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 45656f2..0ba325d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d00dfe4e..cb9491a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 81ddca0..983042b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 84f56a2..b834e21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index a115dc6..e4c264b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 370b66c..d5253a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 25e8714..c32012e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ae04327..a47fa38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 8f6b05f..4b9de7a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index c3dadb0..2ff9434 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 0008a35..01a2169 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 4f0fa21..d4d2829 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 10ca032..998ac19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index ffb428a..e8ce188 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 588c9ad..021e00b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index b429daa..be8eb95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df484a9..fa098d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_power_setting_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index b0ffb89..b7a5f23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 618841a..7894f2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index 402fd4c..86dc055 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_rf_kill_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 2a008b1..efafb91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c4b9030..3c803f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c index ad319a1..a9a1897 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index fa990a1..b7d7943 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 4a2479a..a803cfa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 7b98ea4..9bb7cef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9d7e45f..1e7cd8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f7fa68b..278f4a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ -- cgit v1.1 From 9f925938680b7d1adeb030befb6a4b5f86026b6a Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 9 Dec 2008 11:28:59 -0800 Subject: iwlifi: remove twice defined SINGLE_FRAME RX FH MASK This patch removes second definition of FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME in iwl-fh.h Signed-off-by: Tomas Winkler Reported-by: Emmanuel Grumbach Acked-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-fh.h | 3 --- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 2ff9434..d7da198 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -266,11 +266,8 @@ #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) -#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME (0x00008000) - #define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ - /** * Rx Shared Status Registers (RSSR) * diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index efafb91..096523200 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -439,7 +439,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME | + FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | rb_size| (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); -- cgit v1.1 From 6d1ef1a3e6b4915d4cde897971ce283bdf0d9fbc Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 9 Dec 2008 11:29:00 -0800 Subject: iwlwifi: 3945 remove qos module parameter The ability of disabling qos from module params is not required anymore. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 42 +++++++++++------------------ 2 files changed, 15 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index b7e366e..ec6084c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -476,7 +476,6 @@ union iwl3945_qos_capabity { /* QoS structures */ struct iwl3945_qos_info { - int qos_enable; int qos_active; union iwl3945_qos_capabity qos_cap; struct iwl3945_qosparam_cmd def_qos_parm; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 278f4a8..953ce9d 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -69,7 +69,6 @@ static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ static int iwl3945_param_disable; /* def: 0 = enable radio */ static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ -static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */ /* @@ -1693,17 +1692,21 @@ static void iwl3945_reset_qos(struct iwl3945_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->qos_data.qos_active = 0; - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + /* QoS always active in AP and ADHOC mode + * In STA mode wait for association + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + priv->iw_mode == NL80211_IFTYPE_AP) + priv->qos_data.qos_active = 1; + else + priv->qos_data.qos_active = 0; + + + /* check for legacy mode */ + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC && + (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) || + (priv->iw_mode == NL80211_IFTYPE_STATION && + (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) { cw_min = 31; is_legacy = 1; } @@ -1775,9 +1778,6 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->qos_data.qos_enable) - return; - spin_lock_irqsave(&priv->lock, flags); priv->qos_data.def_qos_parm.qos_flags = 0; @@ -7095,11 +7095,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } q = AC_NUM - 1 - queue; spin_lock_irqsave(&priv->lock, flags); @@ -7979,9 +7974,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->iw_mode = NL80211_IFTYPE_STATION; - if (iwl3945_param_qos_enable) - priv->qos_data.qos_enable = 1; - iwl3945_reset_qos(priv); priv->qos_data.qos_active = 0; @@ -8372,9 +8364,5 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl3945_param_queues_num, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -/* QoS */ -module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); - module_exit(iwl3945_exit); module_init(iwl3945_init); -- cgit v1.1 From 30dab79ed40f6c0f8a24e25fd9be7bd873eeeb8b Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 9 Dec 2008 11:29:01 -0800 Subject: iwlwifi: remove qos module parameter The ability of disabling qos from module params is not required anymore. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ---- drivers/net/wireless/iwlwifi/iwl-5000.c | 3 --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 -------- drivers/net/wireless/iwlwifi/iwl-core.c | 30 ++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 6 files changed, 14 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 3afecf8..a7e6e32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -63,7 +63,6 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); static struct iwl_mod_params iwl4965_mod_params = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, - .enable_qos = 1, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -2363,9 +2362,6 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -/* QoS */ -module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); /* 11n */ module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1b82742..2344de9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1530,7 +1530,6 @@ static struct iwl_ops iwl5000_ops = { static struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .enable_qos = 1, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -1628,8 +1627,6 @@ module_param_named(debug50, iwl50_mod_params.debug, int, 0444); MODULE_PARM_DESC(debug50, "50XX debug output mask"); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); -module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); -MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 344225a..3f425f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -546,9 +546,6 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->qos_data.qos_enable) - return; - priv->qos_data.def_qos_parm.qos_flags = 0; if (priv->qos_data.qos_cap.q_AP.queue_request && @@ -3112,11 +3109,6 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } q = AC_NUM - 1 - queue; spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cb9491a..6fc3950 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -243,24 +243,25 @@ void iwl_reset_qos(struct iwl_priv *priv) u16 cw_min = 15; u16 cw_max = 1023; u8 aifs = 2; - u8 is_legacy = 0; + bool is_legacy = false; unsigned long flags; int i; spin_lock_irqsave(&priv->lock, flags); - priv->qos_data.qos_active = 0; + /* QoS always active in AP and ADHOC mode + * In STA mode wait for association + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + priv->iw_mode == NL80211_IFTYPE_AP) + priv->qos_data.qos_active = 1; + else + priv->qos_data.qos_active = 0; - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + /* check for legacy mode */ + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC && + (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) || + (priv->iw_mode == NL80211_IFTYPE_STATION && + (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) { cw_min = 31; is_legacy = 1; } @@ -890,9 +891,6 @@ int iwl_init_drv(struct iwl_priv *priv) iwl_set_rxon_chain(priv); iwl_init_scan_params(priv); - if (priv->cfg->mod_params->enable_qos) - priv->qos_data.qos_enable = 1; - iwl_reset_qos(priv); priv->qos_data.qos_active = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 983042b..72f82ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -157,7 +157,6 @@ struct iwl_mod_params { int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ - int enable_qos; /* def: 1 = use quality of service */ int disable_11n; /* def: 0 = disable 11n capabilities */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c32012e..fc859f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -436,7 +436,6 @@ union iwl_qos_capabity { /* QoS structures */ struct iwl_qos_info { - int qos_enable; int qos_active; union iwl_qos_capabity qos_cap; struct iwl_qosparam_cmd def_qos_parm; -- cgit v1.1 From 39ca5bb76f3382b1cb0062d75ec45abd1c46e6d2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 21:09:00 +0100 Subject: p54: enforce strict tx_queue limits The patch fixes an old FIXME in p54pci.c by moving the "queue full" check into the common library, where we can deal with it properly. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 22 +++++++++++++++++++++- drivers/net/wireless/p54/p54pci.c | 7 ------- 2 files changed, 21 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 409ae93..fac6b41 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -874,7 +874,27 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, return -EINVAL; spin_lock_irqsave(&priv->tx_queue.lock, flags); + left = skb_queue_len(&priv->tx_queue); + if (unlikely(left >= 28)) { + /* + * The tx_queue is nearly full! + * We have throttle normal data traffic, because we must + * have a few spare slots for control frames left. + */ + ieee80211_stop_queues(dev); + + if (unlikely(left == 32)) { + /* + * The tx_queue is now really full. + * + * TODO: check if the device has crashed and reset it. + */ + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + } + while (left--) { u32 hole_size; info = IEEE80211_SKB_CB(entry); @@ -903,7 +923,7 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, if (!target_skb) { spin_unlock_irqrestore(&priv->tx_queue.lock, flags); ieee80211_stop_queues(dev); - return -ENOMEM; + return -ENOSPC; } info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index d21c509..c28220e 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -332,13 +332,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); P54P_READ(dev_int); - - /* FIXME: unlikely to happen because the device usually runs out of - memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) { - p54_free_skb(dev, skb); - printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); - } } static void p54p_stop(struct ieee80211_hw *dev) -- cgit v1.1 From 0c06dd8a237c673eedd295fbef7a8c0e52f5c045 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Tue, 9 Dec 2008 21:46:28 +0000 Subject: orinoco: Fix function names used in debug strings Signed-off-by: David Kilroy Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco_cs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index bf6a51d..f127602 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -178,13 +178,17 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } -- cgit v1.1 From 499b702a8d848aaa15d6255e9302d9186827691e Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Tue, 9 Dec 2008 21:46:29 +0000 Subject: orinoco: Fix inappropriate use of IRQ_BAP This hardware buffer should only be used from an interrupt. The wireless event generation functions are called from a workqueue, so use USER_BAP instead. Signed-off-by: David Kilroy Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index 171bfa0..bc84e27 100644 --- a/drivers/net/wireless/orinoco/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -1750,7 +1750,7 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv) union iwreq_data wrqu; int err; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) return; @@ -1773,7 +1773,7 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) if (!priv->has_wpa) return; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, sizeof(buf), NULL, &buf); if (err != 0) return; @@ -1803,7 +1803,7 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) if (!priv->has_wpa) return; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, sizeof(buf), NULL, &buf); if (err != 0) return; -- cgit v1.1 From 62d714e5ebec9ad4d63bb9a6da19dfd83d3db860 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Tue, 9 Dec 2008 23:05:38 +0000 Subject: spectrum_cs: Fix function names used in debug strings Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/spectrum_cs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index a276476..b2ca2e3 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -248,13 +248,17 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } -- cgit v1.1 From 388cdf31db6dfc3d175786a76989266380e12c26 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 9 Dec 2008 23:05:38 -0500 Subject: ath5k: fix endianness of bitwise ops when installing mic Fix these bugs found by sparse: ath5k/pcu.c:1102:21: warning: restricted __le32 degrades to integer ath5k/pcu.c:1102:13: warning: incorrect type in assignment (different base types) ath5k/pcu.c:1102:13: expected restricted __le32 ath5k/pcu.c:1102:13: got unsigned int ath5k/pcu.c:1104:20: warning: restricted __le32 degrades to integer ath5k/pcu.c:1104:13: warning: incorrect type in assignment (different base types) ath5k/pcu.c:1104:13: expected restricted __le32 ath5k/pcu.c:1104:13: got unsigned int Changes-licensed-under: ISC Reported-by: Johannes Berg Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/pcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index dabe422..0cac05c 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -1099,9 +1099,9 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, if (ah->ah_combined_mic) { key_v[0] = rxmic[0]; - key_v[1] = (txmic[0] >> 16) & 0xffff; + key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); key_v[2] = rxmic[1]; - key_v[3] = txmic[0] & 0xffff; + key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); key_v[4] = txmic[1]; } else { key_v[0] = rxmic[0]; -- cgit v1.1 From c1db52b9d27ee6e15a7136e67e4a21dc916cd07f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 9 Dec 2008 23:34:27 -0600 Subject: rtl8187: Use usb anchor facilities to manage urbs When SLUB debugging is enabled in the kernel, and the boot command includes the option "slub_debug=P", rtl8187 encounters a GPF due to a read-after-free of a urb. Following the example of changes in p54usb to fix the same problem, the code has been modified to use the usb_anchor_urb() method. With this change, the USB core handles the freeing of urb's. This patch fixes the problem reported in Kernel Bugzilla #12185 (http://bugzilla.kernel.org/show_bug.cgi?id=12185). Signed-off-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187.h | 2 +- drivers/net/wireless/rtl818x/rtl8187_dev.c | 75 ++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index c385407a9..3b1e1c2 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -99,6 +99,7 @@ struct rtl8187_priv { struct ieee80211_supported_band band; struct usb_device *udev; u32 rx_conf; + struct usb_anchor anchored; u16 txpwr_base; u8 asic_rev; u8 is_rtl8187b; @@ -115,7 +116,6 @@ struct rtl8187_priv { u8 aifsn[4]; struct { __le64 buf; - struct urb *urb; struct sk_buff_head queue; } b_tx_status; }; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 417a2d7..74f5449 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -99,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = { static void rtl8187_iowrite_async_cb(struct urb *urb) { kfree(urb->context); - usb_free_urb(urb); } static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, @@ -136,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), (unsigned char *)dr, buf, len, rtl8187_iowrite_async_cb, buf); + usb_anchor_urb(urb, &priv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { kfree(buf); - usb_free_urb(urb); + usb_unanchor_urb(urb); } + usb_free_urb(urb); } static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, @@ -172,7 +173,6 @@ static void rtl8187_tx_cb(struct urb *urb) struct ieee80211_hw *hw = info->rate_driver_data[0]; struct rtl8187_priv *priv = hw->priv; - usb_free_urb(info->rate_driver_data[1]); skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); ieee80211_tx_info_clear_status(info); @@ -273,11 +273,13 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), buf, skb->len, rtl8187_tx_cb, skb); + usb_anchor_urb(urb, &priv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { - usb_free_urb(urb); + usb_unanchor_urb(urb); kfree_skb(skb); } + usb_free_urb(urb); return 0; } @@ -301,14 +303,13 @@ static void rtl8187_rx_cb(struct urb *urb) return; } spin_unlock(&priv->rx_queue.lock); + skb_put(skb, urb->actual_length); if (unlikely(urb->status)) { - usb_free_urb(urb); dev_kfree_skb_irq(skb); return; } - skb_put(skb, urb->actual_length); if (!priv->is_rtl8187b) { struct rtl8187_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); @@ -361,7 +362,6 @@ static void rtl8187_rx_cb(struct urb *urb) skb = dev_alloc_skb(RTL8187_MAX_RX); if (unlikely(!skb)) { - usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } @@ -373,24 +373,32 @@ static void rtl8187_rx_cb(struct urb *urb) urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(urb, GFP_ATOMIC); + usb_anchor_urb(urb, &priv->anchored); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + usb_unanchor_urb(urb); + skb_unlink(skb, &priv->rx_queue); + dev_kfree_skb_irq(skb); + } } static int rtl8187_init_urbs(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; - struct urb *entry; + struct urb *entry = NULL; struct sk_buff *skb; struct rtl8187_rx_info *info; + int ret = 0; while (skb_queue_len(&priv->rx_queue) < 8) { skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); - if (!skb) - break; + if (!skb) { + ret = -ENOMEM; + goto err; + } entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { - kfree_skb(skb); - break; + ret = -ENOMEM; + goto err; } usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, @@ -401,10 +409,22 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); + usb_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(entry); + goto err; + } + usb_free_urb(entry); } + return ret; - return 0; +err: + usb_free_urb(entry); + kfree_skb(skb); + usb_kill_anchored_urbs(&priv->anchored); + return ret; } static void rtl8187b_status_cb(struct urb *urb) @@ -414,10 +434,8 @@ static void rtl8187b_status_cb(struct urb *urb) u64 val; unsigned int cmd_type; - if (unlikely(urb->status)) { - usb_free_urb(urb); + if (unlikely(urb->status)) return; - } /* * Read from status buffer: @@ -488,26 +506,32 @@ static void rtl8187b_status_cb(struct urb *urb) spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); } - usb_submit_urb(urb, GFP_ATOMIC); + usb_anchor_urb(urb, &priv->anchored); + if (usb_submit_urb(urb, GFP_ATOMIC)) + usb_unanchor_urb(urb); } static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; struct urb *entry; + int ret = 0; entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) return -ENOMEM; - priv->b_tx_status.urb = entry; usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9), &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf), rtl8187b_status_cb, dev); - usb_submit_urb(entry, GFP_KERNEL); + usb_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) + usb_unanchor_urb(entry); + usb_free_urb(entry); - return 0; + return ret; } static int rtl8187_cmd_reset(struct ieee80211_hw *dev) @@ -841,6 +865,9 @@ static int rtl8187_start(struct ieee80211_hw *dev) return ret; mutex_lock(&priv->conf_mutex); + + init_usb_anchor(&priv->anchored); + if (priv->is_rtl8187b) { reg = RTL818X_RX_CONF_MGMT | RTL818X_RX_CONF_DATA | @@ -936,12 +963,12 @@ static void rtl8187_stop(struct ieee80211_hw *dev) while ((skb = skb_dequeue(&priv->rx_queue))) { info = (struct rtl8187_rx_info *)skb->cb; - usb_kill_urb(info->urb); kfree_skb(skb); } while ((skb = skb_dequeue(&priv->b_tx_status.queue))) dev_kfree_skb_any(skb); - usb_kill_urb(priv->b_tx_status.urb); + + usb_kill_anchored_urbs(&priv->anchored); mutex_unlock(&priv->conf_mutex); } -- cgit v1.1 From d8004cb9267b15cd902eef01a75bb1ffa3995af8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 9 Dec 2008 23:35:41 -0600 Subject: b43legacy: Fix sparse warnings Sparse yields the following warnings for b43legacy: CHECK drivers/net/wireless/b43legacy/phy.c drivers/net/wireless/b43legacy/phy.c:1304:31: warning: potentially expensive pointer subtraction drivers/net/wireless/b43legacy/phy.c:1304:31: warning: potentially expensive pointer subtraction drivers/net/wireless/b43legacy/phy.c:1304:31: warning: potentially expensive pointer subtraction CHECK drivers/net/wireless/b43legacy/debugfs.c drivers/net/wireless/b43legacy/debugfs.c:243:9: warning: memset with byte count of 131072 Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/debugfs.c | 2 +- drivers/net/wireless/b43legacy/phy.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 03ce082..1f85ac5 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -211,7 +211,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, struct b43legacy_dfs_file *dfile; ssize_t uninitialized_var(ret); char *buf; - const size_t bufsize = 1024 * 128; + const size_t bufsize = 1024 * 16; /* 16 KiB buffer */ const size_t buforder = get_order(bufsize); int err = 0; diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 4c9442b..11319ec 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -1296,12 +1296,10 @@ void b43legacy_lo_write(struct b43legacy_wldev *dev, /* Sanity check. */ if (pair->low < -8 || pair->low > 8 || pair->high < -8 || pair->high > 8) { - struct b43legacy_phy *phy = &dev->phy; b43legacydbg(dev->wl, "WARNING: Writing invalid LOpair " - "(low: %d, high: %d, index: %lu)\n", - pair->low, pair->high, - (unsigned long)(pair - phy->_lo_pairs)); + "(low: %d, high: %d)\n", + pair->low, pair->high); dump_stack(); } #endif -- cgit v1.1 From 14a4dfe2ff8c353f59ae8324059ded1cfe22c7d9 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 10 Dec 2008 13:17:26 +0100 Subject: ipw2200: fix scanning while associated This patch fixes sporadic firmware restarts when scanning while associated. The firmware will quietly cancel a scan (while associated) if the dwell time for a channel to be scanned is larger than the time it may stay away from the operating channel (because of DTIM catching). Unfortunately the driver is not notified about the canceled scan and therefore the scan watchdog timeout will be hit and the driver causes a firmware restart which results in disassociation. This mainly happens on passive channels which use a dwell time of 120 whereas a typical beacon interval is around 100. The patch changes the dwell time for passive channels to be slightly smaller than the actual beacon interval to work around the firmware issue. Furthermore the number of allowed beacon misses is increased from one to three as otherwise most scans (while associated) won't complete successfully. However scanning while associated will still fail in corner cases such as a beacon intervals below 30. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 28 ++++++++++++++++++++++------ drivers/net/wireless/ipw2x00/ipw2200.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 23728eb..625f2cf 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -4345,7 +4345,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, return; } - if (priv->status & STATUS_SCANNING) { + if (priv->status & STATUS_SCANNING && + missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) { /* Stop scan to keep fw from getting * stuck (only if we aren't roaming -- * otherwise we'll never scan more than 2 or 3 @@ -6271,6 +6272,20 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } +static int ipw_passive_dwell_time(struct ipw_priv *priv) +{ + /* staying on passive channels longer than the DTIM interval during a + * scan, while associated, causes the firmware to cancel the scan + * without notification. Hence, don't stay on passive channels longer + * than the beacon interval. + */ + if (priv->status & STATUS_ASSOCIATED + && priv->assoc_network->beacon_interval > 10) + return priv->assoc_network->beacon_interval - 10; + else + return 120; +} + static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) { struct ipw_scan_request_ext scan; @@ -6314,16 +6329,16 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); if (type == IW_SCAN_TYPE_PASSIVE) { - IPW_DEBUG_WX("use passive scanning\n"); - scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; + IPW_DEBUG_WX("use passive scanning\n"); + scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = - cpu_to_le16(120); + cpu_to_le16(ipw_passive_dwell_time(priv)); ipw_add_scan_channels(priv, &scan, scan_type); goto send_request; } /* Use active scan by default. */ - if (priv->config & CFG_SPEED_SCAN) + if (priv->config & CFG_SPEED_SCAN) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = cpu_to_le16(30); else @@ -6333,7 +6348,8 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(ipw_passive_dwell_time(priv)); scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); #ifdef CONFIG_IPW2200_MONITOR diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 0a84d52..277b274 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -245,6 +245,7 @@ enum connection_manager_assoc_states { #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 +#define IPW_MB_SCAN_CANCEL_THRESHOLD 3 #define IPW_MB_ROAMING_THRESHOLD_MIN 1 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 #define IPW_MB_ROAMING_THRESHOLD_MAX 30 -- cgit v1.1 From b7a530d82cb36bb43901c196039b0fccee3ffcc3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 10 Dec 2008 14:51:47 +0200 Subject: mac80211: Disable requests for new scans in AP mode AP mode operations are seriously affected if mac80211 runs through a multi-second scan while the AP is trying to send Beacon frames on the operation channel. While this could be implemented in a way that does not cause too many problems, it is not very simple and will require synchronization with Beacon frame scheduling in the drivers (scan one channel at a time between Beacon frames). Furthermore, such scanning takes quite a bit longer time and existing userspace applications would be likely to timeout while waiting for the results. For now, just refuse requests for new scans (SIOCSIWSCAN) when in AP mode. In practice, this moves the rejection from iwl* drivers into mac80211 to make it apply to every mac80211-based driver. This issue shows up in associated stations getting disconnected when something (e.g., Network Manager) requests a scan while the interface is in AP mode. When doing this continuously (e.g., NM does it every 120 seconds), the network gets close to useless. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 11 ----------- 2 files changed, 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3f425f6..06e2682 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2960,12 +2960,6 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) goto out_unlock; } - if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ - ret = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 953ce9d..f883006 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2103,11 +2103,6 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) static int iwl3945_scan_initiate(struct iwl3945_priv *priv) { - if (priv->iw_mode == NL80211_IFTYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; @@ -6976,12 +6971,6 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) goto out_unlock; } - if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ - rc = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - /* we don't schedule scan within next_scan_jiffies period */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { -- cgit v1.1 From 59651e89187293e88863891b821c7379391ef75c Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 9 Dec 2008 21:07:50 +0100 Subject: p54: fix oops on faulty devices This patch fixes an oops when the devices suddenly starts to receive martian data frames. bug reference: http://marc.info/?l=linux-wireless&m=122872280317635&w=2 Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index fac6b41..a4e99b0 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -540,6 +540,14 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) size_t header_len = sizeof(*hdr); u32 tsf32; + /* + * If the device is in a unspecified state we have to + * ignore all data frames. Else we could end up with a + * nasty crash. + */ + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return 0; + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { if (priv->filter_flags & FIF_FCSFAIL) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; @@ -608,6 +616,12 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) return; + /* + * don't try to free an already unlinked skb + */ + if (unlikely((!skb->next) || (!skb->prev))) + return; + spin_lock_irqsave(&priv->tx_queue.lock, flags); info = IEEE80211_SKB_CB(skb); range = (void *)info->rate_driver_data; @@ -1695,19 +1709,18 @@ static void p54_stop(struct ieee80211_hw *dev) struct sk_buff *skb; mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; del_timer(&priv->stats_timer); p54_free_skb(dev, priv->cached_stats); priv->cached_stats = NULL; if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); + priv->stop(dev); while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - priv->cached_beacon = NULL; - priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; mutex_unlock(&priv->conf_mutex); } -- cgit v1.1 From b77f483fcf0579de28873828897f53371a33a0ea Mon Sep 17 00:00:00 2001 From: Sujith Date: Sun, 7 Dec 2008 21:44:03 +0530 Subject: ath9k: Refactor struct ath_softc Split ath_softc into smaller structures for rx, tx and beacon handling. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 94 ++++++++++++------------- drivers/net/wireless/ath9k/core.h | 134 ++++++++++++++++-------------------- drivers/net/wireless/ath9k/main.c | 60 ++++++++-------- drivers/net/wireless/ath9k/recv.c | 107 ++++++++++++++-------------- drivers/net/wireless/ath9k/xmit.c | 126 ++++++++++++++++----------------- 5 files changed, 254 insertions(+), 267 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 9e5c0c0..3ab0b43 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -26,7 +26,7 @@ static int ath_beaconq_config(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; - ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi); + ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; @@ -34,17 +34,17 @@ static int ath_beaconq_config(struct ath_softc *sc) qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs; - qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin; - qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax; + qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs; + qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin; + qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax; } - if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, "unable to update h/w beacon queue parameters\n"); return 0; } else { - ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ + ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */ return 1; } } @@ -53,7 +53,7 @@ static void ath_bstuck_process(struct ath_softc *sc) { DPRINTF(sc, ATH_DBG_BEACON, "stuck beacon; resetting (bmiss count %u)\n", - sc->sc_bmisscount); + sc->beacon.bmisscnt); ath_reset(sc, false); } @@ -96,7 +96,7 @@ static void ath_beacon_setup(struct ath_softc *sc, * SWBA's * XXX assumes two antenna */ - antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); + antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); } ds->ds_data = bf->bf_buf_addr; @@ -153,7 +153,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) ASSERT(vif); avp = (void *)vif->drv_priv; - cabq = sc->sc_cabq; + cabq = sc->beacon.cabq; if (avp->av_bcbuf == NULL) { DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", @@ -182,9 +182,9 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * TX frames) */ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } bf->bf_buf_addr = bf->bf_dmacontext = @@ -270,10 +270,10 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) ath_beacon_setup(sc, avp, bf); /* NB: caller is known to have already stopped tx dma */ - ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); - ath9k_hw_txstart(ah, sc->sc_bhalq); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", - sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc); + sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } int ath_beaconq_setup(struct ath_hal *ah) @@ -306,7 +306,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) if (!avp->av_bcbuf) { /* Allocate beacon state for hostap/ibss. We know * a buffer is available. */ - avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, + avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list); list_del(&avp->av_bcbuf->list); @@ -319,13 +319,13 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) */ avp->av_bslot = 0; for (slot = 0; slot < ATH_BCBUF; slot++) - if (sc->sc_bslot[slot] == ATH_IF_ID_ANY) { + if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) { /* * XXX hack, space out slots to better * deal with misses */ if (slot+1 < ATH_BCBUF && - sc->sc_bslot[slot+1] == + sc->beacon.bslot[slot+1] == ATH_IF_ID_ANY) { avp->av_bslot = slot+1; break; @@ -333,8 +333,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) avp->av_bslot = slot; /* NB: keep looking for a double slot */ } - BUG_ON(sc->sc_bslot[avp->av_bslot] != ATH_IF_ID_ANY); - sc->sc_bslot[avp->av_bslot] = if_id; + BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY); + sc->beacon.bslot[avp->av_bslot] = if_id; sc->sc_nbcnvaps++; } } @@ -362,7 +362,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) } tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->bc_tstamp = le64_to_cpu(tstamp); + sc->beacon.bc_tstamp = le64_to_cpu(tstamp); /* * Calculate a TSF adjustment factor required for @@ -422,7 +422,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) struct ath_buf *bf; if (avp->av_bslot != -1) { - sc->sc_bslot[avp->av_bslot] = ATH_IF_ID_ANY; + sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY; sc->sc_nbcnvaps--; } @@ -435,7 +435,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } - list_add_tail(&bf->list, &sc->sc_bbuf); + list_add_tail(&bf->list, &sc->beacon.bbuf); avp->av_bcbuf = NULL; } @@ -469,18 +469,18 @@ void ath9k_beacon_tasklet(unsigned long data) * * FIXME: Clean up this mess !! */ - if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) { - sc->sc_bmisscount++; + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { + sc->beacon.bmisscnt++; /* XXX: doth needs the chanchange IE countdown decremented. * We should consider adding a mac80211 call to indicate * a beacon miss so appropriate action could be taken * (in that layer). */ - if (sc->sc_bmisscount < BSTUCK_THRESH) { + if (sc->beacon.bmisscnt < BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "missed %u consecutive beacons\n", - sc->sc_bmisscount); + sc->beacon.bmisscnt); if (show_cycles) { /* * Display cycle counter stats from HW @@ -499,11 +499,11 @@ void ath9k_beacon_tasklet(unsigned long data) } else { DPRINTF(sc, ATH_DBG_BEACON, "missed %u consecutive beacons\n", - sc->sc_bmisscount); + sc->beacon.bmisscnt); } - } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { + } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { - if (sc->sc_bmisscount == BSTUCK_THRESH) { + if (sc->beacon.bmisscnt == BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, "beacon is officially " "stuck\n"); @@ -517,17 +517,17 @@ void ath9k_beacon_tasklet(unsigned long data) return; } - if (sc->sc_bmisscount != 0) { + if (sc->beacon.bmisscnt != 0) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "resume beacon xmit after %u misses\n", - sc->sc_bmisscount); + sc->beacon.bmisscnt); } else { DPRINTF(sc, ATH_DBG_BEACON, "resume beacon xmit after %u misses\n", - sc->sc_bmisscount); + sc->beacon.bmisscnt); } - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; } /* @@ -542,7 +542,7 @@ void ath9k_beacon_tasklet(unsigned long data) tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); slot = ((tsftu % intval) * ATH_BCBUF) / intval; - if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; + if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; DPRINTF(sc, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", @@ -574,12 +574,12 @@ void ath9k_beacon_tasklet(unsigned long data) * set to ATH_BCBUF so this check is a noop. */ /* XXX locking */ - if (sc->sc_updateslot == UPDATE) { - sc->sc_updateslot = COMMIT; /* commit next beacon */ - sc->sc_slotupdate = slot; - } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) { - ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime); - sc->sc_updateslot = OK; + if (sc->beacon.updateslot == UPDATE) { + sc->beacon.updateslot = COMMIT; /* commit next beacon */ + sc->beacon.slotupdate = slot; + } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { + ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); + sc->beacon.updateslot = OK; } if (bfaddr != 0) { /* @@ -587,17 +587,17 @@ void ath9k_beacon_tasklet(unsigned long data) * This should never fail since we check above that no frames * are still pending on the queue. */ - if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) { + if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { DPRINTF(sc, ATH_DBG_FATAL, - "beacon queue %u did not stop?\n", sc->sc_bhalq); + "beacon queue %u did not stop?\n", sc->beacon.beaconq); /* NB: the HAL still stops DMA, so proceed */ } /* NB: cabq traffic should already be queued and primed */ - ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bfaddr); - ath9k_hw_txstart(ah, sc->sc_bhalq); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); - sc->ast_be_xmit += bc; /* XXX per-vap? */ + sc->beacon.ast_be_xmit += bc; /* XXX per-vap? */ } } @@ -644,7 +644,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; /* extract tstamp from last beacon and convert to TU */ - nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); + nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); /* XXX conditionalize multi-bss support? */ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { @@ -831,7 +831,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath_beaconq_config(sc); } ath9k_hw_beaconinit(ah, nexttbtt, intval); - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, sc->sc_imask); /* * When using a self-linked beacon descriptor in diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 41a87b9..e38f033 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -61,7 +61,7 @@ struct ath_node; #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<tx.txqsetup & (1<rx_filter & FIF_BCN_PRBRESP_PROMISC) + if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) return; /* Long calibration runs independently of short calibration. */ @@ -487,9 +487,9 @@ static void ath9k_tasklet(unsigned long data) if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - spin_lock_bh(&sc->sc_rxflushlock); + spin_lock_bh(&sc->rx.rxflushlock); ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->sc_rxflushlock); + spin_unlock_bh(&sc->rx.rxflushlock); } /* XXX: optimize this */ if (status & ATH9K_INT_TX) @@ -1306,7 +1306,7 @@ static void ath_detach(struct ath_softc *sc) /* cleanup tx queues */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); + ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath9k_hw_detach(sc->sc_ah); ath9k_exit_debug(sc); @@ -1397,15 +1397,15 @@ static int ath_init(u16 devid, struct ath_softc *sc) * priority. Note that the hal handles reseting * these queues at the needed time. */ - sc->sc_bhalq = ath_beaconq_setup(ah); - if (sc->sc_bhalq == -1) { + sc->beacon.beaconq = ath_beaconq_setup(ah); + if (sc->beacon.beaconq == -1) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); error = -EIO; goto bad2; } - sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->sc_cabq == NULL) { + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->beacon.cabq == NULL) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup CAB xmit queue\n"); error = -EIO; @@ -1415,8 +1415,8 @@ static int ath_init(u16 devid, struct ath_softc *sc) sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++) - sc->sc_haltype2q[i] = -1; + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; /* Setup data queues */ /* NB: ensure BK queue is the lowest priority h/w queue */ @@ -1496,7 +1496,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->sc_defant = ath9k_hw_getdefantenna(ah); + sc->rx.defant = ath9k_hw_getdefantenna(ah); ath9k_hw_getmac(ah, sc->sc_myaddr); if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { @@ -1505,11 +1505,11 @@ static int ath_init(u16 devid, struct ath_softc *sc) ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); } - sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++) - sc->sc_bslot[i] = ATH_IF_ID_ANY; + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) + sc->beacon.bslot[i] = ATH_IF_ID_ANY; /* save MISC configurations */ sc->sc_config.swBeaconProcess = 1; @@ -1535,7 +1535,7 @@ bad2: /* cleanup tx queues */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); + ath_tx_cleanupq(sc, &sc->tx.txq[i]); bad: if (ah) ath9k_hw_detach(ah); @@ -1673,9 +1673,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) int i; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { - spin_lock_bh(&sc->sc_txq[i].axq_lock); - ath_txq_schedule(sc, &sc->sc_txq[i]); - spin_unlock_bh(&sc->sc_txq[i].axq_lock); + spin_lock_bh(&sc->tx.txq[i].axq_lock); + ath_txq_schedule(sc, &sc->tx.txq[i]); + spin_unlock_bh(&sc->tx.txq[i].axq_lock); } } } @@ -1810,19 +1810,19 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) switch (queue) { case 0: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO]; + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; break; case 1: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI]; + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; break; case 2: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; break; case 3: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK]; + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; break; default: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; break; } @@ -1993,9 +1993,9 @@ static int ath9k_tx(struct ieee80211_hw *hw, 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; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } /* Add the padding after the header if this is not already done */ @@ -2049,7 +2049,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_stoprecv(sc); ath9k_hw_phy_disable(sc->sc_ah); } else - sc->sc_rxlink = NULL; + sc->rx.rxlink = NULL; #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) @@ -2131,7 +2131,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, /* Reclaim beacon resources */ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ath_beacon_return(sc, avp); } @@ -2250,7 +2250,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, * causes reconfiguration; we may be called * with beacon transmission active. */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); error = ath_beacon_alloc(sc, 0); if (error != 0) @@ -2296,7 +2296,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - sc->rx_filter = *total_flags; + sc->rx.rxfilter = *total_flags; rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); @@ -2305,7 +2305,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); } - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx_filter); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); } 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 b182ef5..cb449f0 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -41,20 +41,19 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ASSERT(skb != NULL); ds->ds_vdata = skb->data; - /* setup rx descriptors. The sc_rxbufsize here tells the harware + /* setup rx descriptors. The rx.bufsize here tells the harware * how much data it can DMA to us and that we are prepared * to process */ - ath9k_hw_setuprxdesc(ah, - ds, - sc->sc_rxbufsize, + ath9k_hw_setuprxdesc(ah, ds, + sc->rx.bufsize, 0); - if (sc->sc_rxlink == NULL) + if (sc->rx.rxlink == NULL) ath9k_hw_putrxbuf(ah, bf->bf_daddr); else - *sc->sc_rxlink = bf->bf_daddr; + *sc->rx.rxlink = bf->bf_daddr; - sc->sc_rxlink = &ds->ds_link; + sc->rx.rxlink = &ds->ds_link; ath9k_hw_rxena(ah); } @@ -62,8 +61,8 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { /* XXX block beacon interrupts */ ath9k_hw_setantenna(sc->sc_ah, antenna); - sc->sc_defant = antenna; - sc->sc_rxotherant = 0; + sc->rx.defant = antenna; + sc->rx.rxotherant = 0; } /* @@ -272,20 +271,20 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) int error = 0; do { - spin_lock_init(&sc->sc_rxflushlock); + spin_lock_init(&sc->rx.rxflushlock); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->sc_rxbuflock); + spin_lock_init(&sc->rx.rxbuflock); - sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN, + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, min(sc->sc_cachelsz, (u16)64)); DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->sc_cachelsz, sc->sc_rxbufsize); + sc->sc_cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ - error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, "rx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, @@ -293,8 +292,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) break; } - list_for_each_entry(bf, &sc->sc_rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); if (skb == NULL) { error = -ENOMEM; break; @@ -302,8 +301,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_mpdu = skb; bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); @@ -315,7 +314,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } bf->bf_dmacontext = bf->bf_buf_addr; } - sc->sc_rxlink = NULL; + sc->rx.rxlink = NULL; } while (0); @@ -330,14 +329,14 @@ void ath_rx_cleanup(struct ath_softc *sc) struct sk_buff *skb; struct ath_buf *bf; - list_for_each_entry(bf, &sc->sc_rxbuf, list) { + list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; if (skb) dev_kfree_skb(skb); } - if (sc->sc_rxdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); + if (sc->rx.rxdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); } /* @@ -375,7 +374,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) /* Can't set HOSTAP into promiscous mode */ if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) && - (sc->rx_filter & FIF_PROMISC_IN_BSS)) || + (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ @@ -401,25 +400,25 @@ int ath_startrecv(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf, *tbf; - spin_lock_bh(&sc->sc_rxbuflock); - if (list_empty(&sc->sc_rxbuf)) + spin_lock_bh(&sc->rx.rxbuflock); + if (list_empty(&sc->rx.rxbuf)) goto start_recv; - sc->sc_rxlink = NULL; - list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) { + sc->rx.rxlink = NULL; + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { ath_rx_buf_link(sc, bf); } /* We could have deleted elements so the list may be empty now */ - if (list_empty(&sc->sc_rxbuf)) + if (list_empty(&sc->rx.rxbuf)) goto start_recv; - bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ath9k_hw_putrxbuf(ah, bf->bf_daddr); ath9k_hw_rxena(ah); start_recv: - spin_unlock_bh(&sc->sc_rxbuflock); + spin_unlock_bh(&sc->rx.rxbuflock); ath_opmode_init(sc); ath9k_hw_startpcureceive(ah); @@ -435,25 +434,25 @@ bool ath_stoprecv(struct ath_softc *sc) ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); mdelay(3); /* 3ms is long enough for 1 frame */ - sc->sc_rxlink = NULL; + sc->rx.rxlink = NULL; return stopped; } void ath_flushrecv(struct ath_softc *sc) { - spin_lock_bh(&sc->sc_rxflushlock); + spin_lock_bh(&sc->rx.rxflushlock); sc->sc_flags |= SC_OP_RXFLUSH; ath_rx_tasklet(sc, 1); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->sc_rxflushlock); + spin_unlock_bh(&sc->rx.rxflushlock); } int ath_rx_tasklet(struct ath_softc *sc, int flush) { #define PA2DESC(_sc, _pa) \ - ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ - ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) + ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \ + ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr))) struct ath_buf *bf; struct ath_desc *ds; @@ -465,19 +464,19 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bool decrypt_error = false; u8 keyix; - spin_lock_bh(&sc->sc_rxbuflock); + spin_lock_bh(&sc->rx.rxbuflock); do { /* If handling rx interrupt and flush is in progress => exit */ if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; - if (list_empty(&sc->sc_rxbuf)) { - sc->sc_rxlink = NULL; + if (list_empty(&sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } - bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ds = bf->bf_desc; /* @@ -499,8 +498,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_buf *tbf; struct ath_desc *tds; - if (list_is_last(&bf->list, &sc->sc_rxbuf)) { - sc->sc_rxlink = NULL; + if (list_is_last(&bf->list, &sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } @@ -540,7 +539,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) goto requeue; /* The status portion of the descriptor could get corrupted. */ - if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen) + if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) goto requeue; if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) @@ -548,21 +547,21 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ - requeue_skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); + requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); /* If there is no memory we ignore the current RX'd frame, * tell hardware it can give us a new frame using the old - * skb and put it at the tail of the sc->sc_rxbuf list for + * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ if (!requeue_skb) goto requeue; - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, + /* Sync and unmap the frame */ + pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, PCI_DMA_FROMDEVICE); pci_unmap_single(sc->pdev, bf->bf_buf_addr, - sc->sc_rxbufsize, + sc->rx.bufsize, PCI_DMA_FROMDEVICE); skb_put(skb, ds->ds_rxstat.rs_datalen); @@ -596,7 +595,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data, - sc->sc_rxbufsize, + sc->rx.bufsize, PCI_DMA_FROMDEVICE); if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { @@ -612,18 +611,18 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. */ - if (sc->sc_defant != ds->ds_rxstat.rs_antenna) { - if (++sc->sc_rxotherant >= 3) + if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { + if (++sc->rx.rxotherant >= 3) ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); } else { - sc->sc_rxotherant = 0; + sc->rx.rxotherant = 0; } requeue: - list_move_tail(&bf->list, &sc->sc_rxbuf); + list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); } while (1); - spin_unlock_bh(&sc->sc_rxbuflock); + spin_unlock_bh(&sc->rx.rxbuflock); return 0; #undef PA2DESC diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index e2e847d..f9c309e 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -286,17 +286,17 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) { struct ath_buf *bf = NULL; - spin_lock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); - if (unlikely(list_empty(&sc->sc_txbuf))) { - spin_unlock_bh(&sc->sc_txbuflock); + if (unlikely(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); return NULL; } - bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list); + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&bf->list); - spin_unlock_bh(&sc->sc_txbuflock); + spin_unlock_bh(&sc->tx.txbuflock); return bf; } @@ -341,9 +341,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, /* * Return the list of ath_buf of this mpdu to free queue */ - spin_lock_irqsave(&sc->sc_txbuflock, flags); - list_splice_tail_init(bf_q, &sc->sc_txbuf); - spin_unlock_irqrestore(&sc->sc_txbuflock, flags); + spin_lock_irqsave(&sc->tx.txbuflock, flags); + list_splice_tail_init(bf_q, &sc->tx.txbuf); + spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } /* @@ -384,7 +384,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; spin_lock_bh(&txq->axq_lock); @@ -397,7 +397,7 @@ static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; ASSERT(tid->paused > 0); spin_lock_bh(&txq->axq_lock); @@ -686,7 +686,7 @@ static int ath_tx_send_normal(struct ath_softc *sc, static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); @@ -861,12 +861,12 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, struct ath_buf *tbf; /* allocate new descriptor */ - spin_lock_bh(&sc->sc_txbuflock); - ASSERT(!list_empty((&sc->sc_txbuf))); - tbf = list_first_entry(&sc->sc_txbuf, + spin_lock_bh(&sc->tx.txbuflock); + ASSERT(!list_empty((&sc->tx.txbuf))); + tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); - spin_unlock_bh(&sc->sc_txbuflock); + spin_unlock_bh(&sc->tx.txbuflock); ATH_TXBUF_RESET(tbf); @@ -1058,9 +1058,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf_held) { list_del(&bf_held->list); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf_held->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); } if (!bf_isampdu(bf)) { @@ -1129,11 +1129,11 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) 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]); + ath_tx_stopdma(sc, &sc->tx.txq[i]); /* The TxDMA may not really be stopped. * Double check the hal tx pending count */ npend += ath9k_hw_numtxpending(ah, - sc->sc_txq[i].axq_qnum); + sc->tx.txq[i].axq_qnum); } } } @@ -1158,7 +1158,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) - ath_tx_draintxq(sc, &sc->sc_txq[i], retry_tx); + ath_tx_draintxq(sc, &sc->tx.txq[i], retry_tx); } } @@ -1820,9 +1820,9 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, } spin_unlock_bh(&txq->axq_lock); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); return r; } @@ -1839,10 +1839,10 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) int error = 0; do { - spin_lock_init(&sc->sc_txbuflock); + spin_lock_init(&sc->tx.txbuflock); /* Setup tx descriptors */ - error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, @@ -1852,7 +1852,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } /* XXX allocate beacon state together with vap */ - error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, "beacon", ATH_BCBUF, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, @@ -1874,12 +1874,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) int ath_tx_cleanup(struct ath_softc *sc) { /* cleanup beacon descriptors */ - if (sc->sc_bdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf); + if (sc->beacon.bdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); /* cleanup tx descriptors */ - if (sc->sc_txdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); + if (sc->tx.txdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); return 0; } @@ -1927,15 +1927,15 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) */ return NULL; } - if (qnum >= ARRAY_SIZE(sc->sc_txq)) { + if (qnum >= ARRAY_SIZE(sc->tx.txq)) { DPRINTF(sc, ATH_DBG_FATAL, "qnum %u out of range, max %u!\n", - qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq)); + qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); ath9k_hw_releasetxqueue(ah, qnum); return NULL; } if (!ATH_TXQ_SETUP(sc, qnum)) { - struct ath_txq *txq = &sc->sc_txq[qnum]; + struct ath_txq *txq = &sc->tx.txq[qnum]; txq->axq_qnum = qnum; txq->axq_link = NULL; @@ -1946,9 +1946,9 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_aggr_depth = 0; txq->axq_totalqueued = 0; txq->axq_linkbuf = NULL; - sc->sc_txqsetup |= 1<tx.txqsetup |= 1<sc_txq[qnum]; + return &sc->tx.txq[qnum]; } /* Reclaim resources for a setup queue */ @@ -1956,7 +1956,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) { ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); - sc->sc_txqsetup &= ~(1<axq_qnum); + sc->tx.txqsetup &= ~(1<axq_qnum); } /* @@ -1973,15 +1973,15 @@ int ath_tx_setup(struct ath_softc *sc, int haltype) { struct ath_txq *txq; - if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { DPRINTF(sc, ATH_DBG_FATAL, "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->sc_haltype2q)); + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return 0; } txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); if (txq != NULL) { - sc->sc_haltype2q[haltype] = txq->axq_qnum; + sc->tx.hwq_map[haltype] = txq->axq_qnum; return 1; } else return 0; @@ -1993,19 +1993,19 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) switch (qtype) { case ATH9K_TX_QUEUE_DATA: - if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { DPRINTF(sc, ATH_DBG_FATAL, "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->sc_haltype2q)); + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return -1; } - qnum = sc->sc_haltype2q[haltype]; + qnum = sc->tx.hwq_map[haltype]; break; case ATH9K_TX_QUEUE_BEACON: - qnum = sc->sc_bhalq; + qnum = sc->beacon.beaconq; break; case ATH9K_TX_QUEUE_CAB: - qnum = sc->sc_cabq->axq_qnum; + qnum = sc->beacon.cabq->axq_qnum; break; default: qnum = -1; @@ -2021,7 +2021,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) int qnum; qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[qnum]; + txq = &sc->tx.txq[qnum]; spin_lock_bh(&txq->axq_lock); @@ -2050,17 +2050,17 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int error = 0; struct ath9k_tx_queue_info qi; - if (qnum == sc->sc_bhalq) { + if (qnum == sc->beacon.beaconq) { /* * XXX: for beacon queue, we just save the parameter. * It will be picked up by ath_beaconq_config when * it's necessary. */ - sc->sc_beacon_qi = *qinfo; + sc->beacon.beacon_qi = *qinfo; return 0; } - ASSERT(sc->sc_txq[qnum].axq_qnum == qnum); + ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); ath9k_hw_get_txq_props(ah, qnum, &qi); qi.tqi_aifs = qinfo->tqi_aifs; @@ -2083,7 +2083,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int ath_cabq_update(struct ath_softc *sc) { struct ath9k_tx_queue_info qi; - int qnum = sc->sc_cabq->axq_qnum; + int qnum = sc->beacon.cabq->axq_qnum; struct ath_beacon_config conf; ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); @@ -2117,7 +2117,7 @@ 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))) - ath_tx_processq(sc, &sc->sc_txq[i]); + ath_tx_processq(sc, &sc->tx.txq[i]); } } @@ -2149,9 +2149,9 @@ void ath_tx_draintxq(struct ath_softc *sc, list_del(&bf->list); spin_unlock_bh(&txq->axq_lock); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); continue; } @@ -2189,9 +2189,9 @@ 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_flags & SC_OP_INVALID)) { - (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n", - ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); + ath9k_hw_gettxbuf(sc->sc_ah, sc->beacon.beaconq)); } ath_drain_txdataq(sc, retry_tx); @@ -2199,12 +2199,12 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) u32 ath_txq_depth(struct ath_softc *sc, int qnum) { - return sc->sc_txq[qnum].axq_depth; + return sc->tx.txq[qnum].axq_depth; } u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum) { - return sc->sc_txq[qnum].axq_aggr_depth; + return sc->tx.txq[qnum].axq_aggr_depth; } bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) @@ -2285,7 +2285,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) { struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); @@ -2467,7 +2467,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) struct ath_txq *txq; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->sc_txq[i]; + txq = &sc->tx.txq[i]; spin_lock(&txq->axq_lock); @@ -2512,9 +2512,9 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) 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; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } /* Add the padding after the header if this is not already done */ @@ -2530,7 +2530,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, hdrlen); } - txctl.txq = sc->sc_cabq; + txctl.txq = sc->beacon.cabq; DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); -- cgit v1.1 From 6fb532527e2592f82ec07508df2e44f6c7ceff12 Mon Sep 17 00:00:00 2001 From: Anna Neal Date: Tue, 9 Dec 2008 13:23:45 -0800 Subject: libertas: Create sysfs entry for changing the mesh probe response limit This patch adds the ability to change the number of probe response retries sent by the mesh interface. In dense networks it is recommended to change this value to zero to reduce traffic congestion. Signed-off-by: Anna Neal Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/host.h | 1 + drivers/net/wireless/libertas/main.c | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index a17b778..277ff19 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -245,6 +245,7 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_ROUTE_EXP, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_ACT_MESH_GET_AUTOSTART_ENABLED, + CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17, }; /* Define actions and types for CMD_MESH_CONFIG */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 241af7f..3dba836 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -257,6 +257,58 @@ static ssize_t lbs_anycast_set(struct device *dev, return strlen(buf); } +/** + * @brief Get function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); + struct cmd_ds_mesh_access mesh_access; + int ret; + u32 retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + retry_limit = le32_to_cpu(mesh_access.data[1]); + return snprintf(buf, 10, "%d\n", retry_limit); +} + +/** + * @brief Set function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); + struct cmd_ds_mesh_access mesh_access; + int ret; + unsigned long retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); + + if (!strict_strtoul(buf, 10, &retry_limit)) + return -ENOTSUPP; + if (retry_limit > 15) + return -ENOTSUPP; + + mesh_access.data[1] = cpu_to_le32(retry_limit); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + return strlen(buf); +} + static int lbs_add_rtap(struct lbs_private *priv); static void lbs_remove_rtap(struct lbs_private *priv); static int lbs_add_mesh(struct lbs_private *priv); @@ -375,8 +427,16 @@ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); */ static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); +/** + * prb_rsp_limit attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/prb_rsp_limit) + */ +static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, + lbs_prb_rsp_limit_set); + static struct attribute *lbs_mesh_sysfs_entries[] = { &dev_attr_anycast_mask.attr, + &dev_attr_prb_rsp_limit.attr, NULL, }; -- cgit v1.1 From f2f1ba253d970479343f97c4620e16842c695d03 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Thu, 11 Dec 2008 14:29:06 +0200 Subject: iwlwifi: fix build warning (iwl-rx.c) This patch fixes the following build warning when CONFIG_IWLWIFI_DEBUG is not set. /work/src/wireless-testing/drivers/net/wireless/iwlwifi/iwl-rx.c:758: warning: 'iwl_dbg_report_frame' defined but not used Signed-off-by: Rami Rosen Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 096523200..71a2a51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -751,12 +751,6 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, if (print_dump) iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } -#else -static void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_phy_res *phy_res, u16 length, - struct ieee80211_hdr *header, int group100) -{ -} #endif static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -- cgit v1.1 From 9c5f89b3f6580cca21dca4ede940900c5b3c3a81 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 11 Dec 2008 18:22:13 +0200 Subject: ath9k: Do not remove header padding on RX from short frames The 802.11 header is only padded to 32-bit boundary when the frame has a non-zero length payload. In other words, control frames (e.g., ACK) do not have a padding and we should not try to remove it. This fixes monitor mode for short control frames. In addition, the hdrlen&3 use is described in more detail to make it easier to understand how the padding length is calculated. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/recv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index cb449f0..f2327d8 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -571,8 +571,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) hdr = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - padsize = hdrlen % 4; + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { memmove(skb->data + padsize, skb->data, hdrlen); skb_pull(skb, padsize); } -- cgit v1.1 From 3d5717ade01ce22511f2992f150bf6644b21c377 Mon Sep 17 00:00:00 2001 From: "Zhu, Yi" Date: Thu, 11 Dec 2008 10:33:36 -0800 Subject: iwlwifi: use iwl_poll_direct_bit in EEPROM reading The patch replaces the current reading EEPROM loop iterations with iwl_poll_direct_bit(). It also fixes some comment error. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 1 - drivers/net/wireless/iwlwifi/iwl-csr.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 23 +++++++++------------ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 7 ++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 31 +++++++++++++---------------- 5 files changed, 27 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 15570e6..94ea0e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -103,7 +103,6 @@ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. */ #define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ /* * Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags. diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index b834e21..f34ede4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -216,6 +216,8 @@ /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define CSR_EEPROM_REG_BIT_CMD (0x00000002) +#define CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC) +#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ #define CSR_EEPROM_GP_VALID_MSK (0x00000006) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index a47fa38..ce2f473 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -209,10 +209,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) { u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - u32 r; int sz = priv->cfg->eeprom_size; int ret; - int i; u16 addr; /* allocate eeprom */ @@ -240,22 +238,19 @@ int iwl_eeprom_init(struct iwl_priv *priv) /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); - - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { IWL_ERROR("Time out reading EEPROM[%d]\n", addr); - ret = -ETIMEDOUT; goto done; } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } ret = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 4b9de7a..603c84b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -68,17 +68,14 @@ struct iwl_priv; /* * EEPROM access time values: * - * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, - * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit - * CSR_EEPROM_REG_BIT_CMD (0x2). + * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG. * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. */ #define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ -#define IWL_EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */ #define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f883006..9f0db4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1504,10 +1504,8 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) { u16 *e = (u16 *)&priv->eeprom; u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP); - u32 r; int sz = sizeof(priv->eeprom); - int rc; - int i; + int ret; u16 addr; /* The EEPROM structure has several padding buffers within it @@ -1522,29 +1520,28 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - rc = iwl3945_eeprom_acquire_semaphore(priv); - if (rc < 0) { + ret = iwl3945_eeprom_acquire_semaphore(priv); + if (ret < 0) { IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); return -ENOENT; } /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + u32 r; - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } - - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + _iwl3945_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + ret = iwl3945_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { IWL_ERROR("Time out reading EEPROM[%d]\n", addr); - return -ETIMEDOUT; + return ret; } + + r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } -- cgit v1.1 From edb342286e18c5bec6d3ac325851a9cba28061b9 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Thu, 11 Dec 2008 10:33:37 -0800 Subject: iwlwifi: fix resume while txpower off This patch take care of coming out rfkill when the driver is up while rfkill is on by restarting interface. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-core.c | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 06e2682..cc4b6eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1402,8 +1402,11 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * the driver as well won't allow loading if RFKILL is set * therefore no need to restart the driver from this handler */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { clear_bit(STATUS_RF_KILL_HW, &priv->status); + if (priv->is_open && !iwl_is_rfkill(priv)) + queue_work(priv->workqueue, &priv->up); + } handled |= CSR_INT_BIT_RF_KILL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6fc3950..ced7911 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1446,6 +1446,16 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) return 0; } + /* when driver is up while rfkill is on, it wont receive + * any CARD_STATE_NOTIFICATION notifications so we have to + * restart it in here + */ + if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { + clear_bit(STATUS_RF_KILL_SW, &priv->status); + if (!iwl_is_rfkill(priv)) + queue_work(priv->workqueue, &priv->up); + } + /* If the driver is already loaded, it will receive * CARD_STATE_NOTIFICATION notifications and the handler will * call restart to reload the driver. -- cgit v1.1 From 29d51d9df53a4b383e2062b2ea0d575c9f3fca47 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Dec 2008 10:33:38 -0800 Subject: iwlwifi: remove unused clip_groups priv member Remove clip_groups from priv and related structure. This code is for 3945 only and was renamed to 4965 in when code was split. Also remove unused RATE definitions Signed-off-by: Tomas Winkler Acked-by: Samuel Ortiz Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-dev.h | 10 ---------- 2 files changed, 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 9873613..6649f7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -84,12 +84,6 @@ #define IWL_CMD_FIFO_NUM 4 #define IWL49_FIRST_AMPDU_QUEUE 7 -/* Tx rates */ -#define IWL_CCK_RATES 4 -#define IWL_OFDM_RATES 8 -#define IWL_HT_RATES 16 -#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) - /* Time constants */ #define SHORT_SLOT_TIME 9 #define LONG_SLOT_TIME 20 diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index fc859f7..a520e47 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -186,12 +186,6 @@ struct iwl_channel_info { u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ }; -struct iwl4965_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - #define IWL_TX_FIFO_AC0 0 #define IWL_TX_FIFO_AC1 1 @@ -793,10 +787,6 @@ struct iwl_priv { struct iwl_channel_info *channel_info; /* channel info array */ u8 channel_count; /* # of channels */ - /* each calibration channel group in the EEPROM has a derived - * clip setting for each rate. */ - const struct iwl4965_clip_group clip_groups[5]; - /* thermal calibration */ s32 temperature; /* degrees Kelvin */ s32 last_temperature; -- cgit v1.1 From b5047f78664fbcc18d67dafbb45bf62b310f9b0a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Dec 2008 10:33:39 -0800 Subject: iwlwifi: remove includes of iwl-helpers.h where not needed This patch removes includes of iwl-helpers.h where not needed Signed-off-by: Tomas Winkler Acked-by: Samuel Ortiz Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ++++ drivers/net/wireless/iwlwifi/iwl-helpers.h | 2 -- drivers/net/wireless/iwlwifi/iwl-led.c | 1 - drivers/net/wireless/iwlwifi/iwl-power.c | 1 - drivers/net/wireless/iwlwifi/iwl-rfkill.c | 2 -- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 -- 7 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a21875d..37b8920 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -38,7 +38,6 @@ #include "iwl-dev.h" #include "iwl-sta.h" #include "iwl-core.h" -#include "iwl-helpers.h" #define RS_NAME "iwl-agn-rs" diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a520e47..664a983 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -498,6 +498,10 @@ struct iwl_sensitivity_ranges { #define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) +#define KELVIN_TO_CELSIUS(x) ((x)-273) +#define CELSIUS_TO_KELVIN(x) ((x)+273) + + /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index d4d2829..ca4f638 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -32,8 +32,6 @@ #include -#define KELVIN_TO_CELSIUS(x) ((x)-273) -#define CELSIUS_TO_KELVIN(x) ((x)+273) #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index e8ce188..dce32ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -41,7 +41,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-helpers.h" #ifdef CONFIG_IWLWIFI_DEBUG static const char *led_type_str[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index be8eb95..75ca6a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -39,7 +39,6 @@ #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" -#include "iwl-helpers.h" /* * Setting power level allow the card to go to sleep when not busy diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 7894f2d..4b69da3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -34,8 +34,6 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-helpers.h" - /* software rf-kill from user */ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index a803cfa..412f66b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -33,8 +33,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-sta.h" -#include "iwl-helpers.h" - #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ -- cgit v1.1 From 2aa6ab86bc475a115f56645591d2413981846509 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Dec 2008 10:33:40 -0800 Subject: iwlwifi: remove 4965 from common uCode API structures This patch removes 4965 from common uCode API structures. Also updates iwlagn commands with 3945 specific RX command in preparation for 3945 port. Signed-off-by: Tomas Winkler Acked-by: Samuel Ortiz Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 11 ++--- drivers/net/wireless/iwlwifi/iwl-commands.h | 67 ++++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-spectrum.c | 2 +- 5 files changed, 42 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cc4b6eb..41fc41b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -310,7 +310,7 @@ void iwl_update_chain_flags(struct iwl_priv *priv) static int iwl_send_bt_config(struct iwl_priv *priv) { - struct iwl4965_bt_cmd bt_cmd = { + struct iwl_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, @@ -319,7 +319,7 @@ static int iwl_send_bt_config(struct iwl_priv *priv) }; return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl4965_bt_cmd), &bt_cmd); + sizeof(struct iwl_bt_cmd), &bt_cmd); } static void iwl_clear_free_frames(struct iwl_priv *priv) @@ -857,7 +857,7 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; - struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); rxon->channel = csa->channel; @@ -869,7 +869,7 @@ static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX("sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); #endif @@ -939,7 +939,8 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); + struct iwl4965_beacon_notif *beacon = + (struct iwl4965_beacon_notif *)pkt->u.raw; u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); IWL_DEBUG_RX("beacon status %x retries %d iss %d " diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0ba325d..60e79d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -94,6 +94,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ + REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, @@ -701,7 +702,7 @@ struct iwl_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl4965_channel_switch_cmd { +struct iwl_channel_switch_cmd { u8 band; u8 expect_beacon; __le16 channel; @@ -714,7 +715,7 @@ struct iwl4965_channel_switch_cmd { /* * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) */ -struct iwl4965_csa_notification { +struct iwl_csa_notification { __le16 band; __le16 channel; __le32 status; /* 0 - OK, 1 - fail */ @@ -1237,7 +1238,7 @@ struct iwl4965_rx_mpdu_res_start { * Used for managing Tx retries when expecting block-acks. * Driver should set these fields to 0. */ -struct iwl4965_dram_scratch { +struct iwl_dram_scratch { u8 try_cnt; /* Tx attempts */ u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */ __le16 reserved; @@ -1268,9 +1269,9 @@ struct iwl_tx_cmd { __le32 tx_flags; /* TX_CMD_FLG_* */ - /* 4965's uCode may modify this field of the Tx command (in host DRAM!). + /* uCode may modify this field of the Tx command (in host DRAM!). * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */ - struct iwl4965_dram_scratch scratch; + struct iwl_dram_scratch scratch; /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */ __le32 rate_n_flags; /* RATE_MCS_* */ @@ -1878,7 +1879,7 @@ struct iwl_link_quality_cmd { * same platform. Bluetooth device alerts wireless device when it will Tx; * wireless device can delay or kill its own Tx to accommodate. */ -struct iwl4965_bt_cmd { +struct iwl_bt_cmd { u8 flags; u8 lead_time; u8 max_kill; @@ -1904,18 +1905,18 @@ struct iwl4965_bt_cmd { RXON_FILTER_ASSOC_MSK | \ RXON_FILTER_BCON_AWARE_MSK) -struct iwl4965_measure_channel { +struct iwl_measure_channel { __le32 duration; /* measurement duration in extended beacon * format */ u8 channel; /* channel to measure */ - u8 type; /* see enum iwl4965_measure_type */ + u8 type; /* see enum iwl_measure_type */ __le16 reserved; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) */ -struct iwl4965_spectrum_cmd { +struct iwl_spectrum_cmd { __le16 len; /* number of bytes starting from token */ u8 token; /* token id */ u8 id; /* measurement id -- 0 or 1 */ @@ -1928,13 +1929,13 @@ struct iwl4965_spectrum_cmd { __le32 filter_flags; /* rxon filter flags */ __le16 channel_count; /* minimum 1, maximum 10 */ __le16 reserved3; - struct iwl4965_measure_channel channels[10]; + struct iwl_measure_channel channels[10]; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) */ -struct iwl4965_spectrum_resp { +struct iwl_spectrum_resp { u8 token; u8 id; /* id of the prior command replaced, or 0xff */ __le16 status; /* 0 - command will be handled @@ -1942,12 +1943,12 @@ struct iwl4965_spectrum_resp { * measurement) */ } __attribute__ ((packed)); -enum iwl4965_measurement_state { +enum iwl_measurement_state { IWL_MEASUREMENT_START = 0, IWL_MEASUREMENT_STOP = 1, }; -enum iwl4965_measurement_status { +enum iwl_measurement_status { IWL_MEASUREMENT_OK = 0, IWL_MEASUREMENT_CONCURRENT = 1, IWL_MEASUREMENT_CSA_CONFLICT = 2, @@ -1960,18 +1961,18 @@ enum iwl4965_measurement_status { #define NUM_ELEMENTS_IN_HISTOGRAM 8 -struct iwl4965_measurement_histogram { +struct iwl_measurement_histogram { __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ } __attribute__ ((packed)); /* clear channel availability counters */ -struct iwl4965_measurement_cca_counters { +struct iwl_measurement_cca_counters { __le32 ofdm; __le32 cck; } __attribute__ ((packed)); -enum iwl4965_measure_type { +enum iwl_measure_type { IWL_MEASURE_BASIC = (1 << 0), IWL_MEASURE_CHANNEL_LOAD = (1 << 1), IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), @@ -1984,7 +1985,7 @@ enum iwl4965_measure_type { /* * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) */ -struct iwl4965_spectrum_notification { +struct iwl_spectrum_notification { u8 id; /* measurement id -- 0 or 1 */ u8 token; u8 channel_index; /* index in measurement channel list */ @@ -1992,7 +1993,7 @@ struct iwl4965_spectrum_notification { __le32 start_time; /* lower 32-bits of TSF */ u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ u8 channel; - u8 type; /* see enum iwl4965_measurement_type */ + u8 type; /* see enum iwl_measurement_type */ u8 reserved1; /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only * valid if applicable for measurement type requested. */ @@ -2002,9 +2003,9 @@ struct iwl4965_spectrum_notification { u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - * unidentified */ u8 reserved2[3]; - struct iwl4965_measurement_histogram histogram; + struct iwl_measurement_histogram histogram; __le32 stop_time; /* lower 32-bits of TSF */ - __le32 status; /* see iwl4965_measurement_status */ + __le32 status; /* see iwl_measurement_status */ } __attribute__ ((packed)); /****************************************************************************** @@ -2062,7 +2063,7 @@ struct iwl_powertable_cmd { * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) * 3945 and 4965 identical. */ -struct iwl4965_sleep_notification { +struct iwl_sleep_notification { u8 pm_sleep_mode; u8 pm_wakeup_src; __le16 reserved; @@ -2092,14 +2093,14 @@ enum { #define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ #define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ #define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ -struct iwl4965_card_state_cmd { +struct iwl_card_state_cmd { __le32 status; /* CARD_STATE_CMD_* request new power state */ } __attribute__ ((packed)); /* * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) */ -struct iwl4965_card_state_notif { +struct iwl_card_state_notif { __le32 flags; } __attribute__ ((packed)); @@ -2162,7 +2163,7 @@ struct iwl_scan_channel { * struct iwl_ssid_ie - directed scan network information element * * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field - * in struct iwl4965_scan_channel; each channel may select different ssids from + * in struct iwl_scan_channel; each channel may select different ssids from * among the 4 entries. SSID IEs get transmitted in reverse order of entry. */ struct iwl_ssid_ie { @@ -2262,7 +2263,7 @@ struct iwl_scan_cmd { * Number of channels in list is specified by channel_count. * Each channel in list is of type: * - * struct iwl4965_scan_channel channels[0]; + * struct iwl_scan_channel channels[0]; * * NOTE: Only one band of channels can be scanned per pass. You * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait @@ -2573,7 +2574,7 @@ struct iwl_notif_statistics { * then this notification will be sent. */ #define CONSECUTIVE_MISSED_BCONS_TH 20 -struct iwl4965_missed_beacon_notif { +struct iwl_missed_beacon_notif { __le32 consequtive_missed_beacons; __le32 total_missed_becons; __le32 num_expected_beacons; @@ -3010,19 +3011,17 @@ struct iwl_rx_packet { struct iwl_cmd_header hdr; union { struct iwl_alive_resp alive_frame; - struct iwl4965_tx_resp tx_resp; - struct iwl4965_spectrum_notification spectrum_notif; - struct iwl4965_csa_notification csa_notif; + struct iwl_spectrum_notification spectrum_notif; + struct iwl_csa_notification csa_notif; struct iwl_error_resp err_resp; - struct iwl4965_card_state_notif card_state_notif; - struct iwl4965_beacon_notif beacon_status; + struct iwl_card_state_notif card_state_notif; struct iwl_add_sta_resp add_sta; struct iwl_rem_sta_resp rem_sta; - struct iwl4965_sleep_notification sleep_notif; - struct iwl4965_spectrum_resp spectrum; + struct iwl_sleep_notification sleep_notif; + struct iwl_spectrum_resp spectrum; struct iwl_notif_statistics stats; struct iwl_compressed_ba_resp compressed_ba; - struct iwl4965_missed_beacon_notif missed_beacon; + struct iwl_missed_beacon_notif missed_beacon; __le32 status; u8 raw[0]; } u; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 664a983..eaf0c9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -780,7 +780,7 @@ struct iwl_priv { #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ - struct iwl4965_spectrum_notification measure_report; + struct iwl_spectrum_notification measure_report; u8 measurement_status; #endif /* ucode beacon time */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 71a2a51..919a775 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -482,7 +482,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_missed_beacon_notif *missed_beacon; + struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c index a9a1897..836c3c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -178,7 +178,7 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { IWL_DEBUG(IWL_DL_11H, -- cgit v1.1 From a7b75207bd37cbbfa0b4ee7dbaf0dc6bafec8fea Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Dec 2008 10:33:41 -0800 Subject: iwlwifi: add contact email to MODULE_AUTHOR Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 41fc41b..2f5e86e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -83,7 +83,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); MODULE_ALIAS("iwl4965"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ced7911..73d7973 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -42,7 +42,7 @@ MODULE_DESCRIPTION("iwl core"); MODULE_VERSION(IWLWIFI_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 72f82ec..08b842f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -72,6 +72,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "1.3.27k" #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" +#define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9f0db4f..352ccac 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -93,12 +93,13 @@ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */ #define IWLWIFI_VERSION "1.2.26k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" +#define DRV_AUTHOR "" #define DRV_VERSION IWLWIFI_VERSION MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); static const struct ieee80211_supported_band *iwl3945_get_band( -- cgit v1.1 From b88a2a22c6670c31586d1a716255eae4c320b363 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Thu, 18 Dec 2008 19:36:46 -0800 Subject: netdevice zd1201: Use after free | commit 3d29b0c33d431ecc69ec778f8c236d382f59a85f | Author: John W. Linville | Date: Fri Oct 31 14:13:12 2008 -0400 | | netdevice zd1201: Convert directly reference of netdev->priv to netdev_priv() | | We have some reasons to kill netdev->priv: | 1. netdev->priv is equal to netdev_priv(). | 2. netdev_priv() wraps the calculation of netdev->priv's offset, obviously | netdev_priv() is more flexible than netdev->priv. | But we cann't kill netdev->priv, because so many drivers reference to it | directly. | | OK, becasue Dave S. Miller said, "every direct netdev->priv usage is a bug", | and I want to kill netdev->priv later, I decided to convert all the direct | reference of netdev->priv first. | | (Original patch posted by Wang Chen w/ above | changelog but using dev->ml_priv. That doesn't seem appropriate | to me for this driver, so I've revamped it to use netdev_priv() | instead. -- JWL) This commit changed the allocation of netdev, but didn't change the free method of it. This causes "zd" be used after the memory, which is pointed by "zd", being freed by free_netdev(). Signed-off-by: Wang Chen Signed-off-by: David S. Miller --- drivers/net/wireless/zd1201.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 3404807..b45c27d 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -1841,10 +1841,6 @@ static void zd1201_disconnect(struct usb_interface *interface) if (!zd) return; usb_set_intfdata(interface, NULL); - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) { hlist_del_init(&frag->fnode); @@ -1860,7 +1856,11 @@ static void zd1201_disconnect(struct usb_interface *interface) usb_kill_urb(zd->rx_urb); usb_free_urb(zd->rx_urb); } - kfree(zd); + + if (zd->dev) { + unregister_netdev(zd->dev); + free_netdev(zd->dev); + } } #ifdef CONFIG_PM -- cgit v1.1 From 094d05dc32fc2930e381189a942016e5561775d9 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 12 Dec 2008 11:57:43 +0530 Subject: mac80211: Fix HT channel selection HT management is done differently for AP and STA modes, unify to just the ->config() callback since HT is fundamentally a PHY property and cannot be per-BSS. Rename enum nl80211_sec_chan_offset as nl80211_channel_type to denote the channel type ( NO_HT, HT20, HT40+, HT40- ). Signed-off-by: Johannes Berg Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 123 ++++++++------------------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 18 +++-- drivers/net/wireless/mac80211_hwsim.c | 6 +- 3 files changed, 44 insertions(+), 103 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 02e1771..e22fea1 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -623,37 +623,40 @@ static int ath_get_channel(struct ath_softc *sc, return -1; } -/* ext_chan_offset: (-1, 0, 1) (below, none, above) */ - static u32 ath_get_extchanmode(struct ath_softc *sc, struct ieee80211_channel *chan, - int ext_chan_offset, - enum ath9k_ht_macmode tx_chan_width) + enum nl80211_channel_type channel_type) { u32 chanmode = 0; switch (chan->band) { case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == 0) && - (tx_chan_width == ATH9K_HT_MACMODE_20)) + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: chanmode = CHANNEL_G_HT20; - if ((ext_chan_offset == 1) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40PLUS: chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == -1) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40MINUS: chanmode = CHANNEL_G_HT40MINUS; + break; + } break; case IEEE80211_BAND_5GHZ: - if ((ext_chan_offset == 0) && - (tx_chan_width == ATH9K_HT_MACMODE_20)) + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: chanmode = CHANNEL_A_HT20; - if ((ext_chan_offset == 1) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40PLUS: chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == -1) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40MINUS: chanmode = CHANNEL_A_HT40MINUS; + break; + } break; default: break; @@ -829,45 +832,15 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } -static void ath9k_ht_conf(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) -{ - if (sc->hw->conf.ht.enabled) { - if (bss_conf->ht.width_40_ok) - sc->tx_chan_width = ATH9K_HT_MACMODE_2040; - else - sc->tx_chan_width = ATH9K_HT_MACMODE_20; - - ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width); - - DPRINTF(sc, ATH_DBG_CONFIG, - "BSS Changed HT, chanwidth: %d\n", sc->tx_chan_width); - } -} - -static inline int ath_sec_offset(u8 ext_offset) -{ - if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) - return 0; - else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) - return 1; - else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) - return -1; - - return 0; -} - static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; struct ath_vap *avp = (void *)vif->drv_priv; - int pos; if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d\n", bss_conf->aid); + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, sc->sc_curbssid); /* New association, store aid */ if (avp->av_opmode == NL80211_IFTYPE_STATION) { @@ -886,40 +859,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; - /* Update chainmask */ - ath_update_chainmask(sc, hw->conf.ht.enabled); - - DPRINTF(sc, ATH_DBG_CONFIG, - "bssid %pM aid 0x%x\n", - sc->sc_curbssid, sc->sc_curaid); - - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "Invalid channel: %d\n", curchan->center_freq); - return; - } - - if (hw->conf.ht.enabled) { - int offset = - ath_sec_offset(bss_conf->ht.secondary_channel_offset); - sc->tx_chan_width = (bss_conf->ht.width_40_ok) ? - ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; - - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan, - offset, sc->tx_chan_width); - } else { - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; - } - - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel: %d\n", - curchan->center_freq); - /* Start ANI */ mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -2146,7 +2085,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_softc *sc = hw->priv; struct ieee80211_conf *conf = &hw->conf; - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_HT)) { struct ieee80211_channel *curchan = hw->conf.channel; int pos; @@ -2165,25 +2105,23 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; - if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) && - (conf->ht.enabled)) { - sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ? - ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; + if (conf->ht.enabled) { + if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS || + conf->ht.channel_type == NL80211_CHAN_HT40MINUS) + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; sc->sc_ah->ah_channels[pos].chanmode = ath_get_extchanmode(sc, curchan, - conf->ht.sec_chan_offset, - sc->tx_chan_width); + conf->ht.channel_type); } if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); return -EINVAL; } - } - if (changed & IEEE80211_CONF_CHANGE_HT) ath_update_chainmask(sc, conf->ht.enabled); + } if (changed & IEEE80211_CONF_CHANGE_POWER) sc->sc_config.txpowlimit = 2 * conf->power_level; @@ -2417,9 +2355,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_HT) - ath9k_ht_conf(sc, bss_conf); - if (changed & BSS_CHANGED_ASSOC) { DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2f5e86e..bbc1c80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -515,19 +515,27 @@ static void iwl_ht_conf(struct iwl_priv *priv, iwl_conf->supported_chan_width = !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset; + /* + * XXX: The HT configuration needs to be moved into iwl_mac_config() + * to be done there correctly. + */ + + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + /* If no above or below channel supplied disable FAT channel */ if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) iwl_conf->supported_chan_width = 0; - } iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok; + iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index fd5a537..f83d69e 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -495,11 +495,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - printk(KERN_DEBUG " %s: HT: sec_ch_offs=%d width_40_ok=%d " - "op_mode=%d\n", + printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", wiphy_name(hw->wiphy), - info->ht.secondary_channel_offset, - info->ht.width_40_ok, info->ht.operation_mode); + info->ht.operation_mode); } if (changed & BSS_CHANGED_BASIC_RATES) { -- cgit v1.1 From 9d8eed12dbc04f8ed70090da14211c808b5a8d81 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 12 Dec 2008 11:59:07 +0530 Subject: ath9k: Do not use association state to update rate table Now that HT information is made available to the driver through config() callback, the channel type can be calculated whenever setting the channel. Update the rate table accordingly with the new channel type. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index e22fea1..550afbe 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -61,8 +61,7 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz) static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { - if (!sc->sc_curaid) - sc->cur_rate_table = sc->hw_rate_table[mode]; + sc->cur_rate_table = sc->hw_rate_table[mode]; /* * All protection frames are transmited at 2Mb/s for * 11g, otherwise at 1Mb/s. -- cgit v1.1 From baad1d921b1565b6f08f60c035531d13ad8afa82 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 12 Dec 2008 14:38:34 +0200 Subject: ath9k: Report HT rates in RX status Fix and clean up the RX status reporting by getting rid of code that used internal rate tables and ratekbps calculation. The correct value is now reported with MCS index instead of the old mechanism that defaulted to using the highest legacy rate. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/recv.c | 61 +++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index f2327d8..cc160fe 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -111,33 +111,6 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) return skb; } -static int ath_rate2idx(struct ath_softc *sc, int rate) -{ - int i = 0, cur_band, n_rates; - struct ieee80211_hw *hw = sc->hw; - - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; - - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].bitrate == rate) - break; - } - - /* - * NB:mac80211 validates rx rate index against the supported legacy rate - * index only (should be done against ht rates also), return the highest - * legacy rate index for rx rate which does not match any one of the - * supported basic and extended rates to make mac80211 happy. - * The following hack will be cleaned up once the issue with - * the rx rate index validation in mac80211 is fixed. - */ - if (i == n_rates) - return n_rates - 1; - - return i; -} - /* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no @@ -147,9 +120,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, struct ieee80211_rx_status *rx_status, bool *decrypt_error, struct ath_softc *sc) { - struct ath_rate_table *rate_table = sc->cur_rate_table; struct ieee80211_hdr *hdr; - int ratekbps, rix; u8 ratecode; __le16 fc; @@ -204,15 +175,36 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } ratecode = ds->ds_rxstat.rs_rate; - rix = rate_table->rateCodeToIndex[ratecode]; - ratekbps = rate_table->info[rix].ratekbps; - /* HT rate */ if (ratecode & 0x80) { + /* HT rate */ + rx_status->flag |= RX_FLAG_HT; if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) - ratekbps = (ratekbps * 27) / 13; + rx_status->flag |= RX_FLAG_40MHZ; if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) - ratekbps = (ratekbps * 10) / 9; + rx_status->flag |= RX_FLAG_SHORT_GI; + rx_status->rate_idx = ratecode & 0x7f; + } else { + int i = 0, cur_band, n_rates; + struct ieee80211_hw *hw = sc->hw; + + cur_band = hw->conf.channel->band; + n_rates = sc->sbands[cur_band].n_bitrates; + + for (i = 0; i < n_rates; i++) { + if (sc->sbands[cur_band].bitrates[i].hw_value == + ratecode) { + rx_status->rate_idx = i; + break; + } + + if (sc->sbands[cur_band].bitrates[i].hw_value_short == + ratecode) { + rx_status->rate_idx = i; + rx_status->flag |= RX_FLAG_SHORTPRE; + break; + } + } } rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); @@ -220,7 +212,6 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, rx_status->freq = sc->hw->conf.channel->center_freq; rx_status->noise = sc->sc_ani.sc_noise_floor; rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; - rx_status->rate_idx = ath_rate2idx(sc, (ratekbps / 100)); rx_status->antenna = ds->ds_rxstat.rs_antenna; /* at 45 you will be able to use MCS 15 reliably. A more elaborate -- cgit v1.1 From 0fe45b1debba7302155b62f3829119a1185a4f5a Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Fri, 12 Dec 2008 15:29:58 +0100 Subject: ath5k: fix 802.11 header padding on RX, unpadding on TX Padding the 802.11 header to a multiple of 4 bytes needs to be done only for frames with a body. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames. Inspired by a patch from Jouni Malinen on ath9k. Ref: http://bugzilla.kernel.org/show_bug.cgi?id=12101 : Signed-off-by: Benoit Papillault Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 0e43170..9b5f31a 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1668,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data) struct ath5k_desc *ds; int ret; int hdrlen; - int pad; + int padsize; spin_lock(&sc->rxbuflock); if (list_empty(&sc->rxbuf)) { @@ -1753,16 +1753,19 @@ accept: skb_put(skb, rs.rs_datalen); - /* - * the hardware adds a padding to 4 byte boundaries between - * the header and the payload data if the header length is - * not multiples of 4 - remove it - */ + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - pad = hdrlen % 4; - memmove(skb->data + pad, skb->data, hdrlen); - skb_pull(skb, pad); + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } /* @@ -2623,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ath5k_buf *bf; unsigned long flags; int hdrlen; - int pad; + int padsize; ath5k_debug_dump_skb(sc, skb, "TX ", 1); @@ -2635,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * if this is not the case we add the padding after the header */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - pad = hdrlen % 4; - if (skb_headroom(skb) < pad) { + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + + if (skb_headroom(skb) < padsize) { ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" - " headroom to pad %d\n", hdrlen, pad); + " headroom to pad %d\n", hdrlen, padsize); return -1; } - skb_push(skb, pad); - memmove(skb->data, skb->data+pad, hdrlen); + skb_push(skb, padsize); + memmove(skb->data, skb->data+padsize, hdrlen); } spin_lock_irqsave(&sc->txbuflock, flags); -- cgit v1.1 From d5e490362feb648048ef20db9b0b2531d5425775 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 12 Dec 2008 08:22:15 -0800 Subject: iwlagn: fix agn rate scaling Rate scaling in agn can be broken because of these two problems 1- the LQ command could not sent, we try to call LQ command before post association will be rejected, this will cause the driver to break in rs_tx_status reporting initial rate does not match. 2- In rs_rate_init we can get a value of 12, rate 60, for last_txrate_idx, this rate only valid in SISO/MIMO mode only Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 37b8920..f3f1792 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -836,6 +836,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); + /* the last LQ command could failed so the LQ in ucode not + * the same in driver sync up + */ + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); goto out; } @@ -2167,6 +2171,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct iwl_lq_sta *lq_sta = priv_sta; + u16 mask_bit = 0; lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; @@ -2200,16 +2205,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, priv->assoc_station_added = 1; } - /* Find highest tx rate supported by hardware and destination station */ - lq_sta->last_txrate_idx = 3; - for (i = 0; i < sband->n_bitrates; i++) - if (sta->supp_rates[sband->band] & BIT(i)) - lq_sta->last_txrate_idx = i; - - /* For MODE_IEEE80211A, skip over cck rates in global rate table */ - if (sband->band == IEEE80211_BAND_5GHZ) - lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; - lq_sta->is_dup = 0; lq_sta->is_green = rs_use_green(priv, conf); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); @@ -2248,6 +2243,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; + /* Find highest tx rate supported by hardware and destination station */ + mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate; + lq_sta->last_txrate_idx = 3; + for (i = 0; i < sband->n_bitrates; i++) + if (mask_bit & BIT(i)) + lq_sta->last_txrate_idx = i; + + /* For MODE_IEEE80211A, skip over cck rates in global rate table */ + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + rs_initialize_lq(priv, conf, sta, lq_sta); } -- cgit v1.1 From 54fdb040b4760d5b2994d15c1371e297679420e9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 13 Dec 2008 14:14:20 +0100 Subject: p54: move statistic timer update routine into a workqueue This patch moves a good chunk of code from the former statistic update timer routine into a workqueue, which is kindly provided by mac80211. Also as a nice side-effect we can lay the foundation for other essential housekeeping features we want to do in the future. e.g: - drain the (clogged) tx_queue. - initiate bursts. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 5 +- drivers/net/wireless/p54/p54common.c | 104 ++++++++++++++++++++--------------- drivers/net/wireless/p54/p54common.h | 5 ++ 3 files changed, 68 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index d2dbb9e..23b80ef 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -71,6 +71,7 @@ struct p54_edcf_queue_param { #define FW_LM20 0x4c4d3230 struct p54_common { + struct ieee80211_hw *hw; u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; @@ -106,9 +107,7 @@ struct p54_common { struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; - struct timer_list stats_timer; - struct completion stats_comp; - struct sk_buff *cached_stats; + struct delayed_work work; struct sk_buff *cached_beacon; int noise; void *eeprom; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index a4e99b0..36310f8 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -589,6 +589,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) ieee80211_rx_irqsafe(dev, skb, &rx_status); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_STATISTICS_UPDATE)); + return -1; } @@ -652,6 +655,27 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(p54_free_skb); +static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, + __le32 req_id) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *entry = priv->tx_queue.next; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + while (entry != (struct sk_buff *)&priv->tx_queue) { + struct p54_hdr *hdr = (struct p54_hdr *) entry->data; + + if (hdr->req_id == req_id) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return entry; + } + entry = entry->next; + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return NULL; +} + static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; @@ -775,8 +799,12 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_common *priv = dev->priv; struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; - u32 tsf32 = le32_to_cpu(stats->tsf32); + u32 tsf32; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + tsf32 = le32_to_cpu(stats->tsf32); if (tsf32 < priv->tsf_low32) priv->tsf_high32++; priv->tsf_low32 = tsf32; @@ -786,9 +814,8 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); - complete(&priv->stats_comp); - mod_timer(&priv->stats_timer, jiffies + 5 * HZ); + p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); } static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) @@ -897,6 +924,8 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, * have a few spare slots for control frames left. */ ieee80211_stop_queues(dev); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_TIMEOUT)); if (unlikely(left == 32)) { /* @@ -1354,6 +1383,10 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) goto err; priv->tx(dev, skb, 0); + + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); + return 0; err: @@ -1579,20 +1612,6 @@ static int p54_set_edcf(struct ieee80211_hw *dev) return 0; } -static int p54_init_stats(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - - priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, - sizeof(struct p54_hdr) + sizeof(struct p54_statistics), - P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); - if (!priv->cached_stats) - return -ENOMEM; - - mod_timer(&priv->stats_timer, jiffies + HZ); - return 0; -} - static int p54_beacon_tim(struct sk_buff *skb) { /* @@ -1686,9 +1705,6 @@ static int p54_start(struct ieee80211_hw *dev) err = p54_set_edcf(dev); if (err) goto out; - err = p54_init_stats(dev); - if (err) - goto out; memset(priv->bssid, ~0, ETH_ALEN); priv->mode = NL80211_IFTYPE_MONITOR; @@ -1698,6 +1714,8 @@ static int p54_start(struct ieee80211_hw *dev) goto out; } + queue_delayed_work(dev->workqueue, &priv->work, 0); + out: mutex_unlock(&priv->conf_mutex); return err; @@ -1710,9 +1728,7 @@ static void p54_stop(struct ieee80211_hw *dev) mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; - del_timer(&priv->stats_timer); - p54_free_skb(dev, priv->cached_stats); - priv->cached_stats = NULL; + cancel_delayed_work_sync(&priv->work); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); @@ -1889,14 +1905,29 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) return 0; } -static void p54_statistics_timer(unsigned long data) +static void p54_work(struct work_struct *work) { - struct ieee80211_hw *dev = (struct ieee80211_hw *) data; - struct p54_common *priv = dev->priv; + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + struct ieee80211_hw *dev = priv->hw; + struct sk_buff *skb; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ - BUG_ON(!priv->cached_stats); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) + + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); + if (!skb) + return ; - priv->tx(dev, priv->cached_stats, 0); + priv->tx(dev, skb, 0); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1904,17 +1935,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - del_timer(&priv->stats_timer); - p54_statistics_timer((unsigned long)dev); - - if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { - printk(KERN_ERR "%s: device does not respond!\n", - wiphy_name(dev->wiphy)); - return -EBUSY; - } - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; } @@ -2072,6 +2093,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; + priv->hw = dev; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->basic_rate_mask = 0x15f; skb_queue_head_init(&priv->tx_queue); @@ -2107,9 +2129,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) mutex_init(&priv->conf_mutex); init_completion(&priv->eeprom_comp); - init_completion(&priv->stats_comp); - setup_timer(&priv->stats_timer, p54_statistics_timer, - (unsigned long)dev); + INIT_DELAYED_WORK(&priv->work, p54_work); return dev; } @@ -2118,8 +2138,6 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - del_timer(&priv->stats_timer); - kfree_skb(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 5a68fda..06e1643 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -355,6 +355,11 @@ struct p54_tx_data { u8 align[0]; } __attribute__ ((packed)); +/* unit is ms */ +#define P54_TX_FRAME_LIFETIME 2000 +#define P54_TX_TIMEOUT 4000 +#define P54_STATISTICS_UPDATE 5000 + #define P54_FILTER_TYPE_NONE 0 #define P54_FILTER_TYPE_STATION BIT(0) #define P54_FILTER_TYPE_IBSS BIT(1) -- cgit v1.1 From ee370ceda823435fe75be7dd4ed7b0e3dc3108b9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 13 Dec 2008 16:45:38 +0100 Subject: p54: update ACK failure statistic counter in real-time Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 36310f8..ddb8586 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -720,6 +720,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) entry_hdr = (struct p54_hdr *) entry->data; entry_data = (struct p54_tx_data *) entry_hdr->data; priv->tx_stats[entry_data->hw_queue].len--; + priv->stats.dot11ACKFailureCount += payload->tries - 1; if (unlikely(entry == priv->cached_beacon)) { kfree_skb(entry); -- cgit v1.1 From 23827926eb5ce5cb944ebbd96d22297a2582d45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Sat, 13 Dec 2008 21:33:13 +0200 Subject: libertas: use roundup instead of opencoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ilpo Järvinen Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b54e2ea..4519d73 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -26,6 +26,7 @@ * if_sdio_card_to_host() to pad the data. */ +#include #include #include #include @@ -581,7 +582,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card) chunk_size, (chunk_size + 31) / 32 * 32); */ ret = sdio_writesb(card->func, card->ioport, - chunk_buffer, (chunk_size + 31) / 32 * 32); + chunk_buffer, roundup(chunk_size, 32)); if (ret) goto release; -- cgit v1.1 From da9f57eade0a743450a201645db7fc5ac0809900 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 13 Dec 2008 18:09:56 -0600 Subject: rtl8187: Fix error returns There are two places in the rtl8187 code where a routine was returning zero (OK) when it should have been returning an error. Signed-off-by: Larry Finger Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 74f5449..3900c47 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -213,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { kfree_skb(skb); - return 0; + return -ENOMEM; } flags = skb->len; @@ -281,7 +281,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) } usb_free_urb(urb); - return 0; + return rc; } static void rtl8187_rx_cb(struct urb *urb) -- cgit v1.1 From 69ba3e5d74a467a64248cd90ccafb524b1fddcb5 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 14 Dec 2008 14:45:30 +0100 Subject: p54: more accurate rssi to dBm conversion This patch replaces the static rssi auto calibration data with more precise values out of the device's eeprom. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 8 +++++ drivers/net/wireless/p54/p54common.c | 69 ++++++++++++++++++++++++++---------- drivers/net/wireless/p54/p54common.h | 17 ++++----- 3 files changed, 68 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 23b80ef..e0a6881 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -61,6 +61,13 @@ struct p54_edcf_queue_param { __le16 txop; } __attribute__ ((packed)); +struct p54_rssi_linear_approximation { + s16 mul; + s16 add; + s16 longbow_unkn; + s16 longbow_unk2; +}; + #define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -91,6 +98,7 @@ struct p54_common { struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; + struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; unsigned int filter_flags; bool use_short_slot; u16 rxhw; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index ddb8586..05eb677 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -335,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; static int p54_init_xbow_synth(struct ieee80211_hw *dev); +static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, + u16 type) +{ + struct p54_common *priv = dev->priv; + int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; + int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; + int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; + int i; + + if (len != (entry_size * num_entries)) { + printk(KERN_ERR "%s: unknown rssi calibration data packing " + " type:(%x) len:%d.\n", + wiphy_name(dev->wiphy), type, len); + + print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + for (i = 0; i < num_entries; i++) { + struct pda_rssi_cal_entry *cal = data + + (offset + i * entry_size); + priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); + priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); + } +} + static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -434,6 +464,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_HARDWARE_PLATFORM_COMPONENT_ID: priv->version = *(u8 *)(entry->data + 1); break; + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + p54_parse_rssical(dev, entry->data, data_len, + le16_to_cpu(entry->code)); + break; case PDR_END: /* make it overrun */ entry_len = len; @@ -453,10 +489,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_DEFAULT_COUNTRY: case PDR_ANTENNA_GAIN: case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: - case PDR_RSSI_LINEAR_APPROXIMATION: - case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: case PDR_REGULATORY_POWER_LIMITS: - case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: case PDR_RADIATED_TRANSMISSION_CORRECTION: case PDR_PRISM_TX_IQ_CALIBRATION: case PDR_BASEBAND_REGISTERS: @@ -527,8 +560,11 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) { - /* TODO: get the rssi_add & rssi_mul data from the eeprom */ - return ((rssi * 0x83) / 64 - 400) / 4; + struct p54_common *priv = dev->priv; + int band = dev->conf.channel->band; + + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; } static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) @@ -1466,15 +1502,15 @@ static int p54_setup_mac(struct ieee80211_hw *dev) return 0; } -static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, - u16 frequency) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) { struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_scan *chan; unsigned int i; void *entry; - __le16 freq = cpu_to_le16(frequency); + __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); + int band = dev->conf.channel->band; skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, @@ -1535,11 +1571,11 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, } if (priv->fw_var < 0x500) { - chan->v1.rssical_mul = cpu_to_le16(130); - chan->v1.rssical_add = cpu_to_le16(0xfe70); + chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add); } else { - chan->v2.rssical_mul = cpu_to_le16(130); - chan->v2.rssical_add = cpu_to_le16(0xfe70); + chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add); chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(chan->v2.rts_rates, 0, 8); } @@ -1801,8 +1837,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) goto out; } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0, - conf->channel->center_freq); + ret = p54_scan(dev, P54_SCAN_EXIT, 0); if (ret) goto out; } @@ -1828,8 +1863,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, } if (conf->changed & IEEE80211_IFCC_BEACON) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0, - dev->conf.channel->center_freq); + ret = p54_scan(dev, P54_SCAN_EXIT, 0); if (ret) goto out; ret = p54_setup_mac(dev); @@ -1968,8 +2002,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->basic_rate_mask = info->basic_rates; p54_setup_mac(dev); if (priv->fw_var >= 0x500) - p54_scan(dev, P54_SCAN_EXIT, 0, - dev->conf.channel->center_freq); + p54_scan(dev, P54_SCAN_EXIT, 0); } if (changed & BSS_CHANGED_ASSOC) { if (info->assoc) { diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 06e1643..6c824e4 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -178,6 +178,11 @@ struct pda_pa_curve_data { u8 data[0]; } __attribute__ ((packed)); +struct pda_rssi_cal_entry { + __le16 mul; + __le16 add; +} __attribute__ ((packed)); + /* * this defines the PDR codes used to build PDAs as defined in document * number 553155. The current implementation mirrors version 1.1 of the @@ -429,22 +434,18 @@ struct p54_scan { u8 dup_16qam; u8 dup_64qam; union { - struct { - __le16 rssical_mul; - __le16 rssical_add; - } v1 __attribute__ ((packed)); + struct pda_rssi_cal_entry v1_rssi; struct { __le32 basic_rate_mask; u8 rts_rates[8]; - __le16 rssical_mul; - __le16 rssical_add; + struct pda_rssi_cal_entry rssi; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12) -#define P54_SCAN_V2_LEN (sizeof(struct p54_scan)) +#define P54_SCAN_V1_LEN 0x70 +#define P54_SCAN_V2_LEN 0x7c struct p54_led { __le16 mode; -- cgit v1.1 From 0a5ec96ad68516582023a877aceff9db7636d141 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 14 Dec 2008 15:05:42 +0100 Subject: p54: remove free_on_tx parameter This patch simplifies the tx code a bit and will be necessary for the upcoming stlc45xx<->p54 port. In detail: we no longer have to tell all back-end drivers directly, if we want to free a frame right after it was send to the firmware, or if we do it in the library callback later. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 10 ++++++++-- drivers/net/wireless/p54/p54common.c | 26 ++++++++++++------------- drivers/net/wireless/p54/p54common.h | 3 --- drivers/net/wireless/p54/p54pci.c | 12 +++++------- drivers/net/wireless/p54/p54usb.c | 37 +++++++++++------------------------- 5 files changed, 37 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index e0a6881..ab79e32 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -44,6 +44,9 @@ enum p54_control_frame_types { P54_CONTROL_TYPE_BT_OPTIONS = 35 }; +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + struct p54_hdr { __le16 flags; __le16 len; @@ -54,6 +57,10 @@ struct p54_hdr { u8 data[0]; } __attribute__ ((packed)); +#define FREE_AFTER_TX(skb) \ + ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) + struct p54_edcf_queue_param { __le16 aifs; __le16 cwmin; @@ -82,8 +89,7 @@ struct p54_common { u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; - void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx); + void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 05eb677..82354b9 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -683,7 +683,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) freed = priv->rx_end - last_addr; __skb_unlink(skb, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - kfree_skb(skb); + dev_kfree_skb_any(skb); if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) @@ -1088,7 +1088,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev) eeprom_hdr->v2.magic2 = 0xf; memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); } - priv->tx(dev, skb, 0); + priv->tx(dev, skb); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -1129,7 +1129,7 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); tim->count = 1; tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1147,7 +1147,7 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); memcpy(sta->addr, addr, ETH_ALEN); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1190,7 +1190,7 @@ static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) hdr = (void *)entry->data; cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); cancel->req_id = hdr->req_id; - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1419,7 +1419,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) /* modifies skb->cb and with it info, so must be last! */ if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) goto err; - priv->tx(dev, skb, 0); + priv->tx(dev, skb); queue_delayed_work(dev->workqueue, &priv->work, msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); @@ -1498,7 +1498,7 @@ static int p54_setup_mac(struct ieee80211_hw *dev) setup->v2.lpf_bandwidth = cpu_to_le16(65535); setup->v2.osc_start_delay = cpu_to_le16(65535); } - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1579,7 +1579,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); memset(chan->v2.rts_rates, 0, 8); } - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; err: @@ -1605,7 +1605,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); led->duration = cpu_to_le16(1000); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1645,7 +1645,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev) edcf->flags = 0; memset(edcf->mapping, 0, sizeof(edcf->mapping)); memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1936,7 +1936,7 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev) xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); memset(xbow->padding, 0, sizeof(xbow->padding)); - priv->tx(dev, skb, 1); + priv->tx(dev, skb); return 0; } @@ -1962,7 +1962,7 @@ static void p54_work(struct work_struct *work) if (!skb) return ; - priv->tx(dev, skb, 0); + priv->tx(dev, skb); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -2094,7 +2094,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); } - priv->tx(dev, skb, 1); + priv->tx(dev, skb); mutex_unlock(&priv->conf_mutex); return 0; } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 6c824e4..f5729de 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -84,9 +84,6 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF -#define P54_HDR_FLAG_CONTROL BIT(15) -#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) - #define P54_HDR_FLAG_DATA_ALIGN BIT(14) #define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) #define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index c28220e..aa367a0 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -227,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - p54_free_skb(dev, tx_buf[i]); + if (tx_buf[i]) + if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i])) + p54_free_skb(dev, tx_buf[i]); tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -298,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) return reg ? IRQ_HANDLED : IRQ_NONE; } -static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; @@ -314,6 +315,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); + priv->tx_buf_data[i] = skb; mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; @@ -324,10 +326,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, wmb(); ring_control->host_idx[1] = cpu_to_le32(idx + 1); - - if (free_on_tx) - priv->tx_buf_data[i] = skb; - spin_unlock_irqrestore(&priv->lock, flags); P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index c2789e5..17f89c7 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -138,22 +138,16 @@ static void p54u_rx_cb(struct urb *urb) } } -static void p54u_tx_reuse_skb_cb(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *) - usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv; - - skb_pull(skb, priv->common.tx_hdr_len); -} - -static void p54u_tx_free_skb_cb(struct urb *urb) +static void p54u_tx_cb(struct urb *urb) { struct sk_buff *skb = urb->context; struct ieee80211_hw *dev = (struct ieee80211_hw *) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + struct p54u_priv *priv = dev->priv; - p54_free_skb(dev, skb); + skb_pull(skb, priv->common.tx_hdr_len); + if (FREE_AFTER_TX(skb)) + p54_free_skb(dev, skb); } static void p54u_tx_dummy_cb(struct urb *urb) { } @@ -213,8 +207,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) return ret; } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; @@ -236,9 +229,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, p54u_tx_dummy_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, - free_on_tx ? p54u_tx_free_skb_cb : - p54u_tx_reuse_skb_cb, skb); + skb->data, skb->len, p54u_tx_cb, skb); usb_anchor_urb(addr_urb, &priv->submitted); err = usb_submit_urb(addr_urb, GFP_ATOMIC); @@ -273,8 +264,7 @@ static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; @@ -293,9 +283,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, - free_on_tx ? p54u_tx_free_skb_cb : - p54u_tx_reuse_skb_cb, skb); + skb->data, skb->len, p54u_tx_cb, skb); usb_anchor_urb(data_urb, &priv->submitted); if (usb_submit_urb(data_urb, GFP_ATOMIC)) { @@ -306,8 +294,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, usb_free_urb(data_urb); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, - int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; @@ -354,9 +341,7 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, - free_on_tx ? p54u_tx_free_skb_cb : - p54u_tx_reuse_skb_cb, skb); + skb->data, skb->len, p54u_tx_cb, skb); usb_anchor_urb(int_urb, &priv->submitted); err = usb_submit_urb(int_urb, GFP_ATOMIC); -- cgit v1.1 From d85882273367e98aecb9ff11a9d76515a6d37131 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Sun, 14 Dec 2008 12:18:09 -0600 Subject: rtl8187: Fix crash on unload when using SLUB debug Reported-by: Hin-Tak Leung After the code was modified to use urb anchors ("rtl8187: Use usb anchor facilities to manage urbs"), rtl8187 began generating an intermittent GPF on shutdown when using SLUB with debugging enabled. Furthermore, rebooting the system with a ping running caused a GPF every time. There are two problems: (1) incorrect locking in the rtl8187_rx_cb() routine, a pre-existing bug that apparently had not been triggered before, and (2) duplicate freeing of receive skbs that was probably introduced with the change to anchors. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 3900c47..00ce3ef 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -294,15 +294,16 @@ static void rtl8187_rx_cb(struct urb *urb) int rate, signal; u32 flags; u32 quality; + unsigned long f; - spin_lock(&priv->rx_queue.lock); + spin_lock_irqsave(&priv->rx_queue.lock, f); if (skb->next) __skb_unlink(skb, &priv->rx_queue); else { - spin_unlock(&priv->rx_queue.lock); + spin_unlock_irqrestore(&priv->rx_queue.lock, f); return; } - spin_unlock(&priv->rx_queue.lock); + spin_unlock_irqrestore(&priv->rx_queue.lock, f); skb_put(skb, urb->actual_length); if (unlikely(urb->status)) { @@ -942,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev) static void rtl8187_stop(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; - struct rtl8187_rx_info *info; struct sk_buff *skb; u32 reg; @@ -961,10 +961,6 @@ static void rtl8187_stop(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct rtl8187_rx_info *)skb->cb; - kfree_skb(skb); - } while ((skb = skb_dequeue(&priv->b_tx_status.queue))) dev_kfree_skb_any(skb); -- cgit v1.1 From da027ca00a48715364da9a94d4b663029add528d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 15 Dec 2008 15:44:53 +0200 Subject: ath9k: Fix TX status reporting for retries and MCS index The count field in struct ieee80211_tx_rate does not include the final successful attempt, so only report retries here. Fix the struct ieee80211_tx_rate::idx field when MCS was used. It is supposed to be the MCS index, not an internal index to the rate control algorithm table. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index f9c309e..d6d402c 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -125,7 +125,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_info->flags |= IEEE80211_TX_STAT_ACK; } - tx_info->status.rates[0].count = tx_status->retries + 1; + tx_info->status.rates[0].count = tx_status->retries; + if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { + /* Change idx from internal table index to MCS index */ + int idx = tx_info->status.rates[0].idx; + struct ath_rate_table *rate_table = sc->cur_rate_table; + if (idx >= 0 && idx < rate_table->rate_cnt) + tx_info->status.rates[0].idx = + rate_table->info[idx].ratecode & 0x7f; + } ieee80211_tx_status(hw, skb); } -- cgit v1.1 From f7a276a625e0b980185d2eb8e8e3e9425a708bee Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 15 Dec 2008 16:02:04 +0200 Subject: ath9k: Remove MAC header pad before reporting TX status Remove the possible MAC header pad before reporting TX status to mac80211. This pad is hardware specific operation and should not be exposed outside the driver. This fixes the frame body in monitor interfaces that could be used to check on TX status for transmitted frames. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index d6d402c..3bfc3b9 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -106,6 +106,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + int hdrlen, padsize; DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); @@ -135,6 +136,17 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, rate_table->info[idx].ratecode & 0x7f; } + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + /* + * Remove MAC header padding before giving the frame back to + * mac80211. + */ + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + ieee80211_tx_status(hw, skb); } -- cgit v1.1 From 9bf9fca8dea70116016d32c2bf3f83170c8fba76 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 15 Dec 2008 20:40:46 +0530 Subject: ath9k: Synchronize DMA transfer with CPU at right place This patch does pci_dma_sync_single_for_cpu() before accessing the header of the frame and queueing the same buffer into h/w. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/recv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index cc160fe..462e08c 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -520,6 +520,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) continue; /* + * Synchronize the DMA transfer with CPU before + * 1. accessing the frame + * 2. requeueing the same buffer to h/w + */ + pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); + + /* * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. */ @@ -547,10 +556,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (!requeue_skb) goto requeue; - /* Sync and unmap the frame */ - pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, - sc->rx.bufsize, - PCI_DMA_FROMDEVICE); + /* Unmap the frame */ pci_unmap_single(sc->pdev, bf->bf_buf_addr, sc->rx.bufsize, PCI_DMA_FROMDEVICE); -- cgit v1.1 From ca8a8560569c5eb954cb18c3a91087797ffa81a4 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 16 Dec 2008 12:37:38 +0530 Subject: ath9k: Move rate control alg register/unregister to appropriate place This patch makes sure the rate control alg is registered/unregistered only once for this module. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 550afbe..11064ca 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1229,9 +1229,6 @@ static void ath_detach(struct ath_softc *sc) ath_deinit_leds(sc); ieee80211_unregister_hw(hw); - - ath_rate_control_unregister(); - ath_rx_cleanup(sc); ath_tx_cleanup(sc); @@ -1512,15 +1509,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc) hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vap); - /* Register rate control */ hw->rate_control_algorithm = "ath9k_rate_control"; - error = ath_rate_control_register(); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to register rate control algorithm: %d\n", error); - ath_rate_control_unregister(); - goto bad; - } if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); @@ -1553,10 +1542,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc) #endif error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - goto bad; - } /* Initialize LED control */ ath_init_leds(sc); @@ -1564,7 +1549,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc) return 0; detach: ath_detach(sc); -bad: return error; } @@ -2714,11 +2698,24 @@ static struct pci_driver ath_pci_driver = { static int __init init_ath_pci(void) { + int error; + printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); + /* Register rate control algorithm */ + error = ath_rate_control_register(); + if (error != 0) { + printk(KERN_ERR + "Unable to register rate control algorithm: %d\n", + error); + ath_rate_control_unregister(); + return error; + } + if (pci_register_driver(&ath_pci_driver) < 0) { printk(KERN_ERR "ath_pci: No devices found, driver not installed.\n"); + ath_rate_control_unregister(); pci_unregister_driver(&ath_pci_driver); return -ENODEV; } @@ -2729,6 +2726,7 @@ module_init(init_ath_pci); static void __exit exit_ath_pci(void) { + ath_rate_control_unregister(); pci_unregister_driver(&ath_pci_driver); printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } -- cgit v1.1 From 73ec1cc28ebc7854a376cde53f62d487e127fbca Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 16 Dec 2008 09:37:07 +0200 Subject: iwlwifi: remove a parameter (dest) from *_fill_beacon_frame() methods. This patch removes a parameter (dest) from iwl_fill_beacon_frame() (iwl-agn.c) and from iwl3945_fill_beacon_frame(). (iwl-3945.c,iwl-3945.h) Signed-off-by: Rami Rosen Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 - drivers/net/wireless/iwlwifi/iwl-3945.h | 3 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index d0c9bdc..8fdb342 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2482,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, frame_size = iwl3945_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl3945_broadcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ec6084c..ffe5a8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -590,8 +590,7 @@ extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd); extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); + struct ieee80211_hdr *hdr,int left); extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q); extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index bbc1c80..ac8f83b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -371,7 +371,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, - const u8 *dest, int left) + int left) { if (!iwl_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && @@ -424,7 +424,6 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl_bcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 352ccac..d9c6baf 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1402,7 +1402,7 @@ static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame * unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, - const u8 *dest, int left) + int left) { if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || -- cgit v1.1 From 34c22cf93d1446791c966c878cc691e07c39d8d3 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 17 Dec 2008 16:52:27 +0800 Subject: iwlwifi: cleanup iwl-dev.h The patch removes unused definition and moves code to proper places. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-calib.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-dev.h | 29 +++-------------------------- 4 files changed, 14 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ffe5a8d..2c0ddc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -405,12 +405,6 @@ struct iwl3945_rx_queue { #define SCAN_INTERVAL 100 -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 7956e08..f836ecc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -70,6 +70,15 @@ * INIT calibrations framework *****************************************************************************/ +struct statistics_general_data { + u32 beacon_silence_rssi_a; + u32 beacon_silence_rssi_b; + u32 beacon_silence_rssi_c; + u32 beacon_energy_a; + u32 beacon_energy_b; + u32 beacon_energy_c; +}; + int iwl_send_calib_results(struct iwl_priv *priv) { int ret = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 60e79d9..52966ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2418,6 +2418,8 @@ struct statistics_rx_ht_phy { __le32 reserved2; } __attribute__ ((packed)); +#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) + struct statistics_rx_non_phy { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index eaf0c9c..0468fcc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -323,14 +323,6 @@ struct iwl_rx_queue { #define IWL_SUPPORTED_RATES_IE_LEN 8 -#define SCAN_INTERVAL 100 - -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - #define MAX_TID_COUNT 9 #define IWL_INVALID_RATE 0xFF @@ -496,8 +488,6 @@ struct iwl_sensitivity_ranges { }; -#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) - #define KELVIN_TO_CELSIUS(x) ((x)-273) #define CELSIUS_TO_KELVIN(x) ((x)+273) @@ -546,9 +536,6 @@ struct iwl_hw_params { const struct iwl_sensitivity_ranges *sens; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - /****************************************************************************** * @@ -590,15 +577,15 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) } -struct iwl_priv; - - struct iwl_dma_ptr { dma_addr_t dma; void *addr; size_t size; }; +#define HT_SHORT_GI_20MHZ (1 << 0) +#define HT_SHORT_GI_40MHZ (1 << 1) + #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 @@ -613,7 +600,6 @@ struct iwl_dma_ptr { #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 /* Sensitivity and chain noise calibration */ -#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) #define INITIALIZATION_VALUE 0xFFFF #define CAL_NUM_OF_BEACONS 20 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -666,15 +652,6 @@ enum iwl4965_calib_enabled_state { IWL_CALIB_ENABLED = 1, }; -struct statistics_general_data { - u32 beacon_silence_rssi_a; - u32 beacon_silence_rssi_b; - u32 beacon_silence_rssi_c; - u32 beacon_energy_a; - u32 beacon_energy_b; - u32 beacon_energy_c; -}; - /* * enum iwl_calib -- cgit v1.1 From 5c11ec60ef2eb8fb409b2c0a427e5a8ab6ee05f8 Mon Sep 17 00:00:00 2001 From: "Wu, Fengguang" Date: Wed, 17 Dec 2008 16:52:28 +0800 Subject: iwlwifi: add line feed to printk This adds line feed to printk. Signed-off-by: Wu Fengguang Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index dce32ff..11eccd7d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -292,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; - IWL_DEBUG_LED("LED BLINK IDX=%d", i); + IWL_DEBUG_LED("LED BLINK IDX=%d\n", i); return i; } -- cgit v1.1 From c3a739fa3507d1d5b3d2cb6cc491edeef8fa54c0 Mon Sep 17 00:00:00 2001 From: "Wu, Fengguang" Date: Wed, 17 Dec 2008 16:52:29 +0800 Subject: iwlwifi: update comments on the debug interface Bring up-to-date some comments on the location of debug files. Signed-off-by: Wu Fengguang Acked-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ac8f83b..a005192 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3342,7 +3342,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) /* * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) * used for controlling the debug level. * * See the level definitions in iwl for details. diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e4c264b..56c13b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -96,28 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #endif /* CONFIG_IWLWIFI_DEBUGFS */ /* - * To use the debug system; + * To use the debug system: * * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: + * list here in the form of * * #define IWL_DL_xxxx VALUE * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) + * where xxxx should be the name of the classification (for example, WEP). * * You then need to either add a IWL_xxxx_DEBUG() macro definition for your * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want * to send output to that classification. * - * To add your debug level to the list of levels seen when you perform + * The active debug levels can be accessed via files * - * % cat /sys/class/net/wlanX/device/debug_level + * /sys/module/iwlagn/parameters/debug{50} + * /sys/class/net/wlan0/device/debug_level * - * you simply need to add your entry to the iwl_debug_levels array. - * - * If you do not see debug_level in /sys/class/net/wlanX/device/debug_level - * then you do not have CONFIG_IWLWIFI_DEBUG defined in your kernel config file + * when CONFIG_IWLWIFI_DEBUG=y. */ #define IWL_DL_INFO (1 << 0) -- cgit v1.1 From 95aa194ac4a8fee0aea64c9609e70211cd057ad2 Mon Sep 17 00:00:00 2001 From: "Wu, Fengguang" Date: Wed, 17 Dec 2008 16:52:30 +0800 Subject: iwlwifi: use type uint for module param debug This enables one to change the debug level at bit 31. Signed-off-by: Wu Fengguang Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a7e6e32..3a78d860 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2354,7 +2354,7 @@ module_param_named(disable, iwl4965_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(debug, iwl4965_mod_params.debug, int, 0444); +module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named( disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 2344de9..7f3a921 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1623,7 +1623,7 @@ MODULE_PARM_DESC(disable50, module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(debug50, iwl50_mod_params.debug, int, 0444); +module_param_named(debug50, iwl50_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug50, "50XX debug output mask"); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 08b842f..7c3a20a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -154,7 +154,7 @@ struct iwl_ops { struct iwl_mod_params { int disable; /* def: 0 = enable radio */ int sw_crypto; /* def: 0 = using hardware encryption */ - int debug; /* def: 0 = minimal debug log messages */ + u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d9c6baf..d645808 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -65,7 +65,7 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, /* module parameters */ static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */ -static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ +static u32 iwl3945_param_debug; /* def: 0 = minimal debug log messages */ static int iwl3945_param_disable; /* def: 0 = enable radio */ static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ @@ -8343,7 +8343,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "using hardware crypto engine (default 0 [software])\n"); -module_param_named(debug, iwl3945_param_debug, int, 0444); +module_param_named(debug, iwl3945_param_debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -- cgit v1.1 From febf3370c63b4ea7fc1cedb9a73ac37e3cb21079 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 17 Dec 2008 16:52:31 +0800 Subject: iwlwifi: remove useless goto The patch removes some useless goto in code cleanup. Signed-off-by: Wu Fengguang Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 8 ++------ drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 3a78d860..5a72bc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -426,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) static int iwl4965_apm_stop_master(struct iwl_priv *priv) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -434,16 +433,13 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_direct_bit(priv, CSR_RESET, + iwl_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; -out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return ret; + return 0; } static void iwl4965_apm_stop(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 7f3a921..66d053d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -73,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { /* FIXME: same implementation as 4965 */ static int iwl5000_apm_stop_master(struct iwl_priv *priv) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -81,16 +80,13 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_direct_bit(priv, CSR_RESET, + iwl_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; -out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return ret; + return 0; } -- cgit v1.1 From 4087f6f68cdbd2845c7e54236bae1b058a7b827b Mon Sep 17 00:00:00 2001 From: "Wu, Fengguang" Date: Wed, 17 Dec 2008 16:52:32 +0800 Subject: iwlwifi: use meaningful vars in _iwl_poll_bit() Rename vars in _iwl_poll_bit() to better reflect the truth. Signed-off-by: Wu Fengguang Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-io.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 998ac19..0a92e74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -87,17 +87,18 @@ static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) #define iwl_read32(p, o) _iwl_read32(p, o) #endif +#define IWL_POLL_INTERVAL 10 /* microseconds */ static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, u32 bits, u32 mask, int timeout) { - int i = 0; + int t = 0; do { if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return i; - udelay(10); - i += 10; - } while (i < timeout); + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); return -ETIMEDOUT; } -- cgit v1.1 From f1bc4ac61f2c08515afd80c6dc3962aa6d0b138b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 17 Dec 2008 16:52:33 +0800 Subject: iwlwifi: use GFP_KERNEL to allocate Rx SKB memory Previously we allocate Rx SKB with GFP_ATOMIC flag. This is because we need to hold a spinlock to protect the two rx_used and rx_free lists operation in the rxq. spin_lock(); ... element = rxq->rx_used.next; element->skb = alloc_skb(..., GFP_ATOMIC); list_del(element); list_add_tail(&element->list, &rxq->rx_free); ... spin_unlock(); After spliting the rx_used delete and rx_free insert into two operations, we don't require the skb allocation in an atomic context any more (the function itself is scheduled in a workqueue). spin_lock(); ... element = rxq->rx_used.next; list_del(element); ... spin_unlock(); ... element->skb = alloc_skb(..., GFP_KERNEL); ... spin_lock() ... list_add_tail(&element->list, &rxq->rx_free); ... spin_unlock(); This patch should fix the "iwlagn: Can not allocate SKB buffers" warning we see recently. Signed-off-by: Zhu Yi Acked-by: Tomas Winkler Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 12 +----------- drivers/net/wireless/iwlwifi/iwl-rx.c | 29 +++++++++++++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a005192..ff8635f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1110,16 +1110,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->cfg->ops->lib->rx_handler_setup(priv); } -/* - * this should be called while priv->lock is locked -*/ -static void __iwl_rx_replenish(struct iwl_priv *priv) -{ - iwl_rx_allocate(priv); - iwl_rx_queue_restock(priv); -} - - /** * iwl_rx_handle - Main entry function for receiving responses from uCode * @@ -1228,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl_rx_replenish(priv); + iwl_rx_queue_restock(priv); count = 0; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 919a775..c5f1aa0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -244,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv) struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { + + while (1) { + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + return; + } element = rxq->rx_used.next; rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - __GFP_NOWARN | GFP_ATOMIC); + GFP_KERNEL); if (!rxb->skb) { - if (net_ratelimit()) - printk(KERN_CRIT DRV_NAME - ": Can not allocate SKB buffers\n"); + printk(KERN_CRIT DRV_NAME + "Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will * call the restock method and if it still needs * more buffers it will schedule replenish */ break; } - priv->alloc_rxb_skb++; - list_del(element); /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single( @@ -276,12 +282,15 @@ void iwl_rx_allocate(struct iwl_priv *priv) rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; + priv->alloc_rxb_skb++; + + spin_unlock_irqrestore(&rxq->lock, flags); } - spin_unlock_irqrestore(&rxq->lock, flags); } -EXPORT_SYMBOL(iwl_rx_allocate); void iwl_rx_replenish(struct iwl_priv *priv) { -- cgit v1.1 From 91f39e8eea725347b6a82d1e35e512ec8b298b0b Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Wed, 17 Dec 2008 16:52:34 +0800 Subject: iwlwifi: indicate txpower is off in sysfs The patch checks if the radio is disabled before displaying the tx power level. Previously when the txpower was set off show_tx_power still returned the prior power level. Now it will indicate the power has been turned off. Signed-off-by: Jay Sternberg Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ff8635f..5da6b35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3418,7 +3418,11 @@ static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); + + if (!iwl_is_ready_rf(priv)) + return sprintf(buf, "off\n"); + else + return sprintf(buf, "%d\n", priv->tx_power_user_lmt); } static ssize_t store_tx_power(struct device *d, -- cgit v1.1 From f66000f7a39769b0ce2355fca13c40ac2f1c39db Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 17 Dec 2008 13:30:31 +0200 Subject: ath9k: Fix a NULL pointer dereference in ath_rate_get It looks like mac80211 may try to send unicast frames to a STA that does not have a STA entry. We need to make sure that that is caught in the rate control code before dereferencing STA data. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 0ae5988..04ab457 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1498,7 +1498,8 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, __le16 fc = hdr->frame_control; /* lowest rate for management and multicast/broadcast frames */ - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta) { tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); tx_info->control.rates[0].count = is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; -- cgit v1.1 From 6ace2891a1d632303283816ae050849da48df142 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 17 Dec 2008 13:32:17 +0200 Subject: ath9k: Key cache allocation for AP mode Enhance allocation of key cache entries to support multiple pairwise keys to fix AP mode with more than one associated STA. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 200 +++++++++++++++++++++++++------------- 1 file changed, 132 insertions(+), 68 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 11064ca..e768be4 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -664,13 +664,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, return chanmode; } -static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) -{ - ath9k_hw_keyreset(sc->sc_ah, keyix); - if (freeslot) - clear_bit(keyix, sc->sc_keymap); -} - static int ath_keyset(struct ath_softc *sc, u16 keyix, struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) { @@ -682,21 +675,20 @@ static int ath_keyset(struct ath_softc *sc, u16 keyix, return status != false; } -static int ath_setkey_tkip(struct ath_softc *sc, - struct ieee80211_key_conf *key, +static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, struct ath9k_keyval *hk, const u8 *addr) { - u8 *key_rxmic = NULL; - u8 *key_txmic = NULL; + const u8 *key_rxmic; + const u8 *key_txmic; - key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; - key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; + key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; + key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; if (addr == NULL) { /* Group key installation */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - return ath_keyset(sc, key->keyidx, hk, addr); + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + return ath_keyset(sc, keyix, hk, addr); } if (!sc->sc_splitmic) { /* @@ -705,14 +697,14 @@ static int ath_setkey_tkip(struct ath_softc *sc, */ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); - return ath_keyset(sc, key->keyidx, hk, addr); + return ath_keyset(sc, keyix, hk, addr); } /* * TX key goes at first index, RX key at +32. * The hal handles the MIC keys at index+64. */ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - if (!ath_keyset(sc, key->keyidx, hk, NULL)) { + if (!ath_keyset(sc, keyix, hk, NULL)) { /* Txmic entry failed. No need to proceed further */ DPRINTF(sc, ATH_DBG_KEYCACHE, "Setting TX MIC Key Failed\n"); @@ -721,18 +713,85 @@ static int ath_setkey_tkip(struct ath_softc *sc, memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); /* XXX delete tx key on failure? */ - return ath_keyset(sc, key->keyidx+32, hk, addr); + return ath_keyset(sc, keyix + 32, hk, addr); +} + +static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) +{ + int i; + + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { + if (test_bit(i, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap)) + continue; /* At least one part of TKIP key allocated */ + if (sc->sc_splitmic && + (test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + continue; /* At least one part of TKIP key allocated */ + + /* Found a free slot for a TKIP key */ + return i; + } + return -1; +} + +static int ath_reserve_key_cache_slot(struct ath_softc *sc) +{ + int i; + + /* First, try to find slots that would not be available for TKIP. */ + if (sc->sc_splitmic) { + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) { + if (!test_bit(i, sc->sc_keymap) && + (test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i; + if (!test_bit(i + 32, sc->sc_keymap) && + (test_bit(i, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i + 32; + if (!test_bit(i + 64, sc->sc_keymap) && + (test_bit(i , sc->sc_keymap) || + test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i; + if (!test_bit(i + 64 + 32, sc->sc_keymap) && + (test_bit(i, sc->sc_keymap) || + test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap))) + return i; + } + } else { + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { + if (!test_bit(i, sc->sc_keymap) && + test_bit(i + 64, sc->sc_keymap)) + return i; + if (test_bit(i, sc->sc_keymap) && + !test_bit(i + 64, sc->sc_keymap)) + return i + 64; + } + } + + /* No partially used TKIP slots, pick any available slot */ + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) { + if (!test_bit(i, sc->sc_keymap)) + return i; /* Found a free slot for a key */ + } + + /* No free slot found */ + return -1; } static int ath_key_config(struct ath_softc *sc, const u8 *addr, struct ieee80211_key_conf *key) { - struct ieee80211_vif *vif; struct ath9k_keyval hk; const u8 *mac = NULL; int ret = 0; - enum nl80211_iftype opmode; + int idx; memset(&hk, 0, sizeof(hk)); @@ -750,65 +809,69 @@ static int ath_key_config(struct ath_softc *sc, return -EINVAL; } - hk.kv_len = key->keylen; + hk.kv_len = key->keylen; memcpy(hk.kv_val, key->key, key->keylen); - if (!sc->sc_vaps[0]) - return -EIO; - - vif = sc->sc_vaps[0]; - opmode = vif->type; + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; + } else if (key->keyidx) { + struct ieee80211_vif *vif; - /* - * Strategy: - * For STA mc tx, we will not setup a key at - * all since we never tx mc. - * - * For STA mc rx, we will use the keyID. - * - * For ADHOC mc tx, we will use the keyID, and no macaddr. - * - * For ADHOC mc rx, we will alloc a slot and plumb the mac of - * the peer node. - * BUT we will plumb a cleartext key so that we can do - * per-Sta default key table lookup in software. - */ - if (is_broadcast_ether_addr(addr)) { - switch (opmode) { - case NL80211_IFTYPE_STATION: - /* default key: could be group WPA key - * or could be static WEP key */ - mac = NULL; - break; - case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_AP: - break; - default: - ASSERT(0); - break; - } + mac = addr; + vif = sc->sc_vaps[0]; + if (vif->type != NL80211_IFTYPE_AP) { + /* Only keyidx 0 should be used with unicast key, but + * allow this for client mode for now. */ + idx = key->keyidx; + } else + return -EIO; } else { mac = addr; + if (key->alg == ALG_TKIP) + idx = ath_reserve_key_cache_slot_tkip(sc); + else + idx = ath_reserve_key_cache_slot(sc); + if (idx < 0) + return -EIO; /* no free key cache entries */ } if (key->alg == ALG_TKIP) - ret = ath_setkey_tkip(sc, key, &hk, mac); + ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac); else - ret = ath_keyset(sc, key->keyidx, &hk, mac); + ret = ath_keyset(sc, idx, &hk, mac); if (!ret) return -EIO; - return 0; + set_bit(idx, sc->sc_keymap); + if (key->alg == ALG_TKIP) { + set_bit(idx + 64, sc->sc_keymap); + if (sc->sc_splitmic) { + set_bit(idx + 32, sc->sc_keymap); + set_bit(idx + 64 + 32, sc->sc_keymap); + } + } + + return idx; } static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) { - int freeslot; + ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); + if (key->hw_key_idx < IEEE80211_WEP_NKID) + return; + + clear_bit(key->hw_key_idx, sc->sc_keymap); + if (key->alg != ALG_TKIP) + return; - freeslot = (key->keyidx >= 4) ? 1 : 0; - ath_key_reset(sc, key->keyidx, freeslot); + clear_bit(key->hw_key_idx + 64, sc->sc_keymap); + if (sc->sc_splitmic) { + clear_bit(key->hw_key_idx + 32, sc->sc_keymap); + clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap); + } } static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) @@ -1301,13 +1364,15 @@ static int ath_init(u16 devid, struct ath_softc *sc) * Mark key cache slots associated with global keys * as in use. If we knew TKIP was not to be used we * could leave the +32, +64, and +32+64 slots free. - * XXX only for splitmic. */ for (i = 0; i < IEEE80211_WEP_NKID; i++) { set_bit(i, sc->sc_keymap); - set_bit(i + 32, sc->sc_keymap); set_bit(i + 64, sc->sc_keymap); - set_bit(i + 32 + 64, sc->sc_keymap); + if (ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) { + set_bit(i + 32, sc->sc_keymap); + set_bit(i + 32 + 64, sc->sc_keymap); + } } /* Collect the channel list using the default country code */ @@ -2292,18 +2357,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw, switch (cmd) { case SET_KEY: ret = ath_key_config(sc, addr, key); - if (!ret) { - set_bit(key->keyidx, sc->sc_keymap); - key->hw_key_idx = key->keyidx; + if (ret >= 0) { + key->hw_key_idx = ret; /* push IV and Michael MIC generation to stack */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->alg == ALG_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + ret = 0; } break; case DISABLE_KEY: ath_key_delete(sc, key); - clear_bit(key->keyidx, sc->sc_keymap); break; default: ret = -EINVAL; -- cgit v1.1 From 6110781af080c007b2202187a8518920e03d5748 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 17 Dec 2008 12:04:43 +0100 Subject: p54usb: bring first generation devices back to life This patch fixes a serious regression (introduced by: "p54: fix memory management") that affected isl3886+net2280 usb devices operation. Signed-off-by: Christian Lamparter Tested-by: Artur Skawina Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 17f89c7..c44a200 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -301,6 +301,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) struct net2280_tx_hdr *hdr; struct net2280_reg_write *reg; int err = 0; + __le32 addr = ((struct p54_hdr *) skb->data)->req_id; + __le16 len = cpu_to_le16(skb->len); reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) @@ -325,8 +327,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; - hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr)); + hdr->len = len; + hdr->device_addr = addr; usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), -- cgit v1.1 From aa33de09a849bd65b1201e1aec42e3e412c14cf6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 18 Dec 2008 11:40:16 +0530 Subject: ath9k: Protect config() callback with a mutex This should fix the timeout issues seen when using wpa_supplicant. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 + drivers/net/wireless/ath9k/main.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index e38f033..4ca2aed 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -701,6 +701,7 @@ struct ath_softc { struct ath_hal *sc_ah; void __iomem *mem; spinlock_t sc_resetlock; + struct mutex mutex; u8 sc_curbssid[ETH_ALEN]; u8 sc_myaddr[ETH_ALEN]; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index e768be4..94c5266 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1324,6 +1324,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) printk(KERN_ERR "Unable to create debugfs files\n"); spin_lock_init(&sc->sc_resetlock); + mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, (unsigned long)sc); @@ -2133,6 +2134,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_softc *sc = hw->priv; struct ieee80211_conf *conf = &hw->conf; + mutex_lock(&sc->mutex); if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_HT)) { struct ieee80211_channel *curchan = hw->conf.channel; @@ -2145,6 +2147,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (pos == -1) { DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); + mutex_unlock(&sc->mutex); return -EINVAL; } @@ -2165,6 +2168,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); + mutex_unlock(&sc->mutex); return -EINVAL; } @@ -2174,6 +2178,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) sc->sc_config.txpowlimit = 2 * conf->power_level; + mutex_unlock(&sc->mutex); return 0; } -- cgit v1.1 From ea6121328885640c137b0a8830f67ca6c386a24a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 18 Dec 2008 14:31:10 +0200 Subject: ath9k: Fix key cache slot selection for splitmic ath_reserve_key_cache_slot() was obviously supposed to return an index to a free slot, not reserved one. This could have caused problems with hardware revisions that use splitmic. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 94c5266..b447367 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -756,12 +756,12 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc) (test_bit(i , sc->sc_keymap) || test_bit(i + 32, sc->sc_keymap) || test_bit(i + 64 + 32, sc->sc_keymap))) - return i; + return i + 64; if (!test_bit(i + 64 + 32, sc->sc_keymap) && (test_bit(i, sc->sc_keymap) || test_bit(i + 32, sc->sc_keymap) || test_bit(i + 64, sc->sc_keymap))) - return i; + return i + 64 + 32; } } else { for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { -- cgit v1.1 From be2864cfff2fe4b599b46f03cce1e7689e05c60c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 18 Dec 2008 14:33:00 +0200 Subject: ath9k: Fixed RX decryption status reporting The RX code in ath9k uses sc_keymap to figure out whether a default key was used. However, the default key entries in sc_keymap were always set and as such, frames could have been claimed to be decrypted by hardware when they were not. This can cause problems especially with TKIP since mac80211 is validating the Michael MIC in the frame and this will result in MIC failure and potentially TKIP countermeasures if the frame was not decrypted correctly. Change key cache slot allocation to mark only the keys that really have been used in sc_keymap to avoid the issue. The key cache slot selection routines are now internally avoiding the slots that may be needed for TKIP group keys. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index b447367..191eec5 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -776,6 +776,18 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc) /* No partially used TKIP slots, pick any available slot */ for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) { + /* Do not allow slots that could be needed for TKIP group keys + * to be used. This limitation could be removed if we know that + * TKIP will not be used. */ + if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) + continue; + if (sc->sc_splitmic) { + if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) + continue; + if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) + continue; + } + if (!test_bit(i, sc->sc_keymap)) return i; /* Found a free slot for a key */ } @@ -1361,20 +1373,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) */ for (i = 0; i < sc->sc_keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - /* - * Mark key cache slots associated with global keys - * as in use. If we knew TKIP was not to be used we - * could leave the +32, +64, and +32+64 slots free. - */ - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - set_bit(i, sc->sc_keymap); - set_bit(i + 64, sc->sc_keymap); - if (ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) { - set_bit(i + 32, sc->sc_keymap); - set_bit(i + 32 + 64, sc->sc_keymap); - } - } /* Collect the channel list using the default country code */ -- cgit v1.1 From 0e7690f1e9ee1e762f27678d2ea10e4c1fde3236 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Thu, 18 Dec 2008 18:04:51 +0200 Subject: iwlwifi: iwl-tx.c cleanup (remove unused parameter and unused local variable). This patch removes unused parameter and unused local variable in methods in iwl-tx.c: - Remove a parameter (is_unicast) from iwl_tx_cmd_build_basic(). - Remove an unused variable name unicast from iwl_tx_skb(). Signed-off-by: Rami Rosen Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1e7cd8d..b0ee86c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -645,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) + u8 std_id) { __le16 fc = hdr->frame_control; __le32 tx_flags = tx_cmd->tx_flags; @@ -834,7 +834,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) u16 len, len_org; u16 seq_number = 0; __le16 fc; - u8 hdr_len, unicast; + u8 hdr_len; u8 sta_id; u8 wait_write_ptr = 0; u8 tid = 0; @@ -854,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - unicast = !is_multicast_ether_addr(hdr->addr1); - fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG @@ -994,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); + iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); -- cgit v1.1 From d10d0e5707fb7b8afa7e68a14d69e752604ee294 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 18 Dec 2008 22:13:39 +0100 Subject: b43: Fix some MAC locking This fixes some locking w.r.t. the lower MAC (firmware). It also removes a lot of ancient IRQ-locking that's not needed anymore. We simply suspend the MAC. That's easier and causes less trouble. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 50 ++++++----------------------------- drivers/net/wireless/b43/phy_common.c | 16 +++++++++++ drivers/net/wireless/b43/phy_g.c | 8 ++++-- 3 files changed, 30 insertions(+), 44 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ba7a5ab..07dc988 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3324,7 +3324,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) unsigned long flags; int antenna; int err = 0; - u32 savedirqs; mutex_lock(&wl->mutex); @@ -3335,24 +3334,14 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) dev = wl->current_dev; phy = &dev->phy; + b43_mac_suspend(dev); + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) b43_set_retry_limits(dev, conf->short_frame_max_tx_count, conf->long_frame_max_tx_count); changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; if (!changed) - goto out_unlock_mutex; - - /* Disable IRQs while reconfiguring the device. - * This makes it possible to drop the spinlock throughout - * the reconfiguration process. */ - spin_lock_irqsave(&wl->irq_lock, flags); - if (b43_status(dev) < B43_STAT_STARTED) { - spin_unlock_irqrestore(&wl->irq_lock, flags); - goto out_unlock_mutex; - } - savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); + goto out_mac_enable; /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ @@ -3399,11 +3388,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) } } - spin_lock_irqsave(&wl->irq_lock, flags); - b43_interrupt_enable(dev, savedirqs); - mmiowb(); - spin_unlock_irqrestore(&wl->irq_lock, flags); - out_unlock_mutex: +out_mac_enable: + b43_mac_enable(dev); +out_unlock_mutex: mutex_unlock(&wl->mutex); return err; @@ -3461,27 +3448,12 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - struct b43_phy *phy; - unsigned long flags; - u32 savedirqs; mutex_lock(&wl->mutex); dev = wl->current_dev; - phy = &dev->phy; - - /* Disable IRQs while reconfiguring the device. - * This makes it possible to drop the spinlock throughout - * the reconfiguration process. */ - spin_lock_irqsave(&wl->irq_lock, flags); - if (b43_status(dev) < B43_STAT_STARTED) { - spin_unlock_irqrestore(&wl->irq_lock, flags); + if (!dev || b43_status(dev) < B43_STAT_STARTED) goto out_unlock_mutex; - } - savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); - b43_mac_suspend(dev); if (changed & BSS_CHANGED_BASIC_RATES) @@ -3495,13 +3467,7 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, } b43_mac_enable(dev); - - spin_lock_irqsave(&wl->irq_lock, flags); - b43_interrupt_enable(dev, savedirqs); - /* XXX: why? */ - mmiowb(); - spin_unlock_irqrestore(&wl->irq_lock, flags); - out_unlock_mutex: +out_unlock_mutex: mutex_unlock(&wl->mutex); return; diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index af37abc..2ebfc7d 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev) b43_power_saving_ctl_bits(dev, 0); } +static inline void assert_mac_suspended(struct b43_wldev *dev) +{ + if (!B43_DEBUG) + return; + if ((b43_status(dev) >= B43_STAT_INITIALIZED) && + (dev->mac_suspended <= 0)) { + b43dbg(dev->wl, "PHY/RADIO register access with " + "enabled MAC.\n"); + dump_stack(); + } +} + u16 b43_radio_read(struct b43_wldev *dev, u16 reg) { + assert_mac_suspended(dev); return dev->phy.ops->radio_read(dev, reg); } void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { + assert_mac_suspended(dev); dev->phy.ops->radio_write(dev, reg, value); } @@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) u16 b43_phy_read(struct b43_wldev *dev, u16 reg) { + assert_mac_suspended(dev); return dev->phy.ops->phy_read(dev, reg); } void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) { + assert_mac_suspended(dev); dev->phy.ops->phy_write(dev, reg, value); } diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 232181f..3b1d673 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) int rfatt, bbatt; u8 tx_control; + b43_mac_suspend(dev); + spin_lock_irq(&dev->wl->irq_lock); /* Calculate the new attenuation values. */ @@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) gphy->tx_control); b43_radio_unlock(dev); b43_phy_unlock(dev); + + b43_mac_enable(dev); } static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, @@ -3215,9 +3219,9 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; + b43_mac_suspend(dev); //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, @@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) 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); + b43_mac_enable(dev); } static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) -- cgit v1.1 From fd6effcaf8a894c0a0f602b943dbc54a170d4418 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 18 Dec 2008 23:23:05 -0500 Subject: ath5k: correct packet length in tx descriptors Packet length calculation (which includes frame check sequence) should take into account whether we add a pad field or not. Extract the calculation into a helper and use it in both places. Changes to desc.c Changes-licensed-under: ISC Changes to ath5k.h, base.c Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 5 +++++ drivers/net/wireless/ath5k/base.c | 8 ++++---- drivers/net/wireless/ath5k/desc.c | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 13df119..183ffc8 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -1350,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) return retval; } +static inline int ath5k_pad_size(int hdrlen) +{ + return (hdrlen < 24) ? 0 : hdrlen & 3; +} + #endif diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 9b5f31a..4af2607 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1762,8 +1762,8 @@ accept: * not try to remove padding from short control frames that do * not have payload. */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { + padsize = ath5k_pad_size(hdrlen); + if (padsize) { memmove(skb->data + padsize, skb->data, hdrlen); skb_pull(skb, padsize); } @@ -2638,8 +2638,8 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * if this is not the case we add the padding after the header */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { + padsize = ath5k_pad_size(hdrlen); + if (padsize) { if (skb_headroom(skb) < padsize) { ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index 5e362a7..b40a928 100644 --- a/drivers/net/wireless/ath5k/desc.c +++ b/drivers/net/wireless/ath5k/desc.c @@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; @@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; -- cgit v1.1 From b929ecf7965c2dab7e373f390ac5fc563011484d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 19 Dec 2008 18:40:00 +0100 Subject: b43: Suspend MAC while killing the radio We should suspend the MAC, before we kill the radio. This gives the MAC a chance to leave any TX/RX state and it avoids races on the PHY/RADIO registers. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 2ebfc7d..026b61c 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -296,8 +296,10 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) state = RFKILL_STATE_SOFT_BLOCKED; } + b43_mac_suspend(dev); phy->ops->software_rfkill(dev, state); phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); + b43_mac_enable(dev); } /** -- cgit v1.1 From 9cf7f247bd0cd21e475c71a4e018bb612ef02aab Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 19 Dec 2008 20:24:30 +0100 Subject: b43: Add key memory dumping This adds an option to dump all crypto related memory to the kernel log. Obviously, it should not be enabled on productive systems. ;) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/debugfs.c | 1 + drivers/net/wireless/b43/debugfs.h | 1 + drivers/net/wireless/b43/main.c | 53 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 06a01da..e04fc91 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -731,6 +731,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); add_dyn_dbg("debug_lo", B43_DBG_LO, 0); add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); + add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0); #undef add_dyn_dbg } diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 22ffd02..7886cbe 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -12,6 +12,7 @@ enum b43_dyndbg { /* Dynamic debugging features */ B43_DBG_PWORK_STOP, B43_DBG_LO, B43_DBG_FIRMWARE, + B43_DBG_KEYS, __B43_NR_DYNDBG, }; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 07dc988..7b31a32 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -992,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev) b43_key_clear(dev, i); } +static void b43_dump_keymemory(struct b43_wldev *dev) +{ + unsigned int i, index, offset; + DECLARE_MAC_BUF(macbuf); + u8 mac[ETH_ALEN]; + u16 algo; + u32 rcmta0; + u16 rcmta1; + u64 hf; + struct b43_key *key; + + if (!b43_debug(dev, B43_DBG_KEYS)) + return; + + hf = b43_hf_read(dev); + b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", + !!(hf & B43_HF_USEDEFKEYS)); + for (index = 0; index < dev->max_nr_keys; index++) { + key = &(dev->key[index]); + printk(KERN_DEBUG "Key slot %02u: %s", + index, (key->keyconf == NULL) ? " " : "*"); + offset = dev->ktp + (index * B43_SEC_KEYSIZE); + for (i = 0; i < B43_SEC_KEYSIZE; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); + printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); + } + + algo = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_KEYIDXBLOCK + (index * 2)); + printk(" Algo: %04X/%02X", algo, key->algorithm); + + if (index >= 4) { + rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, + ((index - 4) * 2) + 0); + rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, + ((index - 4) * 2) + 1); + *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); + *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); + printk(" MAC: %s", + print_mac(macbuf, mac)); + } else + printk(" DEFAULT KEY"); + printk("\n"); + } +} + void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) { u32 macctl; @@ -3565,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, default: B43_WARN_ON(1); } + out_unlock: - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " "mac: %pM\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, addr); + b43_dump_keymemory(dev); } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + return err; } -- cgit v1.1 From 2ed5ba890e1e8dda89557e4ea233a26ab8bf3d58 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 26 Dec 2008 00:12:59 -0800 Subject: drivers/net/wireless: fix sparse warnings: make symbols static Fix this sparse warnings: drivers/net/wireless/airo.c:3610:6: warning: symbol 'mpi_receive_802_11' was not declared. Should it be static? drivers/net/wireless/atmel.c:3183:6: warning: symbol 'atmel_join_bss' was not declared. Should it be static? drivers/net/wireless/ray_cs.c:831:5: warning: symbol 'ray_dev_init' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: David S. Miller --- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/atmel.c | 2 +- drivers/net/wireless/ray_cs.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 67d504e..fc4322c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3607,7 +3607,7 @@ badrx: } } -void mpi_receive_802_11 (struct airo_info *ai) +static void mpi_receive_802_11(struct airo_info *ai) { RxFid rxd; struct sk_buff *skb = NULL; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 3962b55..350157f 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -3180,7 +3180,7 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) } } -void atmel_join_bss(struct atmel_private *priv, int bss_index) +static void atmel_join_bss(struct atmel_private *priv, int bss_index) { struct bss_info *bss = &priv->BSSinfo[bss_index]; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 81b71f0..99ec7d6 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -828,7 +828,7 @@ static int ray_resume(struct pcmcia_device *link) } /*===========================================================================*/ -int ray_dev_init(struct net_device *dev) +static int ray_dev_init(struct net_device *dev) { #ifdef RAY_IMMEDIATE_INIT int i; -- cgit v1.1 From bf512bc827c84f77553538834fffe71604079f23 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 26 Dec 2008 00:13:29 -0800 Subject: drivers/net/wireless/ath9k: fix sparse warnings: make symbols static Fix this sparse warnings: drivers/net/wireless/ath9k/eeprom.c:195:6: warning: symbol 'ath9k_fill_eeprom' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:463:5: warning: symbol 'ath9k_check_eeprom' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:1219:6: warning: symbol 'ath9k_hw_set_def_power_per_rate_table' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:1510:6: warning: symbol 'ath9k_hw_set_4k_power_per_rate_table' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2007:5: warning: symbol 'ath9k_set_txpower' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2106:6: warning: symbol 'ath9k_set_addac' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2543:6: warning: symbol 'ath9k_eeprom_set_board_values' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2606:5: warning: symbol 'ath9k_get_eeprom_antenna_cfg' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2622:4: warning: symbol 'ath9k_hw_get_4k_num_ant_config' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2628:4: warning: symbol 'ath9k_hw_get_def_num_ant_config' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2647:4: warning: symbol 'ath9k_get_num_ant_config' was not declared. Should it be static? drivers/net/wireless/ath9k/eeprom.c:2790:5: warning: symbol 'ath9k_get_eeprom' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: David S. Miller --- drivers/net/wireless/ath9k/eeprom.c | 62 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index 14f8d40..acd6c53 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -192,7 +192,7 @@ static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah) #undef SIZE_EEPROM_DEF } -bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = { +static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = { ath9k_hw_fill_def_eeprom, ath9k_hw_fill_4k_eeprom }; @@ -460,7 +460,7 @@ static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) #undef EEPROM_4K_SIZE } -int (*ath9k_check_eeprom[]) (struct ath_hal *) = { +static int (*ath9k_check_eeprom[]) (struct ath_hal *) = { ath9k_hw_check_def_eeprom, ath9k_hw_check_4k_eeprom }; @@ -1216,13 +1216,13 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, return true; } -bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) +static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) { #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ @@ -1507,13 +1507,13 @@ bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, return true; } -bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) +static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; @@ -2004,9 +2004,9 @@ static int ath9k_hw_4k_set_txpower(struct ath_hal *ah, return 0; } -int (*ath9k_set_txpower[]) (struct ath_hal *, - struct ath9k_channel *, - u16, u8, u8, u8) = { +static int (*ath9k_set_txpower[]) (struct ath_hal *, + struct ath9k_channel *, + u16, u8, u8, u8) = { ath9k_hw_def_set_txpower, ath9k_hw_4k_set_txpower }; @@ -2103,7 +2103,7 @@ static void ath9k_hw_set_4k_addac(struct ath_hal *ah, } } -void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { +static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { ath9k_hw_set_def_addac, ath9k_hw_set_4k_addac }; @@ -2540,8 +2540,8 @@ static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah, return true; } -bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *, - struct ath9k_channel *) = { +static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *, + struct ath9k_channel *) = { ath9k_hw_eeprom_set_def_board_values, ath9k_hw_eeprom_set_4k_board_values }; @@ -2603,8 +2603,9 @@ static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah, return -EINVAL; } -int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *, struct ath9k_channel *, - u8, u16 *) = { +static int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *, + struct ath9k_channel *, + u8, u16 *) = { ath9k_hw_get_def_eeprom_antenna_cfg, ath9k_hw_get_4k_eeprom_antenna_cfg }; @@ -2619,14 +2620,14 @@ int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, index, config); } -u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, - enum ieee80211_band freq_band) +static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) { return 1; } -u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, - enum ieee80211_band freq_band) +static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; @@ -2644,7 +2645,8 @@ u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, return num_ant_config; } -u8 (*ath9k_get_num_ant_config[])(struct ath_hal *, enum ieee80211_band) = { +static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *, + enum ieee80211_band) = { ath9k_hw_get_def_num_ant_config, ath9k_hw_get_4k_num_ant_config }; @@ -2787,7 +2789,7 @@ static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah, } } -u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = { +static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = { ath9k_hw_get_eeprom_def, ath9k_hw_get_eeprom_4k }; -- cgit v1.1 From 11ab72a7c94f3ccac05b85928875fdc4f1ed5e9b Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 26 Dec 2008 00:13:46 -0800 Subject: drivers/net/wireless/b43: fix sparse warnings: make symbols static Fix this sparse warnings: drivers/net/wireless/b43/phy_a.c:80:6: warning: symbol 'b43_radio_set_tx_iq' was not declared. Should it be static? drivers/net/wireless/b43/phy_a.c:150:6: warning: symbol 'b43_radio_init2060' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:57:10: warning: symbol 'b43_radio_channel_codes_bg' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:218:6: warning: symbol 'b43_set_txpower_g' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:386:6: warning: symbol 'b43_nrssi_hw_write' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:393:5: warning: symbol 'b43_nrssi_hw_read' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:404:6: warning: symbol 'b43_nrssi_hw_update' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:418:6: warning: symbol 'b43_nrssi_mem_update' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:592:6: warning: symbol 'b43_calc_nrssi_slope' was not declared. Should it be static? drivers/net/wireless/b43/phy_g.c:1357:5: warning: symbol 'b43_radio_init2050' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: David S. Miller --- drivers/net/wireless/b43/phy_a.c | 4 ++-- drivers/net/wireless/b43/phy_g.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 0f1a84c..7fe9d17 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -77,7 +77,7 @@ static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) } #endif -void b43_radio_set_tx_iq(struct b43_wldev *dev) +static 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 }; @@ -147,7 +147,7 @@ static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) //FIXME b43_phy_xmitpower(dev); } -void b43_radio_init2060(struct b43_wldev *dev) +static void b43_radio_init2060(struct b43_wldev *dev) { b43_radio_write16(dev, 0x0004, 0x00C0); b43_radio_write16(dev, 0x0005, 0x0008); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 3b1d673..caac4a45 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -54,7 +54,7 @@ static const s8 b43_tssi2dbm_g_table[] = { -20, -20, -20, -20, }; -const u8 b43_radio_channel_codes_bg[] = { +static const u8 b43_radio_channel_codes_bg[] = { 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, @@ -215,9 +215,9 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, } /* 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 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; @@ -383,14 +383,14 @@ static void b43_set_original_gains(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); 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) +static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) { u16 val; @@ -401,7 +401,7 @@ s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) { u16 i; s16 tmp; @@ -415,7 +415,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_mem_update(struct b43_wldev *dev) +static void b43_nrssi_mem_update(struct b43_wldev *dev) { struct b43_phy_g *gphy = dev->phy.g; s16 i, delta; @@ -589,7 +589,7 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) b43_phy_write(dev, 0x0811, backup[1]); } -void b43_calc_nrssi_slope(struct b43_wldev *dev) +static void b43_calc_nrssi_slope(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -1354,7 +1354,7 @@ struct init2050_saved_values { u16 phy_syncctl; }; -u16 b43_radio_init2050(struct b43_wldev *dev) +static u16 b43_radio_init2050(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct init2050_saved_values sav; -- cgit v1.1 From a3d1fd23e1ff2deeda0415805cf9a044dda7f55c Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 26 Dec 2008 00:14:41 -0800 Subject: drivers/net/wireless/ipw2x00: fix sparse warnings: make symbols static Fix this sparse warnings: drivers/net/wireless/ipw2x00/ipw2100.c:5271:6: warning: symbol 'ipw2100_queues_initialize' was not declared. Should it be static? drivers/net/wireless/ipw2x00/ipw2100.c:5278:6: warning: symbol 'ipw2100_queues_free' was not declared. Should it be static? drivers/net/wireless/ipw2x00/ipw2100.c:5285:5: warning: symbol 'ipw2100_queues_allocate' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: David S. Miller --- drivers/net/wireless/ipw2x00/ipw2100.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 2d2044d..1667065 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -5268,21 +5268,21 @@ static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, return 0; } -void ipw2100_queues_initialize(struct ipw2100_priv *priv) +static void ipw2100_queues_initialize(struct ipw2100_priv *priv) { ipw2100_tx_initialize(priv); ipw2100_rx_initialize(priv); ipw2100_msg_initialize(priv); } -void ipw2100_queues_free(struct ipw2100_priv *priv) +static void ipw2100_queues_free(struct ipw2100_priv *priv) { ipw2100_tx_free(priv); ipw2100_rx_free(priv); ipw2100_msg_free(priv); } -int ipw2100_queues_allocate(struct ipw2100_priv *priv) +static int ipw2100_queues_allocate(struct ipw2100_priv *priv) { if (ipw2100_tx_allocate(priv) || ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv)) -- cgit v1.1 From 6dd014808f91ad99d4d794cf7c7c69610c10f904 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 26 Dec 2008 00:15:03 -0800 Subject: drivers/net/wireless/prism54: fix sparse warnings: make symbols static Fix this sparse warnings: drivers/net/wireless/prism54/islpci_hotplug.c:97:1: warning: symbol 'prism54_probe' was not declared. Should it be static? drivers/net/wireless/prism54/islpci_hotplug.c:220:1: warning: symbol 'prism54_remove' was not declared. Should it be static? drivers/net/wireless/prism54/islpci_hotplug.c:263:1: warning: symbol 'prism54_suspend' was not declared. Should it be static? drivers/net/wireless/prism54/islpci_hotplug.c:286:1: warning: symbol 'prism54_resume' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: David S. Miller --- drivers/net/wireless/prism54/islpci_hotplug.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index af2e4f2..9a72b1e 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -93,7 +93,7 @@ static struct pci_driver prism54_driver = { Module initialization functions ******************************************************************************/ -int +static int prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *ndev; @@ -216,7 +216,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) static volatile int __in_cleanup_module = 0; /* this one removes one(!!) instance only */ -void +static void prism54_remove(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -259,7 +259,7 @@ prism54_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -int +static int prism54_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -282,7 +282,7 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -int +static int prism54_resume(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); -- cgit v1.1