diff options
Diffstat (limited to 'drivers/net/wireless')
242 files changed, 29375 insertions, 22253 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 45bdf0b339bb..ea543fcf2687 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -123,154 +123,11 @@ 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 IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2100 Network - Connection 802.11b wireless network adapter. - - See <file:Documentation/networking/README.ipw2100> 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 - <http://ipw2100.sf.net/>. 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: - - <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. - - 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 IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network - Connection adapters. - - See <file:Documentation/networking/README.ipw2200> 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 - <http://ipw2200.sf.net/>. 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: - - <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. - - 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 select WIRELESS_EXT + select LIB80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices. @@ -357,6 +214,21 @@ config HERMES configure your card and that /etc/pcmcia/wireless.opts works : <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> +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 @@ -651,7 +523,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. @@ -711,6 +583,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 59d2d805f60b..ac590e1ca8be 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 @@ -16,14 +15,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 @@ -38,6 +30,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 @@ -50,12 +44,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/adm8211.c b/drivers/net/wireless/adm8211.c index b2c050b68890..fc0897fb2239 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; @@ -1298,25 +1297,10 @@ 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, 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) { @@ -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; } @@ -1690,8 +1667,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; @@ -1723,10 +1702,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); @@ -1791,7 +1770,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 +1903,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/adm8211.h b/drivers/net/wireless/adm8211.h index 9b190ee26e90..4f6ab1322189 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; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 370133e492d2..fc4322ca669f 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -47,10 +47,11 @@ #include <linux/ioport.h> #include <linux/pci.h> #include <asm/uaccess.h> -#include <net/ieee80211.h> #include <linux/kthread.h> #include <linux/freezer.h> +#include <linux/ieee80211.h> + #include "airo.h" #define DRV_NAME "airo" @@ -1270,6 +1271,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 +1867,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 +1914,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 +1958,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 +2087,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 +2113,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 +2152,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 +2178,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 +2222,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 +2256,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 +2283,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 +2301,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 +2341,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 +2367,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 +2667,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 +2682,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; @@ -2757,7 +2759,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); @@ -2766,7 +2767,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; @@ -2860,15 +2861,14 @@ 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)) 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; @@ -2917,8 +2917,7 @@ static int waitbusy (struct airo_info *ai) { int reset_airo_card( struct net_device *dev ) { int i; - struct airo_info *ai = dev->priv; - DECLARE_MAC_BUF(mac); + struct airo_info *ai = dev->ml_priv; if (reset_card (dev, 1)) return -1; @@ -2927,8 +2926,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++ ) @@ -2942,7 +2940,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; @@ -3019,7 +3017,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(); @@ -3134,7 +3132,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; @@ -3369,7 +3367,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 ); @@ -3599,7 +3596,6 @@ badmic: skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, ai->dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } badrx: @@ -3611,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; @@ -3693,7 +3689,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: @@ -4604,7 +4599,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; @@ -4687,7 +4682,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; @@ -4750,7 +4745,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; @@ -4962,7 +4957,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; @@ -5053,7 +5048,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; @@ -5096,7 +5091,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; @@ -5191,7 +5186,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; @@ -5233,7 +5228,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; @@ -5282,7 +5277,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; @@ -5326,11 +5321,10 @@ 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; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5354,8 +5348,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"); @@ -5368,13 +5361,12 @@ 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; /* 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 +5403,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)); @@ -5447,7 +5439,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); @@ -5518,7 +5510,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; @@ -5550,7 +5542,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); @@ -5729,7 +5721,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 */ @@ -5774,7 +5766,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; @@ -5805,7 +5797,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 */ @@ -5851,7 +5843,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); @@ -5879,7 +5871,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; @@ -5916,7 +5908,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); @@ -5937,7 +5929,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) { @@ -5960,7 +5952,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); @@ -5979,7 +5971,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; @@ -6049,7 +6041,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); @@ -6071,7 +6063,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) @@ -6095,7 +6087,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); @@ -6114,7 +6106,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) @@ -6139,7 +6131,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); @@ -6158,7 +6150,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); @@ -6221,7 +6213,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 */ @@ -6258,7 +6250,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; @@ -6345,7 +6337,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 */ @@ -6393,7 +6385,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 */ @@ -6479,7 +6471,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 */ @@ -6542,7 +6534,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; @@ -6610,7 +6602,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; @@ -6659,7 +6651,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; @@ -6696,7 +6688,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); @@ -6716,7 +6708,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) { @@ -6754,7 +6746,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 */ @@ -6785,7 +6777,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; @@ -6910,7 +6902,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) { @@ -6967,7 +6959,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); @@ -6998,7 +6990,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 = @@ -7017,7 +7009,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); @@ -7037,7 +7029,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; @@ -7110,7 +7102,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; @@ -7156,7 +7148,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 */ @@ -7274,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; @@ -7338,7 +7327,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; @@ -7382,7 +7371,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; @@ -7527,7 +7516,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; @@ -7655,7 +7644,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 */ @@ -7680,7 +7669,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; @@ -7746,7 +7735,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); @@ -7869,41 +7858,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; } diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index dec5e874a54d..bfca15da6f0f 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) @@ -1535,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/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 53ea439aff48..183ffc8e62ca 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 @@ -817,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 */ @@ -853,7 +850,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 +866,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 +878,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 }; @@ -1030,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; @@ -1064,10 +1087,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; @@ -1081,6 +1105,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; @@ -1321,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/attach.c b/drivers/net/wireless/ath5k/attach.c index 51d569883cdd..dea378f76731 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,15 @@ 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; + 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); + /* 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 2d14255eb103..4af2607deec0 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."); /******************\ @@ -197,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), @@ -219,8 +222,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); @@ -238,7 +240,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, +static int ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb); static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -548,8 +550,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 */ @@ -711,7 +713,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); @@ -781,7 +783,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); @@ -1188,7 +1196,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; @@ -1200,7 +1208,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, @@ -1660,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)) { @@ -1745,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 = ath5k_pad_size(hdrlen); + if (padsize) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } /* @@ -1785,7 +1796,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); @@ -1846,30 +1867,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; @@ -2143,8 +2160,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) @@ -2157,7 +2172,9 @@ 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_MESH_POINT || + 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 @@ -2169,13 +2186,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); } @@ -2215,9 +2234,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_RX | AR5K_INT_TX | 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; @@ -2409,9 +2428,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) { } @@ -2527,8 +2547,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; } @@ -2607,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); @@ -2619,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 = ath5k_pad_size(hdrlen); + if (padsize) { + + 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); @@ -2746,8 +2766,10 @@ 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_MESH_POINT: case NL80211_IFTYPE_MONITOR: sc->opmode = conf->type; break; @@ -2759,6 +2781,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: @@ -2771,11 +2794,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); @@ -2785,10 +2810,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; @@ -2809,7 +2834,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 @@ -2817,18 +2842,17 @@ 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_MESH_POINT || + 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); @@ -2888,9 +2912,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 */ @@ -2948,12 +2972,15 @@ 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->assoc) || - 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; /* 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]); @@ -2970,12 +2997,13 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath5k_softc *sc = hw->priv; int ret = 0; - switch(key->alg) { + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + switch (key->alg) { case ALG_WEP: - /* XXX: fix hardware encryption, its not working. For now - * allow software encryption */ - /* break; */ case ALG_TKIP: + break; case ALG_CCMP: return -EOPNOTSUPP; default: @@ -2994,6 +3022,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 | + IEEE80211_KEY_FLAG_GENERATE_MMIC); break; case DISABLE_KEY: ath5k_hw_reset_key(sc->ah, key->keyidx); @@ -3060,19 +3090,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; @@ -3085,7 +3109,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) mmiowb(); } -end: return ret; } static void diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index 5e362a7a3620..b40a9287a39a 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; diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c index 7adceb2c7fab..7e2b1a67e5da 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/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index a883839b6a9f..1cb7edfae625 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 <reyk@openbsd.org> * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> * * 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 a468ecfbb18a..09eb7d0176a4 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/initvals.c b/drivers/net/wireless/ath5k/initvals.c index ceaa6c475c06..450bd6e945ff 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/pcu.c b/drivers/net/wireless/ath5k/pcu.c index a47df9a24aa1..0cac05c6a9ce 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 */ } /** @@ -258,16 +271,19 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) 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; } @@ -290,8 +306,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 +433,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 +597,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 +682,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 +695,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 +958,26 @@ 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; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; 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) { + 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(micentry, i)); + } + /* * Set NULL encryption on AR5212+ * @@ -916,10 +987,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; } @@ -936,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 */ @@ -943,40 +1037,53 @@ 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; + const u8 *key_ptr; ATH5K_TRACE(ah->ah_sc); - /* key->keylen comes in from mac80211 in bytes */ + is_tkip = (key->alg == ALG_TKIP); - if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + /* + * key->keylen comes in from mac80211 in bytes. + * TKIP is 128 bit + 128 bit mic + */ + keylen = (is_tkip) ? (128 / 8) : key->keylen; + + if (entry > AR5K_KEYTABLE_SIZE || + (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) return -EOPNOTSUPP; - switch (key->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 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; - 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) { + key0 = key_v[0] = ~key_v[0]; + key1 = key_v[1] = ~key_v[1]; } for (i = 0; i < ARRAY_SIZE(key_v); i++) @@ -985,6 +1092,40 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, 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 (ah->ah_combined_mic) { + key_v[0] = rxmic[0]; + key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); + key_v[2] = rxmic[1]; + key_v[3] = cpu_to_le32(le32_to_cpu(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)); + + 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); } diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index e43f6563e61a..7ba18e09463b 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; } @@ -2195,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/qcu.c b/drivers/net/wireless/ath5k/qcu.c index 01bf09176d23..1b7bc50ea8eb 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 e557fe178bbf..91aaeaf88199 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 @@ -1113,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 */ @@ -1726,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 */ /* @@ -1810,6 +1814,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 diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 1b6d45b6772d..dc2d7d8bdb7a 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) | @@ -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 @@ -864,8 +862,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) diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 80a692430413..c43bd321f97f 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 a6411517e5f8..1209d14613ac 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -1,11 +1,16 @@ ath9k-y += hw.o \ + eeprom.o \ + mac.o \ + calib.o \ + ani.o \ phy.o \ regd.o \ beacon.o \ main.o \ recv.o \ xmit.o \ - rc.o \ - core.o + rc.o + +ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c new file mode 100644 index 000000000000..251e2d9a7a4a --- /dev/null +++ b/drivers/net/wireless/ath9k/ani.c @@ -0,0 +1,852 @@ +/* + * 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, + "level out of range (%u > %u)\n", + 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, + "level out of range (%u > %u)\n", + 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, + "level out of range (%u > %u)\n", + 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, + "invalid cmd %u\n", cmd); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); + 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, + "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); + 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 == NL80211_IFTYPE_AP) { + 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 == NL80211_IFTYPE_AP) { + 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 == NL80211_IFTYPE_AP) { + 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 != 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++; + + 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 == NL80211_IFTYPE_AP) { + 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, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + 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, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + 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, + "cycle counter wrap. ExtBusy = 0\n"); + 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 accace5f7efb..d27813502953 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 @@ -138,6 +139,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 @@ -388,22 +402,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 @@ -479,12 +477,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) @@ -493,6 +489,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) || \ @@ -651,13 +648,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 @@ -689,13 +679,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, @@ -778,7 +774,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; @@ -815,195 +812,246 @@ 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); +struct ath_rate_table; + +/* 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, + struct ath_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); +/* 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); +#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); 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) */ + +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/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 4dd1c1bda0fb..3ab0b43aaf93 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 @@ -30,33 +26,38 @@ 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); - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + 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; qi.tqi_cwmin = 0; 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, - "%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 */ + ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */ return 1; } } +static void ath_bstuck_process(struct ath_softc *sc) +{ + DPRINTF(sc, ATH_DBG_BEACON, + "stuck beacon; resetting (bmiss count %u)\n", + sc->beacon.bmisscnt); + 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. @@ -68,21 +69,20 @@ 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; 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; 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; @@ -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; @@ -106,15 +106,15 @@ 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->cur_rate_table; + 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 */ 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, @@ -138,31 +138,26 @@ 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; 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); - cabq = sc->sc_cabq; + avp = (void *)vif->drv_priv; + cabq = sc->beacon.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; } @@ -172,9 +167,10 @@ 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, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); bf->bf_mpdu = skb; if (skb == NULL) return NULL; @@ -186,17 +182,24 @@ 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 = 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, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); /* * if the CABQ traffic from previous DTIM is pending and the current @@ -219,7 +222,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"); } } @@ -232,7 +235,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,17 +247,20 @@ 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", - __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; @@ -264,20 +270,12 @@ 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); - DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__, - sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc); + 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->beacon.beaconq, 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; @@ -290,35 +288,29 @@ 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; 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) { /* 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); - 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; /* @@ -327,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; @@ -341,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++; } } @@ -363,15 +355,14 @@ 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__); + DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); return -ENOMEM; } 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 @@ -402,36 +393,36 @@ 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; 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; } -/* - * 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) { 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--; } @@ -444,19 +435,12 @@ 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; } } -/* - * 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; @@ -473,9 +457,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); } /* @@ -487,67 +469,65 @@ 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, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); 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->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, - "%s: beacon is officially " - "stuck\n", __func__); - ath9k_hw_dmaRegDump(ah); + "beacon is officially " + "stuck\n"); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially stuck\n", - __func__); + "beacon is officially stuck\n"); ath_bstuck_process(sc); } } return; } - if (sc->sc_bmisscount != 0) { + if (sc->beacon.bmisscnt != 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->beacon.bmisscnt); } 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->beacon.bmisscnt); } - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; } /* @@ -562,11 +542,11 @@ 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, - "%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; @@ -594,48 +574,34 @@ 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) - ath_setslottime(sc); /* commit change to hardware */ - + 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) { /* * Stop any current dma and put the new frame(s) on the queue. * 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, - "%s: beacon queue %u did not stop?\n", - __func__, 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? */ } } /* - * 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 @@ -652,15 +618,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; - enum ath9k_opmode av_opmode; + struct ath_vap *avp; + enum nl80211_iftype opmode; u32 nexttbtt, intval; - if (if_id != ATH_IF_ID_ANY) - av_opmode = sc->sc_vaps[if_id]->av_opmode; - else - av_opmode = sc->sc_ah->ah_opmode; + if (if_id != ATH_IF_ID_ANY) { + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + avp = (void *)vif->drv_priv; + opmode = avp->av_opmode; + } else { + opmode = sc->sc_ah->ah_opmode; + } memset(&conf, 0, sizeof(struct ath_beacon_config)); @@ -672,10 +644,10 @@ 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 == 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 @@ -694,11 +666,11 @@ 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) { + /* 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; @@ -782,7 +754,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 " @@ -794,7 +766,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, @@ -818,7 +789,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 @@ -834,8 +805,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); @@ -850,7 +821,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. @@ -860,20 +831,18 @@ 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 * 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); } } -/* 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/calib.c b/drivers/net/wireless/ath9k/calib.c new file mode 100644 index 000000000000..3c7454fc51bd --- /dev/null +++ b/drivers/net/wireless/ath9k/calib.c @@ -0,0 +1,1021 @@ +/* + * 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_CALIBRATE, + "noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + 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_CALIBRATE, + "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_CALIBRATE, + "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_CALIBRATE, + "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_CALIBRATE, + "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 = (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 = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel flags 0x%x\n", 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, + "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, + "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, + "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, + "starting Init ADC DC Calibration\n"); + 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, + "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, + "Calibration state incorrect, %d\n", + currCal->calState); + return; + } + + + if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) + return; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Resetting Cal %d state for channel %u/0x%x\n", + 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, + "NF did not complete in calibration window\n"); + 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, + "noise floor failed detected; " + "detected %d, threshold %d\n", + 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_CALIBRATE, + "invalid channel %u/0x%x; no mapping\n", + 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, + "invalid channel %u/0x%x; no mapping\n", + 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; +} + +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) +{ + 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, + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); + 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); + + 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, + "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, + "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, + "enabling IQ Calibration.\n"); + } + + 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/core.c b/drivers/net/wireless/ath9k/core.c deleted file mode 100644 index c5033f6f42ac..000000000000 --- a/drivers/net/wireless/ath9k/core.c +++ /dev/null @@ -1,1886 +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. - */ - - /* Implementation of the main "ATH" layer. */ - -#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 = - 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 */ -} - -/* - * 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; - - 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]; - - 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 - * 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_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt = 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); - break; - case IEEE80211_BAND_5GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A); - break; - default: - break; - } - - if (rt == NULL) - return; - - sband = &sc->sbands[band]; - rate = sc->rates[band]; - - if (rt->rateCount > ATH_RATE_MAX) - maxrates = ATH_RATE_MAX; - else - maxrates = rt->rateCount; - - for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rt->info[i].rateKbps / 100; - rate[i].hw_value = rt->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; -} - -/* - * 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 - * 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)); -} - -/******************/ -/* 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 */ -/********/ - -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); - - /* - * 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); - - /* - * 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; - /* - * 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; -done: - 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); /* disable interrupts */ - ath_draintxq(sc, retry_tx); /* stop xmit */ - ath_stoprecv(sc); /* stop recv */ - ath_flushrecv(sc); /* flush recv queue */ - - /* 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) /* restart recv */ - 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; -} - -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. */ - -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; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); - - /* Initialize tasklet */ - 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 */ - - spin_lock_init(&sc->sc_resetlock); - - 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; - - /* 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) { - 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 and including outdoor channels. The 802.11 layer - * is resposible for filtering this list based on settings - * like the phy mode. - */ - error = ath_setup_channels(sc); - if (error) - goto bad; - - /* default to STA mode */ - sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; - - /* Setup rate tables */ - - 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 - * 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; - } - - setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - - sc->sc_rc = ath_rate_attach(ah); - if (sc->sc_rc == NULL) { - error = -EIO; - goto bad2; - } - - 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 - - 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; -} - -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); -} - -/*******************/ -/* Node Management */ -/*******************/ - -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); - - /* 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); - - /* set up per-node tx/rx state */ - ath_tx_node_init(sc, an); - ath_rx_node_init(sc, an); - - 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) -{ - 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); - ath_rx_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; -} - -/* - * 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); - if (sc->sc_flags & SC_OP_RXAGGR) - ath_rx_aggr_teardown(sc, an, tidno); - } - } - an->an_flags = 0; -} - -/**************/ -/* 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; - } -} - -/* 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 */ -/**************************/ - -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 cb3e61e57c4d..4ca2aed236e0 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 <linux/version.h> -#include <linux/autoconf.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/ip.h> -#include <linux/tcp.h> -#include <linux/in.h> -#include <linux/delay.h> -#include <linux/wait.h> #include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/list.h> -#include <asm/byteorder.h> -#include <linux/scatterlist.h> -#include <asm/page.h> #include <net/mac80211.h> #include <linux/leds.h> #include <linux/rfkill.h> @@ -47,10 +28,6 @@ struct ath_node; -/******************/ -/* Utility macros */ -/******************/ - /* Macro to expand scalars to 64-bit objects */ #define ito64(x) (sizeof(x) == 8) ? \ @@ -84,94 +61,125 @@ 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<<i)) - -static inline unsigned long get_timestamp(void) -{ - return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ); -} +#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i)) 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) +#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 + +static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, + const char *fmt, ...) +{ +} + +static inline int ath9k_init_debug(struct ath_softc *sc) +{ + return 0; +} -/***************************/ -/* Load-time Configuration */ -/***************************/ +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 */ -/* 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) */ -}; - -/***********************/ -/* Chainmask Selection */ -/***********************/ - -#define ATH_CHAINMASK_SEL_TIMEOUT 6000 -/* Default - Number of last RSSI values that is used for - * chainmask selection */ -#define ATH_CHAINMASK_SEL_RSSI_CNT 10 -/* Means use 3x3 chainmask instead of configured chainmask */ -#define ATH_CHAINMASK_SEL_3X3 7 -/* Default - Rssi threshold below which we have to switch to 3x3 */ -#define ATH_CHAINMASK_SEL_UP_RSSI_THRES 20 -/* Default - Rssi threshold above which we have to switch to - * user configured values */ -#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES 35 -/* Struct to store the chainmask select related info */ -struct ath_chainmask_sel { - struct timer_list timer; - int cur_tx_mask; /* user configured or 3x3 */ - int cur_rx_mask; /* user configured or 3x3 */ - int tx_avgrssi; - u8 switch_allowed:1, /* timer will set this */ - cm_sel_enabled : 1; + u8 cabqReadytime; + u8 swBeaconProcess; }; -int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an); -void ath_update_chainmask(struct ath_softc *sc, int is_ht); - /*************************/ /* Descriptor Management */ /*************************/ @@ -200,15 +208,14 @@ 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 */ - struct ath_rc_series bfs_rcs[4]; /* rate series */ - 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; }; @@ -219,6 +226,7 @@ struct ath_buf_state { #define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_rcs bf_state.bfs_rcs +#define bf_keyix bf_state.bfs_keyix #define bf_keytype bf_state.bfs_keytype #define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) @@ -242,9 +250,7 @@ struct ath_buf { an aggregate) */ struct ath_buf *bf_lastfrm; /* last buf of this frame */ 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 */ @@ -254,13 +260,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 */ @@ -281,159 +280,81 @@ 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, - const char *name, - int nbuf, - int ndesc); -int ath_desc_alloc(struct ath_softc *sc); -void ath_desc_free(struct ath_softc *sc); -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc); +void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head); -/******/ -/* RX */ -/******/ - -#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 { - 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 */ -}; - -/* 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_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); -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); -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 */ -/******/ +/***********/ +/* RX / TX */ +/***********/ +#define ATH_MAX_ANTENNA 3 +#define ATH_RXBUF 512 +#define WME_NUM_TID 16 #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 #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)) -/* 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 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_SM_PWRSAV{ - ATH_SM_ENABLE, - ATH_SM_PWRSAV_STATIC, - ATH_SM_PWRSAV_DYNAMIC, +enum ATH_AGGR_STATUS { + ATH_AGGR_DONE, + ATH_AGGR_BAW_CLOSED, + ATH_AGGR_LIMITED, + ATH_AGGR_SHORTPKT, + ATH_AGGR_8K_LIMITED, }; -/* - * 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 */ @@ -443,10 +364,6 @@ struct ath_txq { u32 axq_depth; /* queue depth */ 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*/ @@ -460,6 +377,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 */ @@ -475,9 +396,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; }; @@ -490,32 +409,10 @@ 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_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 */ @@ -528,21 +425,63 @@ 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 */ -/* 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 + int rssi; + int rssictl[ATH_MAX_ANTENNA]; + int rssiextn[ATH_MAX_ANTENNA]; + int rateieee; + int rateKbps; + int ratecode; + int flags; 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; +}; + +struct ath_tx { + u16 seq_no; + u32 txqsetup; + int hwq_map[ATH9K_WME_AC_VO+1]; + spinlock_t txbuflock; + struct list_head txbuf; + struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; + struct ath_descdma txdma; +}; + +struct ath_rx { + u8 defant; + u8 rxotherant; + u32 *rxlink; + int bufsize; + unsigned int rxfilter; + spinlock_t rxflushlock; + spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; +}; + +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); @@ -550,139 +489,51 @@ 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); 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); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); +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); +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); -/**********************/ -/* 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 */ -/* 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 - -/* 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, -}; - -enum ATH_AGGR_CHECK { - AGGR_NOT_REQUIRED, - AGGR_REQUIRED, - AGGR_CLEANUP_PROGRESS, - AGGR_EXCHANGE_PROGRESS, - AGGR_EXCHANGE_DONE -}; +/********/ +/* VAPs */ +/********/ -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; +/* + * 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. + */ -/* Per-node aggregation state */ -struct ath_node_aggr { - struct ath_atx tx; /* node transmit state */ - struct ath_arx rx; /* node receive state */ -}; +#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ + ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) -/* 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]; +struct ath_vap { + int av_bslot; + enum nl80211_iftype av_opmode; + struct ath_buf *av_bcbuf; + struct ath_tx_control av_btxctl; }; -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); -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); -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); - /*******************/ /* Beacon Handling */ /*******************/ @@ -693,12 +544,11 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); * 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 1 +#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; @@ -712,93 +562,32 @@ struct ath_beacon_config { } u; /* last received beacon/probe response timestamp of this BSS. */ }; +struct ath_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + + u32 beaconq; + u32 bmisscnt; + u32 ast_be_xmit; + u64 bc_tstamp; + int bslot[ATH_BCBUF]; + int slottime; + int slotupdate; + struct ath9k_tx_queue_info beacon_qi; + struct ath_descdma bdma; + struct ath_txq *cabq; + struct list_head bbuf; +}; + void ath9k_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); int ath_beacon_alloc(struct ath_softc *sc, int if_id); -void ath_bstuck_process(struct ath_softc *sc); void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); void ath_beacon_sync(struct ath_softc *sc, int if_id); -void ath_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)) - -/* VAP configuration (from protocol layer) */ -struct ath_vap_config { - u32 av_fixed_rateset; - u32 av_fixed_retryset; -}; - -/* driver-specific vap state */ -struct ath_vap { - struct ieee80211_vif *av_if_data; - enum ath9k_opmode av_opmode; /* VAP operational mode */ - struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_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 */ -/*********************/ - -#define ATH_ANT_DIV_MAX_CFG 2 -#define ATH_ANT_DIV_MIN_IDLE_US 1000000 /* us */ -#define ATH_ANT_DIV_MIN_SCAN_US 50000 /* us */ - -enum ATH_ANT_DIV_STATE{ - ATH_ANT_DIV_IDLE, - ATH_ANT_DIV_SCAN, /* evaluating antenna */ -}; - -struct ath_antdiv { - struct ath_softc *antdiv_sc; - u8 antdiv_start; - enum ATH_ANT_DIV_STATE antdiv_state; - u8 antdiv_num_antcfg; - u8 antdiv_curcfg; - u8 antdiv_bestcfg; - int32_t antdivf_rssitrig; - int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG]; - u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG]; - u64 antdiv_laststatetsf; - u8 antdiv_bssid[ETH_ALEN]; -}; - -void ath_slow_ant_div_init(struct ath_antdiv *antdiv, - struct ath_softc *sc, int32_t rssitrig); -void ath_slow_ant_div_start(struct ath_antdiv *antdiv, - u8 num_antcfg, - const u8 *bssid); -void ath_slow_ant_div_stop(struct ath_antdiv *antdiv); -void ath_slow_ant_div(struct ath_antdiv *antdiv, - struct ieee80211_hdr *wh, - struct ath_rx_status *rx_stats); -void ath_setdefantenna(void *sc, u32 antenna); /*******/ /* ANI */ @@ -863,7 +652,7 @@ struct ath_rfkill { #define DEFAULT_CACHELINE 32 #define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 -#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ +#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -876,34 +665,12 @@ struct ath_rfkill { * Different parts have different size key caches. We handle * up to ATH_KEYMAX entries (could dynamically allocate state). */ -#define ATH_KEYMAX 128 /* max key cache size we handle */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ #define ATH_IF_ID_ANY 0xff #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ - -#define RSSI_LPF_THRESHOLD -20 -#define ATH_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */ -#define ATH_RATE_DUMMY_MARKER 0 -#define ATH_RSSI_LPF_LEN 10 -#define ATH_RSSI_DUMMY_MARKER 0x127 - -#define ATH_EP_MUL(x, mul) ((x) * (mul)) -#define ATH_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((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, @@ -911,19 +678,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; - u16 maxampdu; - u8 mpdudensity; - u8 ext_chan_offset; -}; - #define SC_OP_INVALID BIT(0) #define SC_OP_BEACONS BIT(1) #define SC_OP_RXAGGR BIT(2) @@ -944,141 +698,57 @@ struct ath_softc { struct pci_dev *pdev; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; - struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; void __iomem *mem; + spinlock_t sc_resetlock; + struct mutex mutex; u8 sc_curbssid[ETH_ALEN]; u8 sc_myaddr[ETH_ALEN]; u8 sc_bssidmask[ETH_ALEN]; - - int sc_debug; u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ - unsigned int rx_filter; u16 sc_curtxpow; u16 sc_curaid; u16 sc_cachelsz; - int sc_slotupdate; /* slot to next advance fsm */ - int sc_slottime; - int sc_bslot[ATH_BCBUF]; + u8 sc_nbcnvaps; + u16 sc_nvaps; u8 sc_tx_chainmask; u8 sc_rx_chainmask; + u32 sc_keymax; + DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); + u8 sc_splitmic; + u8 sc_protrix; enum ath9k_int sc_imask; - enum wireless_mode sc_curmode; /* current phy mode */ enum PROT_MODE sc_protmode; - - u8 sc_nbcnvaps; /* # of vaps sending beacons */ - u16 sc_nvaps; /* # of active virtual ap's */ - struct ath_vap *sc_vaps[ATH_BCBUF]; - - u8 sc_mcastantenna; - u8 sc_defant; /* current default antenna */ - 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; + 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 */ - COMMIT /* beacon sent, commit change */ - } sc_updateslot; /* slot time update fsm */ - - /* Crypto */ - u32 sc_keymax; /* size of key cache */ - DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */ - 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 */ - - /* TX */ - struct list_head sc_txbuf; - 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 */ - - /* Beacon */ - struct ath9k_tx_queue_info sc_beacon_qi; - struct ath_descdma sc_bdma; - struct ath_txq *sc_cabq; - struct list_head sc_bbuf; - u32 sc_bhalq; - u32 sc_bmisscount; - u32 ast_be_xmit; /* beacons transmitted */ - u64 bc_tstamp; - - /* Rate */ + struct ath_config sc_config; + struct ath_rx rx; + struct ath_tx tx; + struct ath_beacon beacon; + struct ieee80211_vif *sc_vaps[ATH_BCBUF]; 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 */ - u8 ieeerate; /* IEEE rate */ - } sc_hwmap[256]; /* h/w rate ix mappings */ - - /* Channel, Band */ + struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + struct ath_rate_table *cur_rate_table; struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - - /* Locks */ - spinlock_t sc_rxflushlock; - spinlock_t sc_rxbuflock; - spinlock_t sc_txbuflock; - spinlock_t sc_resetlock; - spinlock_t node_lock; - - /* LEDs */ struct ath_led radio_led; struct ath_led assoc_led; struct ath_led tx_led; struct ath_led rx_led; - - /* Rfkill */ struct ath_rfkill rf_kill; - - /* ANI */ struct ath_ani sc_ani; + struct ath9k_node_stats sc_halstats; +#ifdef CONFIG_ATH9K_DEBUG + struct ath9k_debug sc_debug; +#endif }; -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); -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 *); -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 */ diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c new file mode 100644 index 000000000000..a80ed576830f --- /dev/null +++ b/drivers/net/wireless/ath9k/debug.c @@ -0,0 +1,262 @@ +/* + * 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 "reg.h" +#include "hw.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.debug_mask & dbg_mask) { + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "ath9k: "); + vprintk(fmt, args); + va_end(args); + } +} + +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 +}; + + +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; + + 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; + + 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; + + 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); + return -ENOMEM; +} + +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/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c new file mode 100644 index 000000000000..acd6c5374d44 --- /dev/null +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -0,0 +1,2824 @@ +/* + * 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, + "cannot remap eeprom region \n"); + 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_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_4k *eep = &ahp->ah_eeprom.map4k; + u16 *eep_data; + 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"); + } + + 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 < 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"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_DEF +} + +static 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_def_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + 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)) { + + 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_def); + 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.def.baseEepHeader.length); + else + el = ahp->ah_eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / 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 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 +} + +static 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) +{ + 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_4k_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + 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_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + 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); + + 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_EEP4K_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_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_EEP4K_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) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +#undef TMP_VAL_VPD_TABLE +} + +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; + + 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, int num_band_edges) +{ + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + 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; + 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_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_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; + + 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_def_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_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; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + 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; + + xpdMask = pEepData->modalHeader.xpdGain; + + 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)); + } + + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_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)) { + pRawDataset = pEepData->calPierData2G[i]; + + ath9k_hw_get_4k_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_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; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +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 */ + + struct ath_hal_5416 *ahp = AH5416(ah); + 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; + int16_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} + }; + u16 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; + u16 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 = (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); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + + scaledPower = max((u16)0, 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), AR5416_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 = 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_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + 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_11A_EXT: + case CTL_11G_EXT: + 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((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]; + + 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 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; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + 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; +} + +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 +}; + +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); + + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); + + freqCount++; + + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(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; + } +#undef XPA_LVL_FREQ +} + +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 (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &eep->modalHeader; + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ahp->ah_iniAddac, 7, 1) = + (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } +} + +static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { + ath9k_hw_set_def_addac, + ath9k_hw_set_4k_addac +}; + +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 */ +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_def *eep = &ahp->ah_eeprom.def; + 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, 0, &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; +} + +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; +} + +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 +}; + +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_def *eep = &ahp->ah_eeprom.def; + 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; +} + +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; +} + +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 +}; + +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); +} + +static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +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; + struct modal_eep_header *pModal = + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == 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; +} + +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 +}; + +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); + 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: + 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 +} + +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_def *eep = &ahp->ah_eeprom.def; + 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; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + + default: + return 0; + } +} + +static 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; + + 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 98bc25c9b3cf..34474edefc97 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -23,277 +23,93 @@ #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} - }, -}; - -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 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_G(chan)) - return ATH9K_MODE_11G; - return ATH9K_MODE_11A; -} -static bool ath9k_hw_wait(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 val) -{ - int i; +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; - for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) { - if ((REG_READ(ah, reg) & mask) == val) - return true; +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_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); - 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; -} +/********************/ +/* Helper Functions */ +/********************/ -static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, - u16 *data) +static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) { - (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; + 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 int ath9k_hw_flash_map(struct ath_hal *ah) +static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) { - struct ath_hal_5416 *ahp = AH5416(ah); - - ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + struct ath9k_channel *chan = ah->ah_curchan; - if (!ahp->ah_cal_mem) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: cannot remap eeprom region \n", __func__); - return -EIO; - } + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_usec(ah, clks) / 2; + else + return ath9k_hw_mac_usec(ah, clks); +} - return 0; +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 bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, - u16 *data) +static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) { - struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; - *data = ioread16(ahp->ah_cal_mem + off); - return true; + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_clks(ah, usecs) * 2; + else + return ath9k_hw_mac_clks(ah, usecs); } -static void ath9k_hw_read_revisions(struct ath_hal *ah) +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan) { - u32 val; - - val = REG_READ(ah, AR_SREV) & AR_SREV_ID; + if (IS_CHAN_B(chan)) + return ATH9K_MODE_11B; + if (IS_CHAN_G(chan)) + return ATH9K_MODE_11G; - if (val == 0xFF) { - val = REG_READ(ah, AR_SREV); + return ATH9K_MODE_11A; +} - ah->ah_macVersion = - (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) +{ + int i; - ah->ah_macRev = MS(val, AR_SREV_REVISION2); - ah->ah_isPciExpress = - (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; + for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) { + if ((REG_READ(ah, reg) & mask) == val) + return true; - } else { - if (!AR_SREV_9100(ah)) - ah->ah_macVersion = MS(val, AR_SREV_VERSION); + udelay(AH_TIME_QUANTUM); + } - ah->ah_macRev = val & AR_SREV_REVISION; + 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); - 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,596 +124,215 @@ 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 = 0; -} - -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_bb(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 synthDelay; - - 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; - - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - - udelay(synthDelay + BASE_ACTIVATE_DELAY); -} - -static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) -{ - 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 ((flags & CHANNEL_2GHZ)) { + *low = pCap->low_2ghz_chan; + *high = pCap->high_2ghz_chan; + return true; } + return false; } -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); - - 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 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 u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp, - enum ieee80211_band freq_band) +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + struct ath_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble) { - 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; -} + u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; + u32 kbps; -static int -ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp, - struct ath9k_channel *chan, - u8 index, - u16 *config) -{ - 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; + kbps = rates->info[rateix].ratekbps; - switch (index) { - case 0: - *config = pModal->antCtrlCommon & 0xFFFF; + if (kbps == 0) return 0; - case 1: - if (pBase->version >= 0x0E0D) { - if (pModal->useAnt1) { - *config = - ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); - return 0; - } + + switch (rates->info[rateix].phy) { + 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 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); + 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_REG_IO, + "Unknown phy %u (rate ix %u)\n", + rates->info[rateix].phy, rateix); + txTime = 0; break; } - return -EINVAL; -} - -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); + return txTime; } -static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) { - 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; + 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); + } } - eep_data++; + return (freq - 5000) / 5; } - 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) +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers) { - struct modal_eep_header *pModal; - int i, regChainOffset; + int8_t extoff; 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)]); + if (!IS_CHAN_HT40(chan)) { + centers->ctl_center = centers->ext_center = + centers->synth_center = chan->channel; + return; + } - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + 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; + } - ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config); - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + 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)); - 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)); - } - } - } +/******************/ +/* Chip Revisions */ +/******************/ - 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); - } +static void ath9k_hw_read_revisions(struct ath_hal *ah) +{ + u32 val; - 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); + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; - 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); + 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 { - 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 (!AR_SREV_9100(ah)) + ah->ah_macVersion = MS(val, AR_SREV_VERSION); - 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); - } + ah->ah_macRev = val & AR_SREV_REVISION; - 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); + if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) + ah->ah_isPciExpress = true; } - - return true; } -static int ath9k_hw_check_eeprom(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { - u32 sum = 0, el; - u16 *eepdata; + u32 val; 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; + REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; + 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); - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; + return ath9k_hw_reverse_bits(val, 8); +} - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } +/************************************/ +/* HW Attach, Detach, Init Routines */ +/************************************/ - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } - } - } +static void ath9k_hw_disablepcie(struct ath_hal *ah) +{ + if (!AR_SREV_9100(ah)) + return; - 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; - } + 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 0; + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } static bool ath9k_hw_chip_test(struct ath_hal *ah) @@ -905,9 +340,9 @@ 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 }; + 0xaaaaaaaa, + 0x66666666, + 0x99999999 }; int i, j; for (i = 0; i < 2; i++) { @@ -921,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 " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); return false; } } @@ -933,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 " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); return false; } } @@ -945,213 +380,65 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah) 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) +static const char *ath9k_hw_devname(u16 devid) { - 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); + switch (devid) { + case AR5416_DEVID_PCI: + return "Atheros 5416"; + case AR5416_DEVID_PCIE: + return "Atheros 5418"; + case AR9160_DEVID_PCI: + return "Atheros 9160"; + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + return "Atheros 9280"; + case AR9285_DEVID_PCIE: + return "Atheros 9285"; } - 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)); + return NULL; } -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt) +static void ath9k_hw_set_defaults(struct ath_hal *ah) { - static u32 cycles, rx_clear, rx_frame, tx_frame; - u32 good = 1; + int i; - 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; + ah->ah_config.intr_mitigation = 1; } -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); -} - - static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, void __iomem *mem, @@ -1165,20 +452,16 @@ 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; } 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 +473,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,163 +491,6 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, return ahp; } -static 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; -} - -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param) -{ - 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; - } -} - -static int ath9k_hw_get_radiorev(struct ath_hal *ah) -{ - u32 val; - int i; - - 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); -} - -static int ath9k_hw_init_macaddr(struct ath_hal *ah) -{ - u32 sum; - int i; - u16 eeval; - struct ath_hal_5416 *ahp = AH5416(ah); - DECLARE_MAC_BUF(mac); - - sum = 0; - for (i = 0; i < 3; i++) { - eeval = ath9k_hw_get_eeprom(ahp, 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: %s\n", __func__, - print_mac(mac, 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) -{ - 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; -} - static int ath9k_hw_rfattach(struct ath_hal *ah) { bool rfStatus = false; @@ -1375,8 +499,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; } @@ -1401,9 +524,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; } @@ -1412,1473 +535,76 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah) return 0; } -static void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - 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); - - if (chan && IS_CHAN_5GHZ(chan)) { - pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - - - 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); - } - - } else if (AR_SREV_9160_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); - - 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; - - 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); - } - } - 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); - - 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; - - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) - phymode |= AR_PHY_FC_DYN2040_PRI_CH; - - 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); - - 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_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; - } -} - -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); - - REG_WRITE(ah, AR_PHY_MODE, rfMode); -} - -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__); - return false; - } - - 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 -struct ath9k_channel *ath9k_hw_check_chan(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; - } - - 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) +static int ath9k_hw_init_macaddr(struct ath_hal *ah) { + u32 sum; 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) -{ + u16 eeval; 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; - } + sum = 0; + for (i = 0; i < 3; 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; } - -#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; - } + if (sum == 0 || sum == 0xffff * 3) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "mac address read failed: %pM\n", + ahp->ah_macaddr); + return -EADDRNOTAVAIL; } - 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) +static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah) { + u32 rxgain_type; 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; + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { + rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE); - 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 (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 - 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; - - 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_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; + 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); } -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan) +static void ath9k_hw_init_txgain_ini(struct ath_hal *ah) { + u32 txgain_type; 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 (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE); - 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; - } + 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) @@ -2887,7 +613,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; } @@ -2906,365 +632,17 @@ static int ath9k_hw_post_attach(struct ath_hal *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; + return 0; } -static struct ath_hal *ath9k_hw_do_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *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 + u32 i, j; ahp = ath9k_hw_newstate(devid, sc, mem, status); if (ahp == NULL) @@ -3278,15 +656,13 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, 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; } @@ -3300,18 +676,18 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, SER_REG_MODE_OFF; } } + 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))) { + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(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; } @@ -3341,8 +717,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, ahp->ah_adcDcCalInitData.calData = &adc_init_dc_cal; } - ahp->ah_suppCals = - ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; } if (AR_SREV_9160(ah)) { @@ -3352,16 +727,46 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, } 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; + 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); + "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, @@ -3369,21 +774,16 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, 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); + 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); + 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); + 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); @@ -3469,13 +869,20 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, if (ah->ah_isPciExpress) ath9k_hw_configpcipowersave(ah, 0); else - ar5416DisablePciePhy(ah); + ath9k_hw_disablepcie(ah); ecode = ath9k_hw_post_attach(ah); if (ecode != 0) goto bad; -#ifndef CONFIG_SLOW_ANT_DIV + /* rxgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_rxgain_ini(ah); + + /* txgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_txgain_ini(ah); + 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); @@ -3484,16 +891,16 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, 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); } } } -#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; } @@ -3501,8 +908,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, 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; } @@ -3511,1106 +917,569 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, 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) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { - if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); - ath9k_hw_rfdetach(ah); + u32 synthDelay; - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - kfree(ah); + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + udelay(synthDelay + BASE_ACTIVATE_DELAY); } -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high) +static void ath9k_hw_init_qos(struct ath_hal *ah) { - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); + REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - 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; + 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)); - return true; - } - return false; + 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 inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, - u8 pwrMax, - u8 *pPwrList, - u8 *pVpdList, - u16 - numIntercepts, - u8 *pRetVpdList) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { - 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; - } + u32 pll; - return true; -} + 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); -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; + 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); - ath9k_hw_get_channel_centers(ah, chan, ¢ers); + if (chan && IS_CHAN_5GHZ(chan)) { + pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - 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])); + 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); } - } - } - *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); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { - pPdGainBoundaries[i] = - min((u16) AR5416_MAX_RATE_POWER, - pPdGainBoundaries[i]); + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } + 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 (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t) (0 - (minPwrT4[i] / 2)); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_9160_PLL_DIV); else - ss = 0; + pll |= SM(0x58, AR_RTC_9160_PLL_DIV); } 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; + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - while ((ss < maxIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } + 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); - 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++; - } + 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); - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } + udelay(RTC_PLL_SETTLE_DELAY); - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - return; + REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); } -static bool -ath9k_hw_set_power_cal_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) +static void ath9k_hw_init_chain_masks(struct ath_hal *ah) { - 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); + int rx_chainmask, tx_chainmask; - 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; + rx_chainmask = ahp->ah_rxchainmask; + tx_chainmask = ahp->ah_txchainmask; - 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++; + switch (rx_chainmask) { + case 0x5: + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + case 0x3: + if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) { + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); + break; } + case 0x1: + case 0x2: + case 0x7: + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); + break; + default: + break; } - 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; - } - } + REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); + if (tx_chainmask == 0x5) { + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); } - *pTxPowerIndexOffset = 0; - - return true; + if (AR_SREV_9100(ah)) + REG_WRITE(ah, AR_PHY_ANALOG_SWAP, + REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); } -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, + enum nl80211_iftype opmode) { struct ath_hal_5416 *ahp = AH5416(ah); - u8 i; - - if (ah->ah_isPciExpress != true) - return; - if (ah->ah_config.pcie_powersave_enable == 2) - return; + ahp->ah_maskReg = AR_IMR_TXERR | + AR_IMR_TXURN | + AR_IMR_RXERR | + AR_IMR_RXORN | + AR_IMR_BCNMISC; - if (restore) - return; + if (ahp->ah_intrMitigation) + ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; + else + ahp->ah_maskReg |= AR_IMR_RXOK; - 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); + ahp->ah_maskReg |= AR_IMR_TXOK; - REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); - REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); + if (opmode == NL80211_IFTYPE_AP) + ahp->ah_maskReg |= AR_IMR_MIB; - 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_IMR, ahp->ah_maskReg); + REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + 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); + } +} - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); +static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - udelay(1000); + if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); + ahp->ah_acktimeout = (u32) -1; + return false; } 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_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); + ahp->ah_acktimeout = us; + return true; } +} - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); +static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - if (ah->ah_config.pcie_waen) { - REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); + if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); + ahp->ah_ctstimeout = (u32) -1; + return false; } else { - if (AR_SREV_9280(ah)) - REG_WRITE(ah, AR_WA, 0x0040073f); - else - REG_WRITE(ah, AR_WA, 0x0000073f); + REG_RMW_FIELD(ah, AR_TIME_OUT, + AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); + ahp->ah_ctstimeout = us; + return true; } } -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 bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu) { - 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; + struct ath_hal_5416 *ahp = AH5416(ah); - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; + if (tu > 0xFFFF) { + DPRINTF(ah->ah_sc, ATH_DBG_XMIT, + "bad global tx timeout %u\n", tu); + ahp->ah_globaltxtimeout = (u32) -1; + return false; } 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; + REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); + ahp->ah_globaltxtimeout = tu; + return true; } +} - 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_init_user_settings(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + 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, + 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); } -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) +const char *ath9k_hw_probe(u16 vendorid, u16 devid) { - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; + return vendorid == ATHEROS_VENDOR_ID ? + ath9k_hw_devname(devid) : NULL; +} - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = isHt40Target ? centers.synth_center : centers.ctl_center; +void ath9k_hw_detach(struct ath_hal *ah) +{ + if (!AR_SREV_9100(ah)) + ath9k_hw_ani_detach(ah); - 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; - } + ath9k_hw_rfdetach(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + kfree(ah); +} - 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]); - } +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: + case AR9285_DEVID_PCIE: + ah = ath9k_hw_do_attach(devid, sc, mem, error); + break; + default: + *error = -ENXIO; + break; } + + return ah; } -static u16 -ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz) +/*******/ +/* INI */ +/*******/ + +static void ath9k_hw_override_ini(struct ath_hal *ah, + struct ath9k_channel *chan) { - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - int i; + /* + * 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)); - 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; + + if (!AR_SREV_5416_V20_OR_LATER(ah) || + AR_SREV_9280_10_OR_LATER(ah)) + return; + + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); +} + +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); + + 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"); } - break; + + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "final ini VAL: %x\n", value); } + break; } - return twiceMaxEdgePower; + + return value; } -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) +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) { - u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + struct ath_hal_5416 *ahp = AH5416(ah); - 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; + 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) +{ + int i, regWrites = 0; struct ath_hal_5416 *ahp = AH5416(ah); + u32 modesIndex, freqIndex; + int status; - tx_chainmask = ahp->ah_txchainmask; + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_B: + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; + freqIndex = 2; + break; - ath9k_hw_get_channel_centers(ah, chan, ¢ers); + default: + return -EINVAL; + } - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + REG_WRITE(ah, AR_PHY(0), 0x00000007); - twiceLargestAntenna = max((u8) twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); - twiceLargestAntenna = - (int8_t) min(AntennaReduction - twiceLargestAntenna, 0); + ath9k_hw_set_addac(ah, chan); - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + if (AR_SREV_5416_V22_OR_LATER(ah)) { + REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites); + } else { + struct ar5416IniArray temp; + u32 addacSize = + sizeof(u32) * ahp->ah_iniAddac.ia_rows * + ahp->ah_iniAddac.ia_columns; - if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->ah_tpScale)] * 2); - } + memcpy(ahp->ah_addac5416_21, + ahp->ah_iniAddac.ia_array, addacSize); - scaledPower = min(powerLimit, maxRegAllowedPower); + (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0; - 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; + 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); } - 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); + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); - 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 { + for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); + u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex); - 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); + REG_WRITE(ah, reg, val); - 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); + if (reg >= 0x7800 && reg < 0x78a0 + && ah->ah_config.analog_shiftreg) { + udelay(100); } + + DO_DELAY(regWrites); } - 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 (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites); - if (ar5416_get_eep_ver(ahp) == 14 - && ar5416_get_eep_rev(ahp) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + if (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites); - 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 < ahp->ah_iniCommon.ia_rows; i++) { + u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0); + u32 val = INI_RA(&ahp->ah_iniCommon, i, 1); - 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; - } - } + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 + && ah->ah_config.analog_shiftreg) { + udelay(100); } - minCtlPower = min(twiceMaxEdgePower, scaledPower); + DO_DELAY(regWrites); + } + + ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); - 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; - } + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { + REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex, + regWrites); } - 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]; - ; + ath9k_hw_override_ini(ah, chan); + ath9k_hw_set_regs(ah, chan, macmode); + ath9k_hw_init_chain_masks(ah); + + status = 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)); + if (status != 0) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "error init'ing transmit power\n"); + return -EIO; } - 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]; - } + + if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "ar5416SetRfRegs failed\n"); + return -EIO; } - return true; + + return 0; } -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) +/****************************************/ +/* Reset and Channel Switching Routines */ +/****************************************/ + +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; + u32 rfMode = 0; - memset(ratesArray, 0, sizeof(ratesArray)); + if (chan == NULL) + return; - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - 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 (!AR_SREV_9280_10_OR_LATER(ah)) + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; - 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; - } + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - 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; - } + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } +static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} - 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) - ); - } +static inline void ath9k_hw_set_dma(struct ath_hal *ah) +{ + u32 regval; - 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) - ); + regval = REG_READ(ah, AR_AHB_MODE); + REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); - 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) - ); - } + regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0) - ); + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); - i = rate6mb; - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; + regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->ah_maxPowerLevel = ratesArray[i]; + REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); - return 0; + 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 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 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 NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + break; + } } static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, @@ -4632,9 +1501,8 @@ static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, *coef_exponent = coef_exp - 16; } -static void -ath9k_hw_set_delta_slope(struct ath_hal *ah, - struct ath9k_channel *chan) +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; @@ -4667,8 +1535,243 @@ ath9k_hw_set_delta_slope(struct ath_hal *ah, AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); } -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) +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, + "RTC stuck in MAC reset\n"); + 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, "RTC not waking up\n"); + return false; + } + + 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_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 | enableDacFifo; + + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN; + + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; + + 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); + + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); +} + +static bool ath9k_hw_chip_reset(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; + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; + + ahp->ah_chipFullSleep = false; + + ath9k_hw_init_pll(ah, chan); + + ath9k_hw_set_rfmode(ah, chan); + + return true; +} + +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; not marked as " + "2GHz or 5GHz\n", chan->channel, chan->channelFlags); + return NULL; + } + + if (!IS_CHAN_OFDM(chan) && + !IS_CHAN_B(chan) && + !IS_CHAN_HT20(chan) && + !IS_CHAN_HT40(chan)) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; not marked as " + "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", + chan->channel, chan->channelFlags); + return NULL; + } + + 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) +{ + u32 synthDelay, qnum; + + for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { + if (ath9k_hw_numtxpending(ah, qnum)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "Transmit frames pending on queue %d\n", qnum); + return false; + } + } + + 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_REG_IO, + "Could not kill baseband RX\n"); + return false; + } + + ath9k_hw_set_regs(ah, chan, macmode); + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "failed to set channel\n"); + return false; + } + } else { + if (!(ath9k_hw_set_channel(ah, chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "failed to set channel\n"); + return false; + } + } + + 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, + "error init'ing transmit power\n"); + return false; + } + + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + udelay(synthDelay + BASE_ACTIVATE_DELAY); + + 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 (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; @@ -4918,8 +2021,7 @@ static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, 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) +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) { int bb_spur = AR_NO_SPUR; int bin, cur_bin; @@ -5120,752 +2222,11 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static void ath9k_hw_init_chain_masks(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int rx_chainmask, tx_chainmask; - - rx_chainmask = ahp->ah_rxchainmask; - tx_chainmask = ahp->ah_txchainmask; - - switch (rx_chainmask) { - case 0x5: - REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, - AR_PHY_SWAP_ALT_CHAIN); - case 0x3: - if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) { - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); - break; - } - 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); - break; - default: - break; - } - - REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); - if (tx_chainmask == 0x5) { - REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, - AR_PHY_SWAP_ALT_CHAIN); - } - if (AR_SREV_9100(ah)) - REG_WRITE(ah, AR_PHY_ANALOG_SWAP, - REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); -} - -static 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; - } -} - -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 u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) -{ - struct ath9k_channel *chan = ah->ah_curchan; - - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_usec(ah, clks) / 2; - else - return ath9k_hw_mac_usec(ah, clks); -} - -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 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); - ahp->ah_acktimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_TIME_OUT, - AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_acktimeout = us; - return true; - } -} - -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); - ahp->ah_ctstimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_TIME_OUT, - AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_ctstimeout = us; - return true; - } -} -static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, - u32 tu) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - if (tu > 0xFFFF) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: bad global tx timeout %u\n", __func__, tu); - ahp->ah_globaltxtimeout = (u32) -1; - return false; - } else { - REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); - ahp->ah_globaltxtimeout = tu; - return true; - } -} - -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); - 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; - } -} - -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); - 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); -} - -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); - u32 modesIndex, freqIndex; - int status; - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; - freqIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - freqIndex = 1; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - freqIndex = 2; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; - freqIndex = 2; - break; - - default: - return -EINVAL; - } - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - - REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); - - ath9k_hw_set_addac(ah, chan); - - if (AR_SREV_5416_V22_OR_LATER(ah)) { - REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites); - } else { - struct ar5416IniArray temp; - u32 addacSize = - sizeof(u32) * ahp->ah_iniAddac.ia_rows * - ahp->ah_iniAddac.ia_columns; - - memcpy(ahp->ah_addac5416_21, - ahp->ah_iniAddac.ia_array, addacSize); - - (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++) { - 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 - && ah->ah_config.analog_shiftreg) { - udelay(100); - } - - DO_DELAY(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); - - REG_WRITE(ah, reg, val); - - if (reg >= 0x7800 && reg < 0x78a0 - && ah->ah_config.analog_shiftreg) { - udelay(100); - } - - DO_DELAY(regWrites); - } - - ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { - REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex, - regWrites); - } - - ath9k_hw_override_ini(ah, chan); - ath9k_hw_set_regs(ah, chan, macmode); - ath9k_hw_init_chain_masks(ah); - - status = 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)); - if (status != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%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__); - return -EIO; - } - - return 0; -} - -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 inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, - int init_cal_count) -{ - 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; - } - - 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; - } - } - - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; - return true; -} - -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); - return false; - } - } - - 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__); - return false; - } - - ath9k_hw_set_regs(ah, chan, macmode); - - 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__); - return false; - } - } else { - if (!(ath9k_hw_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); - return false; - } - } - - 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) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error init'ing transmit power\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; - - udelay(synthDelay + BASE_ACTIVATE_DELAY); - - 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 (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 bool ath9k_hw_chip_reset(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; - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; - - ahp->ah_chipFullSleep = false; - - ath9k_hw_init_pll(ah, chan); - - ath9k_hw_set_rfmode(ah, chan); - - return true; -} - -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); - } -} - -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; - } -} - -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); -} - -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 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; -} - - -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); @@ -5886,8 +2247,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); + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); ecode = -EINVAL; goto bad; } @@ -5907,8 +2268,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ((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); @@ -5930,8 +2290,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, 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; } @@ -5965,7 +2324,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__); + "error setting board options\n"); ecode = -EIO; goto bad; } @@ -6016,7 +2375,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, 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 @@ -6055,15 +2414,13 @@ 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); + "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 @@ -6078,693 +2435,402 @@ 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, + "entry %u out of range\n", 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); - } - } - } + keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - if (longcal) { - ath9k_hw_getnf(ah, ichan); - ath9k_hw_loadnf(ah, ah->ah_curchan); - ath9k_hw_start_nfcal(ah); + 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 ((ichan->channelFlags & CHANNEL_CW_INT) != 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); - chan->channelFlags |= CHANNEL_CW_INT; - ichan->channelFlags &= ~CHANNEL_CW_INT; - } } + if (ah->ah_curchan == NULL) + return true; + return true; } -static void ath9k_hw_iqcal_collect(struct ath_hal *ah) +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) { - struct ath_hal_5416 *ahp = AH5416(ah); - int i; + u32 macHi, macLo; - 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]); + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); + return false; } -} -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]); + 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; } -} - -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - 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]); - } + return true; } -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) +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); - 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 (entry >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); + return false; + } - if (iqCorrMeas > 0x80000000) { - iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; - iqCorrNeg = 1; + 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, + "AES-CCM not supported by mac rev 0x%x\n", + ah->ah_macRev); + return false; } - - 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 = 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, + "entry %u inappropriate for TKIP\n", entry); + return false; } - } - - 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); + break; + case ATH9K_CIPHER_WEP: + if (k->kv_len < LEN_WEP40) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "WEP key length %u too small\n", 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, + "cipher %u not supported\n", k->kv_type); + return false; } - 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); -} - -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; + 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; - ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; - 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; + 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); - return true; -} + if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { + u32 mic0, mic1, mic2, mic3, mic4; -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); + 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); - if (!IS_CHAN_HT40(chan)) { - centers->ctl_center = centers->ext_center = - centers->synth_center = chan->channel; - return; - } + } else { + u32 mic0, mic2; - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) { - centers->synth_center = - chan->channel + HT40_CHANNEL_CENTER_SHIFT; - extoff = 1; + 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 { - centers->synth_center = - chan->channel - HT40_CHANNEL_CENTER_SHIFT; - extoff = -1; + 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); } - 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)); + if (ah->ah_curchan == NULL) + return true; + return true; } -void -ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone) +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) { - 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 (entry < ah->ah_caps.keycache_size) { + u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return true; } - - - 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; + return false; } -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) +/******************************/ +/* Power Management (Chipset) */ +/******************************/ + +static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) { - struct ath_hal_5416 *ahp = AH5416(ah); + 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); - memcpy(mac, ahp->ah_macaddr, ETH_ALEN); + REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), + AR_RTC_RESET_EN); + } } -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) +static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) { - struct ath_hal_5416 *ahp = AH5416(ah); + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - memcpy(ahp->ah_macaddr, mac, ETH_ALEN); - return true; + 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); + } + } } -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) +static bool ath9k_hw_set_power_awake(struct ath_hal *ah, + int setChip) { - struct ath_hal_5416 *ahp = AH5416(ah); + u32 val; + int i; - memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); -} + 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); -bool -ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + udelay(50); - memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); + 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, + "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); + return false; + } + } - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); return true; } -void -ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId) +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; - 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)); -} - -u64 ath9k_hw_gettsf64(struct ath_hal *ah) -{ - u64 tsf; - - tsf = REG_READ(ah, AR_TSF_U32); - tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - return tsf; -} - -void ath9k_hw_reset_tsf(struct ath_hal *ah) -{ - int count; + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); - 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); + 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, + "Unknown power mode %u\n", mode); + return false; } - 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; -} + ahp->ah_powerMode = mode; -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) -{ - REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); + return status; } -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_configpcipowersave(struct ath_hal *ah, int restore) { struct ath_hal_5416 *ahp = AH5416(ah); - static u8 tx_chainmask_cfg, rx_chainmask_cfg; + u8 i; - if (AR_SREV_9280(ah)) { - if (!tx_chainmask_cfg) { + if (ah->ah_isPciExpress != true) + return; - tx_chainmask_cfg = *tx_chainmask; - rx_chainmask_cfg = *rx_chainmask; - } + if (ah->ah_config.pcie_powersave_enable == 2) + return; - 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 (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)); } - } else { - ahp->ah_diversityControl = settings; - } + 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); - return true; -} + REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); + REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); -void ath9k_hw_setopmode(struct ath_hal *ah) -{ - ath9k_hw_set_operating_mode(ah, ah->ah_opmode); -} + if (ah->ah_config.pcie_clock_req) + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); + else + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); -bool -ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, - u32 capability, u32 *result) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); - 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; - } -} + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); -int -ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) -{ - 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; + 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); + } - halNumAntConfig = - IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap-> - num_antcfg_5ghz; + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - 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_waen) { + REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); + } else { + 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, AR_WA_DEFAULT); } - return -EINVAL; } +/**********************/ +/* Interrupt Handling */ +/**********************/ + bool ath9k_hw_intrpend(struct ath_hal *ah) { u32 host_isr; @@ -6791,6 +2857,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) { @@ -6800,9 +2867,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; @@ -6814,8 +2880,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); @@ -6842,7 +2906,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; } @@ -6867,8 +2930,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)) { @@ -6881,8 +2943,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 & @@ -6892,32 +2956,29 @@ 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); (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); } + return true; } @@ -6933,12 +2994,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)) { @@ -6993,8 +3052,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 | @@ -7014,8 +3072,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, @@ -7035,9 +3092,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; @@ -7045,14 +3104,14 @@ ath9k_hw_beaconinit(struct ath_hal *ah, 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, @@ -7060,7 +3119,7 @@ ath9k_hw_beaconinit(struct ath_hal *ah, (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 - @@ -7073,6 +3132,12 @@ ath9k_hw_beaconinit(struct ath_hal *ah, 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)); @@ -7089,9 +3154,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; @@ -7120,14 +3184,10 @@ 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)); @@ -7154,1424 +3214,682 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, } -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; -} +/*******************/ +/* HW Capabilities */ +/*******************/ -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) +bool ath9k_hw_fill_cap_info(struct ath_hal *ah) { - u32 keyType; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 capField = 0, eeval; - 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)); + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0); - 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); + ah->ah_currentRD = eeval; - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1); + ah->ah_currentRDExt = eeval; - 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); + capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP); + 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; + else if (ah->ah_currentRD == 0x41) + ah->ah_currentRD = 0x43; + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + "regdomain mapped to 0x%x\n", ah->ah_currentRD); } - if (ah->ah_curchan == NULL) - return true; - - 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; - } + eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE); + bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - 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; + 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); + } + } } - 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 (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); + } } - 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); - - if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { - u32 mic0, mic1, mic2, mic3, mic4; - - 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); - - } else { - u32 mic0, mic2; - - 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); + 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 { - 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); + pCap->rx_chainmask = + (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; } - if (ah->ah_curchan == NULL) - return true; - - 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; - - 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)); + if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) + ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; - ath9k_hw_set_interrupts(ah, omask); + pCap->low_2ghz_chan = 2312; + pCap->high_2ghz_chan = 2732; - ah->ah_txTrigLevel = newLevel; + pCap->low_5ghz_chan = 4920; + pCap->high_5ghz_chan = 6100; - return newLevel != curLevel; -} + pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; -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; + pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } + pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - 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; - } + if (ah->ah_config.ht_enable) + pCap->hw_caps |= ATH9K_HW_CAP_HT; + else + pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi); + 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; - 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); + if (capField & AR_EEPROM_EEPCAP_MAXQCU) + pCap->total_queues = + MS(capField, AR_EEPROM_EEPCAP_MAXQCU); 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; + pCap->total_queues = ATH9K_NUM_TX_QUEUES; - 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); + if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) + pCap->keycache_size = + 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); 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; -} + pCap->keycache_size = AR_KEYTABLE_SIZE; -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; + pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; + pCap->num_mr_retries = 4; + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } + if (AR_SREV_9280_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR928X_NUM_GPIO; + else + pCap->num_gpio_pins = AR_NUM_GPIO; - 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; + 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; } - 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; + 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); + } - return true; -} + pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; -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; +#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 = + MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); + ah->ah_rfkill_polarity = + MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - 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; + 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; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + 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; - 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; + 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 { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; } - return q; -} + pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; -static void -ath9k_hw_set_txq_interrupts(struct ath_hal *ah, - struct ath9k_tx_queue_info *qi) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + pCap->num_antcfg_5ghz = + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); + pCap->num_antcfg_2ghz = + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - 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); + return true; } -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + 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; - } - 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); + 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; } - - 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) +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); - 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; + u32 v; - 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); + 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; - } - - 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; + 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 - 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; + 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: - 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); + return false; } - - 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; } -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); -} +/****************************/ +/* GPIO / RFKILL / Antennae */ +/****************************/ -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) +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, + u32 gpio, u32 type) { - struct ar5416_desc *ads = AR5416DESC(ds); + int addr; + u32 gpio_shift, tmp; - 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; -} + if (gpio > 11) + addr = AR_GPIO_OUTPUT_MUX3; + else if (gpio > 5) + addr = AR_GPIO_OUTPUT_MUX2; + else + addr = AR_GPIO_OUTPUT_MUX1; -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; - } + gpio_shift = (gpio % 6) * 5; - 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; + 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); } - - 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) +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) { - 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); + u32 gpio_shift; - ads->ds_ctl6 = SM(keyType, AR_EncrType); + ASSERT(gpio < ah->ah_caps.num_gpio_pins); - if (AR_SREV_9285(ah)) { + gpio_shift = gpio << 1; - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; - } + 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_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) +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) { - 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; - } + if (gpio >= ah->ah_caps.num_gpio_pins) + return 0xffffffff; - ads->ds_ctl0 = ds_ctl0; + 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 { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & + AR_GPIO_BIT(gpio)) != 0; } - - 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_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - 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; + ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + gpio_shift = 2 * gpio; - 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_ALL << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) { - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), + AR_GPIO_BIT(gpio)); } -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); + 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 -void -ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, - u32 burstDuration) +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) { - struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_channel *chan = ah->ah_curchan; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 ant_config; + u32 halNumAntConfig; - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} + halNumAntConfig = IS_CHAN_2GHZ(chan) ? + pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz; -void -ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); + 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; + } + } - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; + return -EINVAL; } -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) +u32 ath9k_hw_getdefantenna(struct ath_hal *ah) { - REG_WRITE(ah, AR_RXDP, rxdp); + return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_rxena(struct ath_hal *ah) +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) { - REG_WRITE(ah, AR_CR, AR_CR_RXE); + REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); } -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +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) { - 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; + struct ath_hal_5416 *ahp = AH5416(ah); + static u8 tx_chainmask_cfg, rx_chainmask_cfg; - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT)); + if (AR_SREV_9280(ah)) { + if (!tx_chainmask_cfg) { - 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); + tx_chainmask_cfg = *tx_chainmask; + rx_chainmask_cfg = *rx_chainmask; + } - return false; + 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 { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + ahp->ah_diversityControl = settings; } 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); -} +/*********************/ +/* General Operation */ +/*********************/ -bool -ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 size, u32 flags) +u32 ath9k_hw_getrxfilter(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u32 bits = REG_READ(ah, AR_RX_FILTER); + u32 phybits = REG_READ(ah, AR_PHY_ERR); - ads->ds_ctl1 = size & AR_BufLen; - if (flags & ATH9K_RXDESC_INTREQ) - ads->ds_ctl1 |= AR_RxIntrReq; + 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; - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); - return true; + return bits; } -int -ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) { - 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; + u32 phybits; - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + 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); - 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); + if (phybits) + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); 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_RXCFG, + REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); } -static void ath9k_hw_setup_rate_table(struct ath_hal *ah, - struct ath9k_rate_table *rt) +bool ath9k_hw_phy_disable(struct ath_hal *ah) { - 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); - } + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); } -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode) +bool ath9k_hw_disable(struct ath_hal *ah) { - 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; -} + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; -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"; - } - return NULL; + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -const char *ath9k_hw_probe(u16 vendorid, u16 devid) +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) { - return vendorid == ATHEROS_VENDOR_ID ? - ath9k_hw_devname(devid) : NULL; -} + struct ath9k_channel *chan = ah->ah_curchan; -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error) -{ - struct ath_hal *ah = NULL; + ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); - 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 (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 ah; + return true; } -u16 -ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble) +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) { - u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; - u32 kbps; - - kbps = rates->info[rateix].rateKbps; - - if (kbps == 0) - return 0; - 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; + struct ath_hal_5416 *ahp = AH5416(ah); - 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; + memcpy(mac, ahp->ah_macaddr, ETH_ALEN); } -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) { - 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 ath_hal_5416 *ahp = AH5416(ah); -/* We can tune this as we go by monitoring really low values */ -#define ATH9K_NF_TOO_LOW -60 + memcpy(ahp->ah_macaddr, mac, ETH_ALEN); -/* 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; } -s16 -ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +void ath9k_hw_setopmode(struct ath_hal *ah) { - 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; + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); } -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1) { - 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; - return true; + REG_WRITE(ah, AR_MCAST_FIL0, filter0); + REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -bool ath9k_hw_phycounters(struct ath_hal *ah) +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) { struct ath_hal_5416 *ahp = AH5416(ah); - return ahp->ah_hasHwPhyCounters ? true : false; + memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); } -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) { - return REG_READ(ah, AR_QTXDP(q)); -} + struct ath_hal_5416 *ahp = AH5416(ah); -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp) -{ - REG_WRITE(ah, AR_QTXDP(q), txdp); + memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); + + 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; } -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + struct ath_hal_5416 *ahp = AH5416(ah); - REG_WRITE(ah, AR_Q_TXE, 1 << q); + memcpy(ahp->ah_bssid, bssid, ETH_ALEN); + ahp->ah_assocId = assocId; - return true; + 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)); } -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +u64 ath9k_hw_gettsf64(struct ath_hal *ah) { - u32 npend; + u64 tsf; - npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; - if (npend == 0) { + tsf = REG_READ(ah, AR_TSF_U32); + tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - if (REG_READ(ah, AR_Q_TXE) & (1 << q)) - npend = 1; - } - return npend; + return tsf; } -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +void ath9k_hw_reset_tsf(struct ath_hal *ah) { - u32 wait; - - REG_WRITE(ah, AR_Q_TXD, 1 << q); + int count; - for (wait = 1000; wait != 0; wait--) { - if (ath9k_hw_numtxpending(ah, q) == 0) + 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, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); break; - udelay(100); + } + udelay(10); } + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); +} - if (ath9k_hw_numtxpending(ah, q)) { - u32 tsfLow, j; - - 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); +bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - 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); - } + if (setting) + ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + else + ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + return true; +} - udelay(200); - REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - wait = 1000; + if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", 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; + } +} - 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); - } +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) +{ + u32 macmode; - REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - } + 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 2113818ee934..91d8f594af81 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,27 @@ 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 + +#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, EEP_NFTHRESH_2, @@ -454,6 +478,8 @@ enum eeprom_param { EEP_MINOR_REV, EEP_TX_MASK, EEP_RX_MASK, + EEP_RXGAIN_TYPE, + EEP_TXGAIN_TYPE, }; enum ar5416_rates { @@ -469,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; @@ -485,9 +516,32 @@ 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 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; @@ -540,11 +594,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]; @@ -555,6 +656,7 @@ struct cal_target_power_ht { u8 tPow2x[8]; } __packed; + #ifdef __BIG_ENDIAN_BITFIELD struct cal_ctl_edges { u8 bChannel; @@ -569,10 +671,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 ar5416_eeprom { +struct cal_ctl_data_4k { + struct cal_ctl_edges + ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; +} __packed; + +struct ar5416_eeprom_def { struct base_eep_header baseEepHeader; u8 custData[64]; struct modal_eep_header modalHeader[2]; @@ -601,6 +708,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; @@ -668,9 +795,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; @@ -792,6 +932,10 @@ struct ath_hal_5416 { struct ar5416IniArray ah_iniAddac; struct ar5416IniArray ah_iniPcieSerdes; 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)) @@ -833,13 +977,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 @@ -923,7 +1074,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/initvals.h b/drivers/net/wireless/ath9k/initvals.h index 3dd3815940a4..f3cfa16525e4 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,6 +2581,516 @@ 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 }, + { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, + { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, +}; + +static const u32 ar9280Common_9280_2[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 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, 0x00000033 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 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, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafa68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009940, 0x14750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x190fb515 }, + { 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, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x000099fc, 0x00001042 }, + { 0x0000a208, 0x803e4788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x233f7180 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c88000 }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 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, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00040000 }, + { 0x00007804, 0xdb005012 }, + { 0x00007808, 0x04924914 }, + { 0x0000780c, 0x21084210 }, + { 0x00007810, 0x6d801300 }, + { 0x00007818, 0x07e41000 }, + { 0x0000781c, 0x00392000 }, + { 0x00007820, 0x92592480 }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb005012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x6d801300 }, + { 0x0000783c, 0x07e40000 }, + { 0x00007840, 0x00392000 }, + { 0x00007844, 0x92592480 }, + { 0x00007848, 0x00100000 }, + { 0x0000784c, 0x773f0567 }, + { 0x00007850, 0x54214514 }, + { 0x00007854, 0x12035828 }, + { 0x00007858, 0x9259269a }, + { 0x00007860, 0x52802000 }, + { 0x00007864, 0x0a8e370e }, + { 0x00007868, 0xc0102850 }, + { 0x0000786c, 0x812d4000 }, + { 0x00007870, 0x807ec400 }, + { 0x00007874, 0x001b6db0 }, + { 0x00007878, 0x00376b63 }, + { 0x0000787c, 0x06db6db6 }, + { 0x00007880, 0x006d8000 }, + { 0x00007884, 0xffeffffe }, + { 0x00007888, 0xffeffffe }, + { 0x0000788c, 0x00010000 }, + { 0x00007890, 0x02060aeb }, + { 0x00007898, 0x2a850160 }, +}; + +static const u32 ar9280Modes_fast_clock_9280_2[][3] = { + { 0x00001030, 0x00000268, 0x000004d0 }, + { 0x00001070, 0x0000018c, 0x00000318 }, + { 0x000010b0, 0x00000fd0, 0x00001fa0 }, + { 0x00008014, 0x044c044c, 0x08980898 }, + { 0x0000801c, 0x148ec02b, 0x148ec057 }, + { 0x00008318, 0x000044c0, 0x00008980 }, + { 0x00009820, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000f0f, 0x00000f0f }, + { 0x00009828, 0x0b020001, 0x0b020001 }, + { 0x00009834, 0x00000f0f, 0x00000f0f }, + { 0x00009844, 0x03721821, 0x03721821 }, + { 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 }, @@ -2715,14 +3219,172 @@ static const u32 ar9280Modes_9280_2[][6] = { { 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 }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 }, - { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 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 }, @@ -2745,14 +3407,363 @@ static const u32 ar9280Modes_9280_2[][6] = { { 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 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {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, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {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 }, - { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, }; -static const u32 ar9280Common_9280_2[][2] = { +static const u_int32_t ar9285Common_9285[][2] = { { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, + { 0x00000030, 0x00020045 }, { 0x00000034, 0x00000005 }, { 0x00000040, 0x00000000 }, { 0x00000044, 0x00000008 }, @@ -2837,7 +3848,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00004024, 0x0000001f }, { 0x00004060, 0x00000000 }, { 0x00004064, 0x00000000 }, - { 0x00007010, 0x00000033 }, + { 0x00007010, 0x00000031 }, { 0x00007034, 0x00000002 }, { 0x00007038, 0x000004c2 }, { 0x00008004, 0x00000000 }, @@ -2847,7 +3858,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008020, 0x00000000 }, { 0x00008038, 0x00000000 }, { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, + { 0x00008048, 0x00000000 }, { 0x00008054, 0x00000000 }, { 0x00008058, 0x00000000 }, { 0x0000805c, 0x000fc78f }, @@ -2923,6 +3934,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -2936,15 +3948,15 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008300, 0x00000040 }, { 0x00008314, 0x00000000 }, { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, + { 0x0000832c, 0x00000001 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, { 0x00008338, 0x00000000 }, { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, + { 0x00008340, 0x00010380 }, { 0x00008344, 0x00581043 }, { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xafa68e30 }, + { 0x0000980c, 0xafe68e30 }, { 0x00009810, 0xfd14e000 }, { 0x00009814, 0x9c0a9f6b }, { 0x0000981c, 0x00000000 }, @@ -2952,7 +3964,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009830, 0x00000000 }, { 0x0000983c, 0x00200400 }, { 0x0000984c, 0x0040233c }, - { 0x0000a84c, 0x0040233c }, { 0x00009854, 0x00000044 }, { 0x00009900, 0x00000000 }, { 0x00009904, 0x00000000 }, @@ -2961,20 +3972,18 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009910, 0x01002310 }, { 0x0000991c, 0x10000fff }, { 0x00009920, 0x04900000 }, - { 0x0000a920, 0x04900000 }, { 0x00009928, 0x00000001 }, { 0x0000992c, 0x00000004 }, { 0x00009934, 0x1e1f2022 }, { 0x00009938, 0x0a0b0c0d }, { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, { 0x00009948, 0x9280c00a }, { 0x0000994c, 0x00020028 }, { 0x00009954, 0x5f3ca3de }, { 0x00009958, 0x2108ecff }, - { 0x00009940, 0x14750604 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb515 }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x1927b515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -2989,7 +3998,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x000099a0, 0x00000000 }, { 0x000099a4, 0x00000001 }, { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f0000 }, + { 0x000099ac, 0x2def0a00 }, { 0x000099b0, 0x03051000 }, { 0x000099b4, 0x00000820 }, { 0x000099dc, 0x00000000 }, @@ -2998,31 +4007,28 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x000099e8, 0x3c466478 }, { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, - { 0x000099fc, 0x00001042 }, + { 0x0000a208, 0x803e6788 }, { 0x0000a210, 0x4080a333 }, - { 0x0000a214, 0x40206c10 }, + { 0x0000a214, 0x00206c10 }, { 0x0000a218, 0x009c4060 }, { 0x0000a220, 0x01834061 }, { 0x0000a224, 0x00000400 }, { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x233f71c0 }, + { 0x0000a22c, 0x00000000 }, { 0x0000a234, 0x20202020 }, { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c88000 }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, { 0x0000a24c, 0x00000000 }, { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cdbd380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x39ce739c }, + { 0x0000a27c, 0x050e039c }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -3037,8 +4043,8 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000a388, 0x0c000000 }, { 0x0000a38c, 0x20202020 }, { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, + { 0x0000a394, 0x39ce739c }, + { 0x0000a398, 0x0000039c }, { 0x0000a39c, 0x00000001 }, { 0x0000a3a0, 0x00000000 }, { 0x0000a3a4, 0x00000000 }, @@ -3050,96 +4056,746 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000a3bc, 0x00000000 }, { 0x0000a3c0, 0x00000000 }, { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, { 0x0000a3cc, 0x20202020 }, { 0x0000a3d0, 0x20202020 }, { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, + { 0x0000a3dc, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c }, { 0x0000a3e4, 0x00000000 }, { 0x0000a3e8, 0x18c43433 }, { 0x0000a3ec, 0x00f70081 }, - { 0x00007800, 0x00040000 }, - { 0x00007804, 0xdb005012 }, - { 0x00007808, 0x04924914 }, - { 0x0000780c, 0x21084210 }, - { 0x00007810, 0x6d801300 }, - { 0x00007814, 0x0019beff }, - { 0x00007818, 0x07e41000 }, - { 0x0000781c, 0x00392000 }, - { 0x00007820, 0x92592480 }, - { 0x00007824, 0x00040000 }, - { 0x00007828, 0xdb005012 }, - { 0x0000782c, 0x04924914 }, - { 0x00007830, 0x21084210 }, - { 0x00007834, 0x6d801300 }, - { 0x00007838, 0x0019beff }, - { 0x0000783c, 0x07e40000 }, - { 0x00007840, 0x00392000 }, - { 0x00007844, 0x92592480 }, - { 0x00007848, 0x00100000 }, - { 0x0000784c, 0x773f0567 }, - { 0x00007850, 0x54214514 }, - { 0x00007854, 0x12035828 }, - { 0x00007858, 0x9259269a }, - { 0x00007860, 0x52802000 }, - { 0x00007864, 0x0a8e370e }, - { 0x00007868, 0xc0102850 }, - { 0x0000786c, 0x812d4000 }, - { 0x00007870, 0x807ec400 }, - { 0x00007874, 0x001b6db0 }, - { 0x00007878, 0x00376b63 }, - { 0x0000787c, 0x06db6db6 }, - { 0x00007880, 0x006d8000 }, - { 0x00007884, 0xffeffffe }, - { 0x00007888, 0xffeffffe }, - { 0x0000788c, 0x00010000 }, - { 0x00007890, 0x02060aeb }, - { 0x00007898, 0x2a850160 }, + { 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 u32 ar9280Modes_fast_clock_9280_2[][3] = { - { 0x00001030, 0x00000268, 0x000004d0 }, - { 0x00001070, 0x0000018c, 0x00000318 }, - { 0x000010b0, 0x00000fd0, 0x00001fa0 }, - { 0x00008014, 0x044c044c, 0x08980898 }, - { 0x0000801c, 0x148ec02b, 0x148ec057 }, - { 0x00008318, 0x000044c0, 0x00008980 }, - { 0x00009820, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000f0f, 0x00000f0f }, - { 0x00009828, 0x0b020001, 0x0b020001 }, - { 0x00009834, 0x00000f0f, 0x00000f0f }, - { 0x00009844, 0x03721821, 0x03721821 }, - { 0x00009914, 0x00000898, 0x00000898 }, - { 0x00009918, 0x0000000b, 0x00000016 }, - { 0x00009944, 0xdfbc1210, 0xdfbc1210 }, +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 u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, {0x00004040, 0x13160820 }, {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffc }, - {0x00004040, 0x1aaabe40 }, + {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 u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { +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, 0x401dcffd }, - {0x00004040, 0x1aaabe40 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, {0x00004040, 0xbe105554 }, {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c new file mode 100644 index 000000000000..af32d091dc38 --- /dev/null +++ b/drivers/net/wireless/ath9k/mac.c @@ -0,0 +1,946 @@ +/* + * 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, + "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) + | 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); +} + +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, "queue %u\n", 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, + "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); + + 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, + "Failed to stop Tx DMA in 100 " + "msec after killing last frame\n"); + 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; + 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) + 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, "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, "inactive queue\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", 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, "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, "inactive queue\n"); + 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, + "no available tx queue\n"); + return -1; + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type); + return -1; + } + + 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, + "tx queue %u already active\n", 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, "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, "inactive queue %u\n", q); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", 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, "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, "inactive queue %u\n", q); + return true; + } + + 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)) + 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, + "rx failed to go idle in 10 ms RXSM=0x%x\n", 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) +{ + 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) +{ + 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, + "dma failed to stop in 10ms\n" + "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return false; + } else { + return true; + } +} diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f05f584ab7bc..191eec50dc75 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -14,15 +14,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* mac80211 and PCI callbacks */ - #include <linux/nl80211.h> #include "core.h" +#include "reg.h" +#include "hw.h" #define ATH_PCI_VERSION "0.1" -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); @@ -36,9 +34,581 @@ 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 } }; +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->cur_rate_table = sc->hw_rate_table[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, "Rate: %2dMbps, ratecode: %2d\n", + 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, + "Unable to collect channel list; " + "regdomain likely %u country code %u\n", + 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, "2MHz channel: %d, " + "channelFlags: 0x%x\n", + 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, "5MHz channel: %d, " + "channelFlags: 0x%x\n", + 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; + + 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); + 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 + * changing channel. */ + + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) + fastcc = false; + + DPRINTF(sc, ATH_DBG_CONFIG, + "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", + 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->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, fastcc, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "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); + 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, + "Unable to restart recv logic\n"); + 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.rxfilter & 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, "longcal @%lu\n", 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, "shortcal @%lu\n", 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, + "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, + "calibrate chan %u/%x failed\n", + 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_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); + + 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, "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) +{ + 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->rx.rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->rx.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); + + 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)); + tasklet_schedule(&sc->intr_tq); + } + + return IRQ_HANDLED; +} + static int ath_get_channel(struct ath_softc *sc, struct ieee80211_channel *chan) { @@ -53,34 +623,39 @@ 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, + enum nl80211_channel_type channel_type) { 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; switch (chan->band) { case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && - (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 == IEEE80211_HT_IE_CHA_SEC_ABOVE) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40PLUS: chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && - (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 == IEEE80211_HT_IE_CHA_SEC_NONE) && - (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 == IEEE80211_HT_IE_CHA_SEC_ABOVE) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40PLUS: chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) + break; + case NL80211_CHAN_HT40MINUS: chanmode = CHANNEL_A_HT40MINUS; + break; + } break; default: break; @@ -89,22 +664,31 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, return chanmode; } +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, +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) { /* @@ -113,34 +697,113 @@ 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, - "%s Setting TX MIC Key Failed\n", __func__); + "Setting TX MIC Key Failed\n"); return 0; } 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 + 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 + 64 + 32; + } + } 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++) { + /* 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 */ + } + + /* 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)); @@ -158,226 +821,103 @@ 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; + 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; - vif = sc->sc_vaps[0]->av_if_data; - opmode = vif->type; - - /* - * 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. - */ - 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; - freeslot = (key->keyidx >= 4) ? 1 : 0; - ath_key_reset(sc, key->keyidx, freeslot); + clear_bit(key->hw_key_idx, sc->sc_keymap); + if (key->alg != ALG_TKIP) + return; + + 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_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; -} - -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; - - /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */ - rx_status->qual = status->rssi * 100 / 64; - - 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 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) -{ -#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; - - if (!(bss_conf->ht_conf->cap & - IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_WIDTH)) - 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); - ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_conf->ampdu_density); - - } - -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT + /* 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 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; - int pos; - DECLARE_MAC_BUF(mac); + struct ath_vap *avp = (void *)vif->drv_priv; if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", - __func__, - bss_conf->aid); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } + 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 == 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); @@ -393,175 +933,16 @@ 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, bss_conf->assoc_ht); - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", - __func__, - print_mac(mac, 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__); - return; - } - - if (hw->conf.ht_conf.ht_supported) - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); - 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__); - - ath_rate_newstate(sc, avp); - /* 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)); } 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; } } -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; -} - -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - 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) { - /* 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; - } - - 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)) { - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - /* Frame was not ACKed, but an ACK was expected */ - tx_info->status.excessive_retries = 1; - } - } else { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } - - tx_info->status.retry_count = tx_status->retries; - - ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); -} - -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 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) { - 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; - } - - 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, - hw->conf.ht_conf.ht_supported, - 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; -} - /********************************/ /* LED functions */ /********************************/ @@ -677,7 +1058,8 @@ fail: ath_deinit_leds(sc); } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /*******************/ /* Rfkill */ /*******************/ @@ -689,14 +1071,14 @@ 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, 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), @@ -708,7 +1090,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; } @@ -747,14 +1129,14 @@ 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, 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), @@ -834,7 +1216,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); @@ -878,61 +1260,258 @@ 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 */ + ath_detach(sc); + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(sc->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 */ - ath_deinit_leds(sc); + DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); -#ifdef CONFIG_RFKILL - /* deinit rfkill */ +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif - - /* Unregister hw */ + ath_deinit_leds(sc); ieee80211_unregister_hw(hw); - - /* unregister Rate control */ - ath_rate_control_unregister(); - - /* tx/rx cleanup */ - 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->tx.txq[i]); + + ath9k_hw_detach(sc->sc_ah); + ath9k_exit_debug(sc); } -static int ath_attach(u16 devid, - struct ath_softc *sc) +static int ath_init(u16 devid, struct ath_softc *sc) { - struct ieee80211_hw *hw = sc->hw; - int error = 0; + struct ath_hal *ah = NULL; + int status; + int error = 0, i; + int csz = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; - error = ath_init(devid, sc); - if (error != 0) - return error; + if (ath9k_init_debug(sc) < 0) + printk(KERN_ERR "Unable to create debugfs files\n"); - /* Init nodes */ + 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); - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); + /* + * 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 */ - /* get mac address from hardware and set in mac80211 */ + ah = ath9k_hw_attach(devid, sc, sc->mem, &status); + if (ah == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to attach hardware; HAL status %u\n", status); + error = -ENXIO; + goto bad; + } + sc->sc_ah = ah; - SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + /* 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, + "Warning, using only %u entries in %u key cache\n", + 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); + + /* 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 = NL80211_IFTYPE_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->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->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; + goto bad2; + } + + sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + 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 */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + DPRINTF(sc, ATH_DBG_FATAL, + "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, + "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, + "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, + "Unable to setup xmit queue for VO traffic\n"); + 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->rx.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->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + 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; /* setup channels and rates */ @@ -942,55 +1521,81 @@ static int ath_attach(u16 devid, 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_info); - - 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; + 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_info); + 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->tx.txq[i]); +bad: + if (ah) + ath9k_hw_detach(ah); - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; - } + return error; +} + +static int ath_attach(u16 devid, struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + int error = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); + + error = ath_init(devid, sc); + if (error != 0) + return error; + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; - /* FIXME: Have to figure out proper hw init values later */ + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); hw->queues = 4; - hw->ampdu_queues = 1; + 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); - /* Register rate control */ hw->rate_control_algorithm = "ath9k_rate_control"; - error = ath_rate_control_register(); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to register rate control " - "algorithm:%d\n", __func__, error); - ath_rate_control_unregister(); - goto bad; - } - error = ieee80211_register_hw(hw); - if (error != 0) { - 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); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); } - /* Initialize LED control */ - ath_init_leds(sc); + 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]; -#ifdef CONFIG_RFKILL + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto detach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto detach; + +#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); @@ -1000,88 +1605,371 @@ static int ath_attach(u16 devid, goto detach; #endif - /* initialize tx/rx engine */ - - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto detach; + error = ieee80211_register_hw(hw); - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto detach; + /* Initialize LED control */ + ath_init_leds(sc); return 0; detach: ath_detach(sc); -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->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "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, "Unable to start recv logic\n"); + + /* + * 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->tx.txq[i].axq_lock); + ath_txq_schedule(sc, &sc->tx.txq[i]); + spin_unlock_bh(&sc->tx.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 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, "ath_desc not DWORD aligned\n"); + 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 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 */ + 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->tx.hwq_map[ATH9K_WME_AC_VO]; + break; + case 1: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; + break; + case 2: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + case 3: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; + break; + default: + qnum = sc->tx.hwq_map[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); + 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__); - return -EINVAL; + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); + error = -EINVAL; + 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]; - /* open ath_dev */ - 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->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__); - return error; + "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); + goto error; } + spin_unlock_bh(&sc->sc_resetlock); -#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); + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath_update_txpow(sc); - /* 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; - } + /* + * 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, + "Unable to start recv logic\n"); + 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 == 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 + * 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 == NL80211_IFTYPE_STATION) && + !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 - ieee80211_wake_queues(hw); - return 0; +error: + return error; } 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 @@ -1091,9 +1979,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 */ @@ -1106,45 +1994,68 @@ static int ath9k_tx(struct ieee80211_hw *hw, memmove(skb->data, skb->data + padsize, hdrlen); } - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", - __func__, - skb); + /* Check if a tx queue is available */ - if (ath_tx_start(sc, skb) != 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; + txctl.txq = ath_test_get_txq(sc, skb); + if (!txctl.txq) + goto exit; + + DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + + if (ath_tx_start(sc, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); + goto exit; } return 0; +exit: + dev_kfree_skb_any(skb); + return 0; } 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__); + if (sc->sc_flags & SC_OP_INVALID) { + DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + return; + } - error = ath_suspend(sc); - if (error) - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Device is no longer present\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); + + 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); - ieee80211_stop_queues(hw); + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_draintxq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(sc->sc_ah); + } else + sc->rx.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 + /* 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, "Driver halt\n"); } 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; + enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; /* Support only vap for now */ @@ -1153,32 +2064,34 @@ 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, - "%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); - 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 == NL80211_IFTYPE_AP) + 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; if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ @@ -1194,78 +2107,76 @@ 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; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); + struct ath_vap *avp = (void *)conf->vif->drv_priv; - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } + 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); - /* 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) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); 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, - 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; - int pos; + struct ieee80211_conf *conf = &hw->conf; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + mutex_lock(&sc->mutex); + if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_HT)) { + 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, "Set channel: %d MHz\n", + 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, "Invalid channel: %d\n", + curchan->center_freq); + mutex_unlock(&sc->mutex); + return -EINVAL; + } - if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) + 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; - sc->sc_config.txpowlimit = 2 * conf->power_level; + 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; - /* 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__); + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan, + 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"); + mutex_unlock(&sc->mutex); + return -EINVAL; + } + + ath_update_chainmask(sc, conf->ht.enabled); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) + sc->sc_config.txpowlimit = 2 * conf->power_level; + mutex_unlock(&sc->mutex); return 0; } @@ -1275,23 +2186,15 @@ 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; - DECLARE_MAC_BUF(mac); - - 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 && - 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 */ @@ -1303,9 +2206,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; @@ -1315,27 +2215,9 @@ 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 & - ~(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 %s aid 0x%x\n", - __func__, rfilt, - print_mac(mac, 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 ; @@ -1357,7 +2239,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) @@ -1403,7 +2285,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); @@ -1412,8 +2294,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.rxfilter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, @@ -1422,37 +2303,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { 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); - 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: %s\n", - __func__, print_mac(mac, sta->addr)); - } else { - ath_node_get(sc, sta->addr); - } - spin_unlock_irqrestore(&sc->node_lock, flags); + ath_node_attach(sc, sta); 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: %s\n", - __func__, - print_mac(mac, sta->addr)); - } + ath_node_detach(sc, sta); break; default: break; @@ -1477,20 +2334,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; } @@ -1504,23 +2355,22 @@ 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: 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; @@ -1537,8 +2387,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; @@ -1547,8 +2396,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) @@ -1557,18 +2405,10 @@ 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 %d\n", - __func__, - bss_conf->assoc_ht); - 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, bss_conf); + ath9k_bss_assoc_info(sc, vif, bss_conf); } } @@ -1601,50 +2441,37 @@ 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); - 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->addr, 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", - __func__); + "Unable to start TX aggregation\n"); else 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", - __func__); + "Unable to stop TX aggregation\n"); 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__); + DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); } 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, @@ -1654,42 +2481,97 @@ 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, - .set_retry_limit = 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, }; +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; i<ARRAY_SIZE(ath_mac_bb_names); i++) { + if (ath_mac_bb_names[i].version == mac_bb_version) { + return ath_mac_bb_names[i].name; + } + } + + return "????"; +} + +/* + * Return the RF name. "????" is returned if the RF is unknown. + */ +static const char * +ath_rf_name(u16 rf_version) +{ + int i; + + for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) { + if (ath_rf_names[i].version == rf_version) { + return ath_rf_names[i].name; + } + } + + return "????"; +} + static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *mem; struct ath_softc *sc; struct ieee80211_hw *hw; - const char *athname; u8 csz; u32 val; int ret = 0; + struct ath_hal *ah; 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"); - ret = -ENODEV; + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); + goto bad; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + + if (ret) { + printk(KERN_ERR "ath9k: 32-bit DMA consistent " + "DMA enable failed\n"); goto bad; } @@ -1746,16 +2628,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; - - 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); @@ -1778,11 +2650,15 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad4; } - athname = ath9k_hw_probe(id->vendor, 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; @@ -1803,17 +2679,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); @@ -1829,7 +2698,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 @@ -1866,7 +2735,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 @@ -1896,11 +2765,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; } @@ -1911,7 +2793,8 @@ 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); + 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 eb9121fdfd38..766982a8196e 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; } @@ -215,7 +214,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 +234,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, @@ -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/phy.h b/drivers/net/wireless/ath9k/phy.h index 14702344448b..3a406a5c0593 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 diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index cca2fc5b0765..04ab457a8faa 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -15,143 +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 u32 tx_triglevel_max; 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 }, }, @@ -160,153 +153,149 @@ 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 */ - /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ 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 }, }, @@ -317,29 +306,30 @@ 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 */ + { 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 }, }, @@ -348,109 +338,44 @@ 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, + {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 }, }, @@ -461,17 +386,18 @@ 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 */ + { 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 }, }, @@ -480,48 +406,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 - */ static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -541,68 +425,65 @@ 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) +static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, + struct ath_rate_priv *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; } } } } -/* 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_priv *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] = 0; } -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_priv *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 ? 1 : 0; } -static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *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, - 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; - 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]; - return TRUE; + 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 1; } } /* No more valid rates */ *next_idx = 0; - return FALSE; + + return 0; } /* Return true only for single stream */ @@ -610,83 +491,72 @@ ath_rc_get_nextvalid_txrate(const 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(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, +ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *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]; - return TRUE; + 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 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, - const 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) { - 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 : 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 = 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, 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, - const 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) { - /* 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++) { @@ -695,196 +565,89 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *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 - * (TRUE/TRUE_20/TRUE_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)) == - WLAN_RC_CAP_MODE(capflag)) && - !WLAN_RC_PHY_HT(phy)) { + * (VALID/VALID_20/VALID_40) flags */ + 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, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) 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, 1); hi = A_MAX(hi, j); } } } + return hi; } -static u8 -ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, - const 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; - 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++) { + 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; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) 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, 1); hi = A_MAX(hi, j); } } - 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 *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); - - /* Save Maximum TX Trigger Level (used for 11n) */ - tx_triglevel_max = ah->ah_caps.tx_triglevel_max; - /* return alias for ath_rate_softc * */ - 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) - 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; - int i; - - ratetable = rsc->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; -} - -/* - * 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; - - /* 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]; - /* NB: check the fixed rate exists */ - if (asc->fixedrix == 0xff) - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } else { - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } + return hi; } 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_priv *ath_rc_priv, + struct ath_rate_table *rate_table, int probe_allowed, int *is_probing, int is_retry) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; 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; + *is_probing = 0; - 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 +659,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 +678,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 +690,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 +705,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,41 +724,35 @@ 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; - *is_probing = TRUE; + ath_rc_priv->probe_rate = rate; + ath_rc_priv->probe_time = now_msec; + ath_rc_priv->hw_maxretry_pktcnt = 0; + *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 > (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 && @@ -1004,40 +761,36 @@ 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 , - struct ath_rc_series *series, - u8 tries, - u8 rix, - int rtsctsenable) +static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , + 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, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) { 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 +798,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; @@ -1055,41 +808,39 @@ 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 ath_rate_priv *ath_rc_priv, + int num_tries, int num_rates, + struct ieee80211_tx_info *tx_info, int *is_probe, 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; + struct ieee80211_tx_rate *rates = tx_info->control.rates; - rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + rate_table = sc->cur_rate_table; + 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, - &series[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, - &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, 0); } /* Fill in the other rates for multirate retry */ @@ -1099,14 +850,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, - &series[i], try_num, nrix, TRUE); + &rates[i], try_num, nrix, 1); } /* @@ -1124,115 +874,29 @@ 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)) { - u8 dot11rate = rate_table->info[rix].dot11rate; + 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 && ((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; - } - } -} - -/* - * 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 ath_rc_series series[], - 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; + rates[3].idx = rates[2].idx; + rates[3].flags = rates[2].flags; } } } -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *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) { - struct ath_tx_ratectrl *rate_ctrl; - u32 now_msec = jiffies_to_msecs(jiffies); - int state_change = FALSE, rate, count; + bool state_change = false; + int 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]; - static u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, 100 * 1 / 4, @@ -1246,56 +910,35 @@ static void ath_rc_update_ht(struct ath_softc *sc, 100 * 9 / 10 }; - if (!ath_rc_priv) - return; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - - 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)) - info_priv->tx.ts_rssi = - 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 = 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) */ - rate_ctrl->state[tx_rate].per = - (u8)(rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100) >> 3)); + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_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. */ - /* Make sure it doesn't index out of array's bounds. */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + } else { /* xretries == 0 */ + 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), @@ -1308,37 +951,35 @@ 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) - rate_ctrl->state[tx_rate].per - = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100*(retries*info_priv->n_frames + - info_priv->n_bad_frames) / - (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) */ - - rate_ctrl->state[tx_rate].per = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->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)); } - 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 = tx_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 (retries > 0 || 2 * info_priv->n_bad_frames > - info_priv->n_frames) { + 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) { /* * Since we probed with just a single attempt, * any retries means the probe failed. Also, @@ -1346,17 +987,18 @@ 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 @@ -1364,8 +1006,8 @@ 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 - - rate_table->probe_interval / 2; + ath_rc_priv->probe_time = + now_msec - rate_table->probe_interval / 2; } } @@ -1375,74 +1017,114 @@ 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 { + 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. */ - 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_info_priv->tx.ts_rssi < + rate_table->info[tx_rate].rssi_ack_validmin) + goto exit; - rate_ctrl->rssi_sum += info_priv->tx.ts_rssi; - rate_ctrl->rssi_sum_cnt++; - - if (rate_ctrl->rssi_sum_cnt > 4) { - int32_t rssi_ackAvg = - (rate_ctrl->rssi_sum + 2) / 4; - int8_t rssi_thres = - rate_ctrl->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; - - /* Now reduce the current - * rssi threshold. */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - rate_ctrl->state[tx_rate]. - rssi_thres--; - } - - state_change = TRUE; - } + /* 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. */ + +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) - /* For all cases */ + u32 now_msec = jiffies_to_msecs(jiffies); + int rate; + u8 last_per; + bool state_change = false; + 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)) + 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 * 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) { @@ -1453,20 +1135,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 < - rate_ctrl->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 (rate_ctrl->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]. - rssi_thres + - rate_table->info[rate]. - rssi_ack_deltamin; + 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; } } @@ -1476,27 +1153,20 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { - if (rate_ctrl->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) - rate_ctrl->state[rate].rssi_thres = 0; + if (CHK_RSSI(rate)) { + if (ath_rc_priv->state[rate+1].rssi_thres < + rate_table->info[rate].rssi_ack_deltamin) + ath_rc_priv->state[rate].rssi_thres = 0; else { - rate_ctrl->state[rate].rssi_thres = - rate_ctrl->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + 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 < - rate_table->info[rate]. - rssi_ack_validmin) { - rate_ctrl->state[rate].rssi_thres = - rate_table->info[rate]. - rssi_ack_validmin; + if (ath_rc_priv->state[rate].rssi_thres < + rate_table->info[rate].rssi_ack_validmin) { + ath_rc_priv->state[rate].rssi_thres = + rate_table->info[rate].rssi_ack_validmin; } } } @@ -1504,74 +1174,86 @@ 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 < 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 < 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 < 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; } + +#undef CHK_RSSI } -/* - * 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 ath_tx_info_priv *info_priv, int final_ts_idx, - int xretries, int long_retry) +static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate) { - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + 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, + 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 *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); struct ath_rate_table *rate_table; - struct ath_tx_ratectrl *rate_ctrl; - struct ath_rc_series rcs[4]; + struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; - u32 series = 0, rix; + u32 i = 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_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - ASSERT(rcs[0].tries != 0); + rate_table = sc->cur_rate_table; /* * If the first rate is not the final index, there @@ -1579,32 +1261,22 @@ 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; + 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 & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != - (flags & ATH_RC_CW40_FLAG))) + + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) 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; - else - rix = rate_table->info[ - rcs[series].rix].base_index; + + rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, - info_priv, rix, + tx_info_priv, rix, xretries ? 1 : 2, - rcs[series].tries); + rates[i].count); } } } else { @@ -1614,240 +1286,152 @@ 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[i].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))) + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { 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; - else - rix = rate_table->info[rcs[series].rix].base_index; - - ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix, - xretries, long_retry); + rix = ath_rc_get_rateindex(rate_table, &rates[i]); + 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 ath_tx_info_priv *info_priv) +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 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)) - 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) >= tx_triglevel_max)) { - tx_status = 1; - is_underrun = 1; + 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_CONFIG, "Invalid band\n"); + return NULL; } - if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || - (info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) - tx_status = 1; + BUG_ON(mode >= ATH9K_MODE_MAX); - ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : - info_priv->tx.ts_longretry); + DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); + return sc->hw_rate_table[mode]; } -/* - * 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_priv *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_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)ath_rc_priv; + 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]; + /* FIXME: Adhoc */ + 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 == NL80211_IFTYPE_AP) { + /* cur_rate_table would be set on init through config() */ + rate_table = sc->cur_rate_table; + } + + 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; + } /* 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 = RATE_TABLE_SIZE; /* 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; 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 = (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); + 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, - rateset, capflag); - if (capflag & WLAN_RC_HT_FLAG) { - hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv, + 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_setvalid_htrates(ath_rc_priv, rate_table, ht_mcs, - capflag); + ath_rc_priv->ht_cap); } 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 <= RATE_TABLE_SIZE); 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]) + if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) + || !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(k <= MAX_TX_RATE_TBL); - - rate_ctrl->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]; -} - -/* - * 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; -} - -/* - * 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) -{ - struct ath_tx_ratectrl *rate_ctrl; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - rate_ctrl->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, - 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; - u32 capflag = 0; - - if (hw->conf.ht_conf.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; - } - - ath_rate_newassoc(sc, rc_priv, capflag, - &rc_priv->neg_rates, - &rc_priv->neg_ht_rates); + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + ASSERT(k <= RATE_TABLE_SIZE); + 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 */ @@ -1856,163 +1440,88 @@ 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_node *an; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_tx_info_priv *tx_info_priv = NULL; 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->driver_data[0]; + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); + if (!priv_sta || !ieee80211_is_data(fc) || + !tx_info_priv->update_rc) + goto exit; - 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; - } - return; - } - if (tx_info->driver_data[0] != NULL) { - ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = 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; + if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) + goto exit; /* - * 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. + * 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. */ - si = container_of(sta, struct sta_info, sta); - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ - state = si->ampdu_mlme.tid_state_tx[tidno]; - - if (state & HT_ADDBA_RECEIVED_MSK) { - txtid->addba_exchangecomplete = 1; - txtid->addba_exchangeinprogress = 0; - txtid->baw_size = buffersize; - - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Resuming tid, buffersize: %d\n", - __func__, - buffersize); - - ath_tx_resume_tid(sc, txtid); + 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); } -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; - struct ath_tx_info_priv *tx_info_priv; - 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, chk, ret; - s8 lowest_idx; + int is_probe = 0; __le16 fc = hdr->frame_control; - u8 *qc, tid; - DECLARE_MAC_BUF(mac); - - 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]; - 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; + 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; return; } /* Find tx rate for unicast frames */ - ath_rate_findrate(sc, ath_rc_priv, - ATH_11N_TXMAXTRY, 4, - ATH_RC_PROBE_ALLOWED, - tx_info_priv->rcs, - &is_probe, - false); - if (is_probe) - sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; - - /* 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; - - sel->rate_idx = tx_info_priv->rcs[0].rix; + 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_conf.ht_supported) { + 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; - 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; - } - - 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: %s\n", - __func__, - print_mac(mac, hdr->addr1)); - else - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Started tx aggr for: %s\n", - __func__, - print_mac(mac, 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); } } } @@ -2021,34 +1530,33 @@ 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; - 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 (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))) + if (sta->ht_cap.ht_supported) { + 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) break; } ath_rc_priv->neg_ht_rates.rs_nrates = j; } - ath_rc_node_update(sc->hw, priv_sta); -} -static void ath_rate_clear(void *priv) -{ - return; + ath_rc_init(sc, priv_sta, sband, 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; } @@ -2060,19 +1568,17 @@ 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_vap *avp = sc->sc_vaps[0]; - struct ath_rate_node *rate_priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + struct ath_rate_priv *rate_priv; - rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, 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; } - ath_rc_sib_init(rate_priv); + + 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; } @@ -2080,11 +1586,8 @@ 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_softc *sc = priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); - ath_rate_node_free(rate_priv); + struct ath_rate_priv *rate_priv = priv_sta; + kfree(rate_priv); } static struct rate_control_ops ath_rate_ops = { @@ -2093,13 +1596,69 @@ 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, .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] = + &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; + + 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) { return ieee80211_rate_control_register(&ath_rate_ops); @@ -2109,4 +1668,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 b95b41508b98..97c60d12e8aa 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -20,84 +20,24 @@ #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 RATE_TABLE_SIZE 64 +#define MAX_TX_RATE_PHY 48 -#define ATH_RATE_MAX 30 -#define MCS_SET_SIZE 128 +/* VALID_ALL - valid for 20/40/Legacy, + * VALID - Legacy only, + * VALID_20 - HT 20 only, + * VALID_40 - HT 40 only */ -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 -#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 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) \ @@ -114,26 +54,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 @@ -150,10 +86,11 @@ 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; + u8 rateCodeToIndex[256]; struct { int valid; int valid_single_stream; @@ -171,42 +108,26 @@ 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; u8 initial_ratemax; }; -#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 - */ -#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 (%) */ }; +struct ath_rateset { + u8 rs_nrates; + u8 rs_rates[ATH_RATE_MAX]; +}; + /** - * struct ath_tx_ratectrl - TX Rate control Information + * 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 @@ -225,9 +146,13 @@ 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]; +struct ath_rate_priv { int8_t rssi_last; int8_t rssi_last_lookup; int8_t rssi_last_prev; @@ -237,89 +162,40 @@ 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 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; + 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 */ + u32 tx_triglevel_max; + struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; struct ath_rateset neg_rates; - - /* Negotiated HT rates */ struct ath_rateset neg_ht_rates; - struct ath_rate_softc *asc; - struct ath_vap *avp; }; -/* Driver data of ieee80211_tx_info */ 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; + bool update_rc; }; -/* - * Attach/detach a rate control module. - */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah); -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); +#define ATH_TX_INFO_PRIV(tx_info) \ + ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) -/* Routines to register/unregister rate control algorithm */ +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); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 504a0444d89f..462e08c3d09d 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,356 +33,53 @@ 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. 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); } -/* 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) +static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { - 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); + /* XXX block beacon interrupts */ + ath9k_hw_setantenna(sc->sc_ah, antenna); + sc->rx.defant = antenna; + sc->rx.rxotherant = 0; } -/* 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) +/* + * 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) { - 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; + u64 tsf; - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - spin_unlock_irqrestore(&rxtid->tidlock, flag); + 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) +static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { struct sk_buff *skb; u32 off; @@ -414,67 +104,131 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, 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; } return skb; } -static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb) +/* + * 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_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 ieee80211_hdr *hdr; + u8 ratecode; + __le16 fc; - ASSERT(bf != NULL); + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - spin_lock_bh(&sc->sc_rxbuflock); - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (ds->ds_rxstat.rs_more) { /* - * This buffer is still held for hw acess. - * Mark it as free to be re-queued it later. + * 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. */ - 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 (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) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) + goto rx_next; + + 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 == NL80211_IFTYPE_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; + } + } } - spin_unlock_bh(&sc->sc_rxbuflock); -} -/* - * 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. - */ -static int ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) -{ - 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, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); - bf->bf_dmacontext = bf->bf_buf_addr; - ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; + ratecode = ds->ds_rxstat.rs_rate; + + if (ratecode & 0x80) { + /* HT rate */ + rx_status->flag |= RX_FLAG_HT; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) + rx_status->flag |= RX_FLAG_40MHZ; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) + 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; - /* queue the new wbuf to H/W */ - ath_rx_requeue(sc, nskb); + 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; + } + } } - return type; + 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->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) @@ -498,11 +252,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) @@ -512,38 +262,29 @@ 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); - /* - * 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, + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, 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->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, - "%s: failed to allocate rx descriptors: %d\n", - __func__, error); + "failed to allocate rx descriptors: %d\n", error); 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); + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); if (skb == NULL) { error = -ENOMEM; break; @@ -551,12 +292,20 @@ 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); + 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; - ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf; } - sc->sc_rxlink = NULL; + sc->rx.rxlink = NULL; } while (0); @@ -566,23 +315,19 @@ 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; 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); } - /* cleanup rx descriptors */ - - 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); } /* @@ -615,201 +360,115 @@ 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) && - (sc->rx_filter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { + if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) && + (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 */ 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 == 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; #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; 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) { - 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 */ + 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); /* 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 */ + spin_unlock_bh(&sc->rx.rxbuflock); + 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->rx.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); + 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); } -/* Process an individual frame */ - -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)) { - *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) { #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, *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 sk_buff *skb = NULL, *requeue_skb; + 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->rx.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); + if (list_empty(&sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; 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); - } - + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ds = bf->bf_desc; - ++rx_processed; /* * Must provide the virtual address of the current @@ -822,8 +481,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); @@ -831,8 +489,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)) { - spin_unlock_bh(&sc->sc_rxbuflock); + if (list_is_last(&bf->list, &sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } @@ -850,451 +508,127 @@ 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. + * Synchronize the DMA transfer with CPU before + * 1. accessing the frame + * 2. requeueing the same buffer to h/w */ - 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); - } - } + pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); - 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) + goto requeue; - if (flush) { - /* - * If we're asked to flush receive queue, directly - * chain it back at the queue without processing it. - */ - goto rx_next; - } + if (!ds->ds_rxstat.rs_datalen) + goto requeue; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - memset(&rx_status, 0, sizeof(struct ath_recv_status)); + /* The status portion of the descriptor could get corrupted. */ + if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) + goto requeue; - 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 (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) + 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->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->rx.rxbuf list for + * processing. */ + if (!requeue_skb) + goto requeue; + + /* Unmap the frame */ + pci_unmap_single(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); - 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. - */ - 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; + /* 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); + + /* 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); } - /* 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; - - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); + keyix = ds->ds_rxstat.rs_keyix; - /* 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; + 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; } - /* Pass frames up to the stack. */ + /* Send the frame to mac80211 */ + __ieee80211_rx(sc->hw, skb, &rx_status); - type = ath_rx_indicate(sc, skb, - &rx_status, ds->ds_rxstat.rs_keyix); + /* 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->rx.bufsize, + 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; /* * 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) - ath_setdefantenna(sc, - ds->ds_rxstat.rs_antenna); + 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->rx.rxbuf); + ath_rx_buf_link(sc, bf); + } while (1); -#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); - } + spin_unlock_bh(&sc->rx.rxbuflock); return 0; #undef PA2DESC } - -/* Process ADDBA request in per-TID data structure */ - -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - 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; - - 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; - } - - sband = hw->wiphy->bands[hw->conf.channel->band]; - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.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, - const u8 *addr, - 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; - } - - 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) -{ - 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; - - /* - * 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) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - 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; - } - } - -} - -/* 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/reg.h b/drivers/net/wireless/ath9k/reg.h index 60617ae66209..9fedb4911bc3 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 diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 62e28887ccd3..64043e99facf 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); } } @@ -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; } @@ -463,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; @@ -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/regd.h b/drivers/net/wireless/ath9k/regd.h index 0ecd344fbd98..512d990aa7ea 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 { \ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3a4757942b3f..3bfc3b90f256 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 @@ -65,11 +61,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. @@ -86,18 +83,16 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, 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); } @@ -105,46 +100,94 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, 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) +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + struct ath_xmit_status *tx_status) { - int i; - int ndx = 0; + 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; - for (i = 0; i < rt->rateCount; i++) { - if (rt->info[i].rateKbps == rate) { - ndx = i; - break; - } + 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) { + 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; + 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; + } + + 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); } - return ndx; + 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) +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; } -static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) +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) { + 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,232 +202,123 @@ 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 is_pae(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; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; - } 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(0x888E))) { - 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))) { + return true; } - if (is_multicast_ether_addr(hdr->addr1)) - txctl->mcast_rate = tx_info_priv->min_rate; } + return false; } -/* 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); - - /* 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; - } - - txctl->if_id = 0; - txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); - txctl->txpower = MAX_RATE_POWER; /* FIXME */ - - /* 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; - } - - /* Fill packet type */ - - txctl->atype = get_hal_packet_type(hdr); - - /* Fill qnum */ - - if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) { - txctl->qnum = 0; - txq = sc->sc_cabq; - } else { - txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[txctl->qnum]; - } - spin_lock_bh(&txq->axq_lock); - - /* Try to avoid running out of descriptors */ - if (txq->axq_depth >= (ATH_TXBUF - 20) && - !(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; + return ATH9K_KEY_TYPE_AES; } - spin_unlock_bh(&txq->axq_lock); - - /* Fill rate */ - - fill_min_rates(skb, txctl); + return ATH9K_KEY_TYPE_CLEAR; +} - /* Fill flags */ +/* Called only when tx aggregation is enabled and HT is supported */ - txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ +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; - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - txctl->flags |= ATH9K_TXDESC_NOACK; - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - txctl->flags |= ATH9K_TXDESC_RTSENA; + if (!tx_info->control.sta) + return; - /* - * Setup for rate calculations. - */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - 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 */ - txctl->ht = (hw->conf.ht_conf.ht_supported && - (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) && !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. * - * 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; - /* - * 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); + return flags; +} + +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) +{ + struct ath_buf *bf = NULL; - if (is_multicast_ether_addr(hdr->addr1)) { - antenna = sc->sc_mcastantenna + 1; - sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; + spin_lock_bh(&sc->tx.txbuflock); + + if (unlikely(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; } - return 0; + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&bf->list); + + spin_unlock_bh(&sc->tx.txbuflock); + + return bf; } /* To complete a chain of buffers associated a frame */ @@ -396,6 +330,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. @@ -414,20 +349,21 @@ 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, 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 */ - spin_lock_bh(&sc->sc_txbuflock); - list_splice_tail_init(bf_q, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_irqsave(&sc->tx.txbuflock, flags); + list_splice_tail_init(bf_q, &sc->tx.txbuf); + spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } /* @@ -468,7 +404,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); @@ -481,7 +417,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); @@ -505,11 +441,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; @@ -518,7 +452,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); @@ -553,8 +487,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; @@ -577,34 +511,23 @@ static void ath_tx_update_baw(struct ath_softc *sc, * 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) +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->cur_rate_table; 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; @@ -614,11 +537,10 @@ static u32 ath_pkt_duration(struct ath_softc *sc, 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); + return duration; } @@ -627,207 +549,127 @@ static u32 ath_pkt_duration(struct ath_softc *sc, 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, dynamic_mimops = 0; + 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; - u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; - struct ath_node *an = (struct ath_node *) bf->bf_node; + __le16 fc; - /* - * 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; + 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->control.rates; + + 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->cur_rate_table; + for (i = 3; i >= 0; i--) { + 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_RC_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)) { - BUG_ON(!an); - /* - * 802.11g protection not needed, use our default behavior - */ + /* 802.11g protection not needed, use our default behavior */ 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_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf_isaggrburst(bf)) { - flags = ATH9K_TXDESC_RTSENA; - dynamic_mimops = 1; - } else { - flags = 0; - } - } } - /* - * 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 > aggr_limit_with_rts)) { - /* - * 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. + * 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); - - /* - * Setup HAL rate series - */ - 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 (!bf->bf_rcs[i].tries) + if (!rates[i].count || (rates[i].idx < 0)) 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].Rate = rt->info[rix].ratecode | + (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 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), - bf_isshpreamble(bf)); + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, + (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), + bf_isshpreamble(bf)); - if ((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. - */ - 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; - } + 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; - } - - /* - * 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, - !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) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -836,27 +678,18 @@ 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, 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); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - 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); @@ -873,7 +706,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); @@ -906,8 +739,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; @@ -915,7 +750,14 @@ 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); + + 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) { @@ -939,7 +781,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 { @@ -961,7 +804,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, /* transmit completion */ } else { - if (!tid->cleanup_inprogress && !isnodegone && + 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); @@ -1038,18 +881,17 @@ 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); /* 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); @@ -1090,25 +932,16 @@ 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) { + 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); @@ -1136,29 +969,45 @@ 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); + + tx_info_priv->update_rc = false; + 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; + tx_info_priv->update_rc = true; + } + } +} + /* 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, - "%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); - 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; @@ -1229,9 +1078,9 @@ static int 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)) { @@ -1246,29 +1095,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->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 @@ -1299,7 +1127,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) @@ -1307,9 +1134,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 */ @@ -1317,40 +1144,33 @@ 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]); - + 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); } } } if (npend) { - int status; - /* 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, 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)) { 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); @@ -1358,7 +1178,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); } } @@ -1390,24 +1210,17 @@ 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_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head, 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)); 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: @@ -1418,21 +1231,16 @@ 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; } - 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]; - 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); @@ -1440,7 +1248,8 @@ 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; } @@ -1448,25 +1257,24 @@ 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_buf *bf, + struct ath_atx_tid *tid) { - const struct ath9k_rate_table *rt = sc->sc_currates; + 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; struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frame_length; 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 *) - tx_info->driver_data[0]; - 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 @@ -1476,14 +1284,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 (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { legacy = 1; break; } + frame_length = + rate_table->info[rates[i].idx].max_4ms_framelen; max_4ms_framelen = min(max_4ms_framelen, frame_length); } } @@ -1504,7 +1312,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); @@ -1516,12 +1324,14 @@ 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, u16 frmlen) { - const struct ath9k_rate_table *rt = sc->sc_currates; + 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; u16 minlen; u8 rc, flags, rix; @@ -1545,7 +1355,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 @@ -1554,11 +1364,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; - rc = rt->info[rix].rateCode; - width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0; - half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0; + rix = tx_info->control.rates[0].idx; + flags = tx_info->control.rates[0].flags; + 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; if (half_gi) nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); @@ -1585,7 +1395,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, @@ -1600,7 +1409,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)); @@ -1619,13 +1428,8 @@ 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 - */ - is_ds_rate = - (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0; } /* @@ -1657,7 +1461,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); @@ -1713,7 +1517,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) { @@ -1799,8 +1602,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; @@ -1821,18 +1624,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); } /* @@ -1849,10 +1646,8 @@ 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, - bool bh_flag) + struct ath_txq *txq) { struct ath_atx_ac *ac, *ac_tmp; struct ath_atx_tid *tid, *tid_tmp; @@ -1863,51 +1658,33 @@ 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); } } } -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 int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, + struct sk_buff *skb, + 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 ath_tx_info_priv *tx_info_priv; - struct ath_rc_series *rcs; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 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]; + struct ath_tx_info_priv *tx_info_priv; + 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); + 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; - 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) : @@ -1921,120 +1698,158 @@ 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 && !is_pae(skb) && + (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; + } + + /* Assign seqno, tidno */ + + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb, bf); + + /* DMA setup */ - bf->bf_flags = txctl->flags; - bf->bf_keytype = txctl->keytype; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - 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; 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); + 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 */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + 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; + + 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, + skb->len, /* segment length */ + true, /* first segment */ + true, /* 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) && + 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 * 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) +/* 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_xmit_status tx_status; - struct ath_atx_tid *tid; - struct scatterlist sg; + struct ath_buf *bf; + int r; - txctl->dmacontext = pci_map_single(sc->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); + /* Check if a tx buffer is available */ - /* setup S/G list */ - memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = txctl->dmacontext; - sg_dma_len(&sg) = skb->len; + bf = ath_tx_get_buffer(sc); + if (!bf) { + DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); + return -1; + } - 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); + r = ath_tx_setup_buffer(sc, bf, skb, txctl); + if (unlikely(r)) { + struct ath_txq *txq = txctl->txq; - tx_status.retries = 0; - tx_status.flags = ATH_TX_ERROR; + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); - 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); + /* 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; } - ath_tx_complete(sc, skb, &tx_status, txctl->an); + spin_unlock_bh(&txq->axq_lock); + + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + return r; } + + ath_tx_start_dma(sc, bf, txctl); + + return 0; } /* Initialize TX queue and h/w */ @@ -2044,26 +1859,25 @@ 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, - "%s: failed to allocate tx descriptors: %d\n", - __func__, error); + "Failed to allocate tx descriptors: %d\n", + error); break; } /* 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, - "%s: failed to allocate " - "beacon descripotrs: %d\n", - __func__, error); + "Failed to allocate beacon descriptors: %d\n", + error); break; } @@ -2080,12 +1894,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; } @@ -2133,15 +1947,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, - "%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->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; @@ -2151,11 +1965,10 @@ 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<<qnum; + sc->tx.txqsetup |= 1<<qnum; } - return &sc->sc_txq[qnum]; + return &sc->tx.txq[qnum]; } /* Reclaim resources for a setup queue */ @@ -2163,7 +1976,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<<txq->axq_qnum); + sc->tx.txqsetup &= ~(1<<txq->axq_qnum); } /* @@ -2180,15 +1993,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, - "%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->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; @@ -2200,20 +2013,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, - "%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->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; @@ -2221,6 +2033,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->tx.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, + "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); + 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, @@ -2230,17 +2070,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; @@ -2251,8 +2091,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 */ @@ -2264,7 +2103,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); @@ -2284,27 +2123,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); - else - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); - - /* failed packets will be dropped by the caller */ - return error; -} - /* Deferred processing of transmit interrupt */ void ath_tx_tasklet(struct ath_softc *sc) @@ -2319,7 +2137,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]); } } @@ -2351,9 +2169,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; } @@ -2378,8 +2196,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); } } @@ -2392,9 +2209,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); - DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__, - ath9k_hw_gettxbuf(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->beacon.beaconq)); } ath_drain_txdataq(sc, retry_tx); @@ -2402,72 +2219,47 @@ 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; } -/* 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; - DECLARE_MAC_BUF(mac); 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->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; + return true; } } - return AGGR_NOT_REQUIRED; + return false; } /* 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); - txtid->addba_exchangeinprogress = 1; + txtid->state |= AGGR_ADDBA_PROGRESS; ath_tx_pause_tid(sc, txtid); } @@ -2476,24 +2268,31 @@ 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 = (struct ath_node *)sta->drv_priv; + + ath_tx_aggr_teardown(sc, an, 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; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); + an = (struct ath_node *)sta->drv_priv; - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: TX aggr stop for non-existent node\n", __func__); - return -1; + 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); } - - ath_tx_aggr_teardown(sc, an, tid); - return 0; } /* @@ -2503,21 +2302,18 @@ 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]; + struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - 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; } @@ -2547,9 +2343,9 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, 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); @@ -2591,10 +2387,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 @@ -2625,72 +2419,67 @@ 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; - - sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT; + 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]; - - /* ADDBA state */ - tid->addba_exchangecomplete = 0; - tid->addba_exchangeinprogress = 0; - tid->addba_exchangeattempts = 0; - } + /* + * Init per tid tx state + */ + for (tidno = 0, tid = &an->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->state &= ~AGGR_CLEANUP; + INIT_LIST_HEAD(&tid->buf_q); + + acno = TID_TO_WME_AC(tidno); + tid->ac = &an->ac[acno]; + + /* ADDBA state */ + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_ADDBA_PROGRESS; + 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->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; } } } /* 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; @@ -2698,12 +2487,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, 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]; - 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) { @@ -2718,36 +2504,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); - tid->addba_exchangecomplete = 0; + ath_tid_drain(sc, txq, tid); + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; } } - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); - } - } -} - -/* 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); + spin_unlock(&txq->axq_lock); } } } @@ -2758,6 +2522,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 @@ -2766,9 +2532,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 */ @@ -2776,8 +2542,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; } @@ -2785,23 +2550,16 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, hdrlen); } - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", - __func__, - skb); + txctl.txq = sc->beacon.cabq; - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.flags = ATH9K_TXDESC_CAB; - if (ath_tx_prepare(sc, skb, &txctl) == 0) { - /* - * Start DMA mapping. - * ath_tx_start_dma() will be called either synchronously - * or asynchrounsly once DMA is complete. - */ - xmit_map_sg(sc, skb, &txctl); - } else { - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); - dev_kfree_skb_any(skb); + 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, "CABQ TX failed\n"); + goto exit; } -} + return; +exit: + dev_kfree_skb_any(skb); +} diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index ecb02bdaab5b..350157fcd080 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -67,7 +67,7 @@ #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/jiffies.h> -#include <net/ieee80211.h> +#include <linux/ieee80211.h> #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,12 +914,11 @@ 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 */ - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -950,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) { @@ -958,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); @@ -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); @@ -1041,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 && @@ -1068,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 @@ -1479,7 +1477,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 +1588,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; @@ -1822,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 @@ -1885,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 @@ -2800,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) { @@ -2829,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); @@ -2864,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; @@ -2877,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); @@ -2890,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); @@ -2904,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); @@ -2915,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; @@ -2965,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) { @@ -3004,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; } @@ -3040,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) { @@ -3183,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]; @@ -3291,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/b43/b43.h b/drivers/net/wireless/b43/b43.h index 427b8203e3f9..a53c378e7484 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/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 06a01da80160..e04fc91f569e 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 22ffd02ba554..7886cbe2d1d1 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/dma.c b/drivers/net/wireless/b43/dma.c index 098f886976f6..6d65a02b7052 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 14c44df584d0..7b31a327b24a 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. @@ -994,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; @@ -1339,25 +1383,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 +1424,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. */ @@ -1693,25 +1718,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); @@ -3339,15 +3345,31 @@ init_failure: return err; } -static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +/* 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); struct b43_wldev *dev; struct b43_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int antenna; int err = 0; - u32 savedirqs; mutex_lock(&wl->mutex); @@ -3358,33 +3380,20 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) 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 & 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_mac_enable; /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ 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. */ @@ -3399,9 +3408,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); @@ -3425,16 +3434,91 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } } - 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; } +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; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_STARTED) + goto out_unlock_mutex; + 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); +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) @@ -3445,7 +3529,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 */ @@ -3528,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: %s\n", + "mac: %pM\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - print_mac(mac, addr)); + addr); + b43_dump_keymemory(dev); } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + return err; } @@ -3598,8 +3684,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)) { @@ -3878,22 +3962,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; @@ -4214,26 +4282,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) { @@ -4263,6 +4311,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, @@ -4270,7 +4319,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, }; @@ -4588,7 +4636,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/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 0f1a84c9de61..7fe9d1701624 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_common.c b/drivers/net/wireless/b43/phy_common.c index af37abccccb3..026b61c03fb9 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); } @@ -280,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); } /** diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 232181f6333c..caac4a45f0bf 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; @@ -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) diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 401591267592..1036bef8c4cc 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 2fabcf8f0474..eae9b8052658 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; } @@ -185,7 +183,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 +200,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 +290,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 +313,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 +324,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 +354,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)) { @@ -596,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); /* @@ -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 0215faf47541..4fb2a190f7a7 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/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index c40078e1fff9..97b0e06dfe21 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/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 03ce0821a60e..1f85ac569fec 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/dma.c b/drivers/net/wireless/b43legacy/dma.c index fb6819e40f38..3649fc367098 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); @@ -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 c66d57560e7c..c1324e31d2f6 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. @@ -1160,29 +1158,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) { @@ -2556,26 +2531,27 @@ init_failure: return err; } -static int b43legacy_antenna_from_ieee80211(u8 antenna) +/* 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) { - 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; - } + /* 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, - 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; @@ -2583,13 +2559,21 @@ 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; 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: @@ -2622,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. */ @@ -2676,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, @@ -2735,7 +2807,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)) { @@ -3002,20 +3073,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; @@ -3380,28 +3437,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) { @@ -3421,13 +3456,13 @@ 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, .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, }; @@ -3710,7 +3745,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/phy.c b/drivers/net/wireless/b43legacy/phy.c index 4c9442b16f3f..11319ec2d64a 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 diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index a86c7647fa2d..746d5361bba0 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 65e833781608..12fca99f7578 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 e56777e0feab..62e09d02788f 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/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 1fef33169fdd..932d207bce23 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,8 +2,17 @@ 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 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--- 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 3a386a636cca..2453deaa3e00 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 3694b1eba521..3a9474d9a907 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 <linux/types.h> -#include <net/ieee80211_crypt.h> +#include <net/ieee80211.h> 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 f106bc1585a4..19b1bf0478bd 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,5 +1,5 @@ #include <linux/etherdevice.h> -#include <net/ieee80211_crypt.h> +#include <net/lib80211.h> #include "hostap_80211.h" #include "hostap.h" @@ -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"); } @@ -68,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) { @@ -557,7 +555,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 +570,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 +586,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; @@ -652,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; @@ -667,10 +664,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 +674,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; } @@ -696,11 +687,10 @@ 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; - DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -713,8 +703,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; } @@ -743,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; @@ -795,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 @@ -822,10 +812,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 +827,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; @@ -896,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) { @@ -1009,10 +993,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 +1003,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 921c984416f8..078a010f39a0 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"); } @@ -307,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; @@ -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; @@ -408,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; @@ -490,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 af3d4ef2a80b..0903db786d5f 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); @@ -1221,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) { @@ -1239,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"); } } @@ -1308,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; @@ -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; } @@ -1336,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); @@ -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; @@ -3142,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; @@ -3290,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 2fa2452b6b07..d36e4b175336 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_common.h b/drivers/net/wireless/hostap/hostap_common.h index b470c743c2d1..90b64b092007 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/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 3153fe9d7ce0..0f27059bbe85 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -47,7 +47,7 @@ #include <linux/wireless.h> #include <net/iw_handler.h> #include <net/ieee80211.h> -#include <net/ieee80211_crypt.h> +#include <net/lib80211.h> #include <asm/irq.h> #include "hostap_80211.h" @@ -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); } @@ -2792,45 +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 ieee80211_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); - - 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_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); - } - spin_unlock_irqrestore(&local->lock, flags); - -} - - static void hostap_passive_scan(unsigned long data) { local_info_t *local = (local_info_t *) data; @@ -3254,10 +3211,8 @@ 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; + + 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_deinit_timer)) - del_timer(&local->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 ieee80211_crypt_data *crypt = local->crypt[i]; - if (crypt) { - if (crypt->ops) - crypt->ops->deinit(crypt->priv); - kfree(crypt); - local->crypt[i] = NULL; - } - } - if (local->ap != NULL) hostap_free_data(local->ap); diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 7cd3fb79230e..99b4cf41edf2 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 3f8b1d7036e5..c40fdf4c79de 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -2,7 +2,7 @@ #include <linux/types.h> #include <linux/ethtool.h> -#include <net/ieee80211_crypt.h> +#include <net/lib80211.h> #include "hostap_wlan.h" #include "hostap.h" @@ -116,32 +116,6 @@ 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 ieee80211_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_deinit_list); - if (!timer_pending(&local->crypt_deinit_timer)) { - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->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) @@ -149,47 +123,47 @@ 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) - 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) { - 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) + 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); @@ -210,16 +184,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 +226,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) { @@ -664,7 +638,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 +659,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; } @@ -3229,8 +3201,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; @@ -3239,7 +3211,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) @@ -3249,7 +3221,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; @@ -3262,7 +3234,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; } @@ -3271,22 +3243,22 @@ 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; } 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", @@ -3295,10 +3267,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", @@ -3317,18 +3289,19 @@ 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); + lib80211_crypt_delayed_deinit(&local->crypt_info, 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; 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; @@ -3356,20 +3329,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: @@ -3401,7 +3374,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; @@ -3413,7 +3386,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--; @@ -3421,7 +3394,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); @@ -3470,8 +3443,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; @@ -3488,7 +3461,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; @@ -3505,20 +3478,20 @@ 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; } - 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", @@ -3533,11 +3506,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); + lib80211_crypt_delayed_deinit(&local->crypt_info, 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; @@ -3570,7 +3543,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); @@ -3606,7 +3579,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; @@ -3622,8 +3595,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, @@ -3701,10 +3674,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 756ab56c1f40..02a312ca8607 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -27,7 +27,7 @@ #include <net/net_namespace.h> #include <net/iw_handler.h> #include <net/ieee80211.h> -#include <net/ieee80211_crypt.h> +#include <net/lib80211.h> #include <asm/uaccess.h> #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, @@ -530,10 +531,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 +549,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 +561,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 +576,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_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 3a874fc621d3..8fdd41f4b4f2 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/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index b03536008ad9..005ff25a405f 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -2,7 +2,7 @@ #include <linux/types.h> #include <linux/proc_fs.h> -#include <net/ieee80211_crypt.h> +#include <net/lib80211.h> #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); @@ -106,7 +107,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 +118,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 +148,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 +159,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", @@ -208,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); } } @@ -314,7 +314,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 +331,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/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index a68f97c39359..4d8d51a353cd 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -6,6 +6,7 @@ #include <linux/mutex.h> #include <net/iw_handler.h> #include <net/ieee80211_radiotap.h> +#include <net/lib80211.h> #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; @@ -822,7 +820,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 */ diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig new file mode 100644 index 000000000000..3d5cc4463d4d --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -0,0 +1,191 @@ +# +# 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 LIBIPW + ---help--- + A driver for the Intel PRO/Wireless 2100 Network + Connection 802.11b wireless network adapter. + + See <file:Documentation/networking/README.ipw2100> 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 + <http://ipw2100.sf.net/>. 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: + + <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + + 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 LIBIPW + ---help--- + A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network + Connection adapters. + + See <file:Documentation/networking/README.ipw2200> 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 + <http://ipw2200.sf.net/>. 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: + + <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + + 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 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 <net/ieee80211.h> + + 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 new file mode 100644 index 000000000000..aecd2cff462b --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Intel Centrino wireless drivers +# + +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/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index bca74811bc7f..1667065b86a7 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -163,6 +163,8 @@ that only one external action is invoked at a time. #include <linux/ctype.h> #include <linux/pm_qos_params.h> +#include <net/lib80211.h> + #include "ipw2100.h" #define IPW2100_VERSION "git-1.2.2" @@ -185,7 +187,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 +203,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; @@ -1914,7 +1916,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1975,10 +1977,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", - priv->net_dev->name, escape_essid(essid, essid_len), - txratename, chan, print_mac(mac, bssid)); + 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)) { @@ -2004,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_essid(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); @@ -2046,12 +2048,12 @@ 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); + DECLARE_SSID_BUF(ssid); IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s \n", - escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -4008,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"); @@ -4058,7 +4060,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 +4087,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 +4663,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 +4673,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 +5052,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: <clear>\n"); #endif @@ -5271,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)) @@ -5517,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 @@ -6905,7 +6902,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 +6927,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 +6943,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 +6952,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; } @@ -6971,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)) { @@ -7000,8 +6994,8 @@ static int ipw2100_wx_set_essid(struct net_device *dev, goto done; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(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); @@ -7022,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_essid(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 */ @@ -7625,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; @@ -7640,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; @@ -7717,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; @@ -7733,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/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index bbf1ddcafba8..bbf1ddcafba8 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 7a9f901d4ff6..625f2cf99fa9 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/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; @@ -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); @@ -4347,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 @@ -4398,7 +4397,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_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); notif->size = le16_to_cpu(notif->size); @@ -4412,11 +4411,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", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "associated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); switch (priv->ieee->iw_mode) { case IW_MODE_INFRA: @@ -4450,7 +4448,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)) { @@ -4493,13 +4491,14 @@ 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), + print_ssid(ssid, + priv-> + essid, + priv-> + essid_len), + priv->bssid, le16_to_cpu(auth->status), ipw_get_status_code (le16_to_cpu @@ -4516,11 +4515,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", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "authenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); break; } @@ -4545,11 +4543,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", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_DISASSOCIATING | @@ -4584,10 +4581,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", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "authenticated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status |= STATUS_AUTH; break; @@ -4603,10 +4600,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", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "deauthenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_ASSOCIATING | STATUS_AUTH | @@ -5430,27 +5427,17 @@ 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); + 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 (%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)); - 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 " - "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5460,11 +5447,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)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } } else { @@ -5477,13 +5464,14 @@ 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), + print_ssid(ssid, 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), - escape_essid(priv->essid, - priv->essid_len)); + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5494,24 +5482,25 @@ 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)); + 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_essid(match->network->ssid, - match->network->ssid_len)); + 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 (%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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5519,10 +5508,11 @@ 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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, network->channel, priv->channel); return 0; } @@ -5530,10 +5520,11 @@ 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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv-> capability & CAP_PRIVACY_ON ? "on" : "off", network-> @@ -5543,41 +5534,44 @@ 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" - ".\n", escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid), - print_mac(mac2, priv->bssid)); + 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 (%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)); + 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 (%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)); + print_ssid(ssid, network->ssid, + network->ssid_len), + 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)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5588,15 +5582,16 @@ 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", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + 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; @@ -5627,8 +5622,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)); + print_ssid(ssid, priv->essid, + priv->essid_len)); ipw_remove_current_network(priv); } @@ -5644,7 +5639,7 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5652,20 +5647,11 @@ 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)); - 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 " - "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5675,11 +5661,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)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } } else { @@ -5691,13 +5677,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_essid(network->ssid, network->ssid_len), + print_ssid(ssid, 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), - escape_essid(priv->essid, - priv->essid_len)); + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5707,14 +5694,14 @@ 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), + print_ssid(ssid, 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), - escape_essid(match->network->ssid, - match->network->ssid_len), - print_mac(mac, match->network->bssid)); + 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; } @@ -5722,11 +5709,12 @@ 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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_associate)); return 0; @@ -5735,10 +5723,11 @@ 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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5746,10 +5735,11 @@ 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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, network->channel, priv->channel); return 0; } @@ -5757,10 +5747,11 @@ 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), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv->capability & CAP_PRIVACY_ON ? "on" : "off", network->capability & @@ -5770,48 +5761,53 @@ 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", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), print_mac(mac, priv->bssid)); + 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 (%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)); + 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 (%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)); + 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 (%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)); + print_ssid(ssid, network->ssid, + network->ssid_len), + 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)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5823,9 +5819,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", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); return 1; } @@ -6067,7 +6063,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { - DECLARE_MAC_BUF(mac); + 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) @@ -6076,12 +6072,11 @@ 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)); + 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 %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) @@ -6277,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; @@ -6320,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 @@ -6339,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 @@ -6607,7 +6617,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; @@ -6629,7 +6639,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; @@ -6706,7 +6716,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; @@ -6722,7 +6732,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; @@ -6893,8 +6903,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, @@ -7296,7 +7305,7 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7365,7 +7374,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), + print_ssid(ssid, priv->essid, priv->essid_len), network->channel, ipw_modes[priv->assoc_request.ieee_mode], rates->num_rates, @@ -7464,9 +7473,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n", - escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); return 0; } @@ -7556,6 +7565,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"); @@ -7582,8 +7592,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; } @@ -7605,7 +7614,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) || @@ -7616,11 +7624,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)); + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); list_add_tail(&target->list, &priv->ieee->network_free_list); } @@ -7673,12 +7681,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 */ @@ -7806,15 +7814,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; @@ -7990,17 +7989,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) @@ -8018,19 +8017,10 @@ 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); - /* 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 */ @@ -8238,7 +8228,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; } @@ -8302,9 +8292,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); @@ -8434,18 +8421,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; } @@ -8984,7 +8965,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 @@ -9015,8 +8995,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); @@ -9034,7 +9014,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 */ @@ -9046,8 +9025,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; } @@ -9058,6 +9037,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); @@ -9082,8 +9062,8 @@ static int ipw_wx_set_essid(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(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); @@ -9102,6 +9082,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 */ @@ -9109,7 +9090,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)); + 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 */ @@ -10203,10 +10184,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; } } @@ -10274,8 +10253,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 @@ -10403,17 +10382,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) @@ -10428,13 +10407,13 @@ 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; - 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)); @@ -10509,15 +10488,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; @@ -11652,7 +11630,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; @@ -11944,7 +11922,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)"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 0bad1ec3e7e0..277b274d4be5 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -48,6 +48,7 @@ #include <linux/jiffies.h> #include <asm/io.h> +#include <net/lib80211.h> #include <net/ieee80211.h> #include <net/ieee80211_radiotap.h> @@ -244,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 diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c new file mode 100644 index 000000000000..960ad13f5e9f --- /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 <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> + +#include <net/ieee80211.h> + +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 000000000000..a2f5616d5b09 --- /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 + <j@w1.fi> + Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> + + 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 <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> +#include <net/net_namespace.h> +#include <net/arp.h> + +#include <net/ieee80211.h> + +#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 <jketreno@linux.intel.com>" + +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 <linux/moduleparam.h> +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 000000000000..9c67dfae4320 --- /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 + * <j@w1.fi> + * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> + * 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 <linux/compiler.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> +#include <linux/ctype.h> + +#include <net/lib80211.h> +#include <net/ieee80211.h> + +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 <hidden> 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 000000000000..f78f57e8844a --- /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 <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/if_arp.h> +#include <linux/in6.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/proc_fs.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/tcp.h> +#include <linux/types.h> +#include <linux/wireless.h> +#include <linux/etherdevice.h> +#include <asm/uaccess.h> + +#include <net/ieee80211.h> + +/* + +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 000000000000..31ea3abfc327 --- /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 + <j@w1.fi> + Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> + + 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 <ipw2100-admin@linux.intel.com> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ + +#include <linux/kmod.h> +#include <linux/module.h> +#include <linux/jiffies.h> + +#include <net/lib80211.h> +#include <net/ieee80211.h> +#include <linux/wireless.h> + +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); diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b0ac0ce3fb9f..47bee0ee0a7c 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/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 47aa28f6a513..0be9e6b66aa0 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,9 +5,10 @@ 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 +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-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 817ece773643..c6f4eb54a2b1 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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, @@ -121,7 +127,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 +164,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 @@ -220,7 +226,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 +328,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 +477,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 +514,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 +672,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 +739,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 +797,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 @@ -991,7 +997,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; @@ -1158,9 +1164,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 +1284,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 +1385,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 +1578,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 +1599,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-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h index bc12f97ba0b1..6f463555402c 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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<api>.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-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index 33016fb5e9b3..85eb778f9df1 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 644bd9e08052..94ea0e60c410 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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. @@ -321,6 +320,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 b3fe48de3ae7..2440fd664dd5 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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. * @@ -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); @@ -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) \ @@ -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; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl3945_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWL3945_DEBUG @@ -307,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 @@ -328,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 @@ -389,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); } @@ -402,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-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 705c65bed9fd..4c638909a7db 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 2fbd126c1347..749ac035fd6a 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 6fc5e7361f26..9b60a0c5de5f 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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; @@ -114,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 @@ -203,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) { @@ -217,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; @@ -227,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); @@ -239,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; @@ -254,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 */ @@ -275,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 @@ -313,14 +321,25 @@ 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, +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"); @@ -330,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"); } @@ -355,12 +379,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; @@ -422,34 +440,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,7 +450,7 @@ 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; + 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; @@ -469,8 +459,9 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband IWL_DEBUG_RATE("enter\n"); - retries = info->status.retry_count; - first_index = sband->bitrates[info->tx_rate_idx].hw_value; + 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)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -496,13 +487,13 @@ 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; - last_index = rs_adjust_next_rate(priv, + last_index = iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -510,15 +501,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 = - rs_adjust_next_rate(priv, scale_rate_index); + scale_rate_index = last_index; } @@ -529,7 +518,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 @@ -537,9 +526,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); @@ -630,10 +620,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,7 +640,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; - DECLARE_MAC_BUF(mac); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); @@ -660,7 +651,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; } @@ -675,8 +666,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); } @@ -686,8 +677,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, 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; } @@ -697,7 +693,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, 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: " @@ -711,8 +706,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } - 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, @@ -760,13 +753,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } } - 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) { @@ -793,24 +788,83 @@ 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); } +#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, .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, .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) @@ -827,13 +881,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); @@ -857,7 +910,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; @@ -871,6 +923,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) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index 98b17ae6ef24..b5a66135dedd 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 7ca5627cc078..8fdb34222c0a 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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 */ @@ -261,6 +261,37 @@ 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; + 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; + } + + return next_rate; +} + /** * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd @@ -308,6 +339,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; 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 +350,18 @@ 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; + + info->status.rates[0].idx = rate_idx; + info->status.rates[0].count = fail + 1; /* 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 +370,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); @@ -756,13 +793,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; - DECLARE_MAC_BUF(mac); + + 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))) { @@ -770,8 +813,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; @@ -1060,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"); @@ -1243,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); @@ -1269,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) { @@ -1830,7 +1870,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); @@ -2268,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"); @@ -2337,7 +2378,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) { @@ -2345,11 +2387,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 = @@ -2360,11 +2405,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: @@ -2428,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); @@ -2467,13 +2520,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 bdd32475b99c..2c0ddc5110c6 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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 2 + +/* 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: @@ -401,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 @@ -472,7 +470,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; @@ -505,7 +502,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 */ @@ -587,8 +584,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); @@ -762,6 +758,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 */ @@ -804,6 +802,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; @@ -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; @@ -888,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; @@ -903,9 +900,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 */ @@ -954,6 +948,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-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index f4793a609443..6649f7b55650 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -71,7 +71,7 @@ #include "iwl-fh.h" -/* EERPROM */ +/* EEPROM */ #define IWL4965_EEPROM_IMG_SIZE 1024 /* @@ -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 @@ -111,7 +105,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) @@ -287,13 +280,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 @@ -301,7 +294,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 @@ -345,7 +338,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: * @@ -815,125 +808,14 @@ 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 #define IWL49_NUM_AMPDU_QUEUES 8 -/** - * struct iwl_tfd_frame_data - * - * 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). - * - * 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] - */ -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_frame - * - * Transmit Frame Descriptor (TFD) - * - * 4965 supports up to 16 Tx queues resident in host DRAM. - * 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. - * - * Driver must indicate the physical address of the base of each - * circular buffer via the 4965's 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 - * 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. - */ -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; -} __attribute__ ((packed)); - - -/** - * 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 * @@ -947,71 +829,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)]; -} __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_sched_queue_byte_cnt_tbl - queues_byte_cnt_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; +struct iwl4965_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; + u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)]; } __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 9838de5f4369..5a72bc0377de 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -48,18 +48,21 @@ 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" +/* 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 */ 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 */ @@ -246,7 +249,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); @@ -318,31 +321,13 @@ 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); } /* - * 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) @@ -366,9 +351,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; @@ -414,7 +398,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 */ @@ -442,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); @@ -450,17 +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_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; + iwl_poll_direct_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); -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) @@ -496,11 +475,9 @@ 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, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); - - if (ret) + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) goto out; udelay(10); @@ -537,10 +514,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.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; @@ -587,11 +564,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.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]; @@ -619,10 +596,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; } @@ -643,7 +620,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); @@ -679,7 +656,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), @@ -709,9 +686,10 @@ 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; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -733,8 +711,18 @@ 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); + 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); + + /* 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); @@ -766,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); @@ -822,7 +810,9 @@ 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.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; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; @@ -1650,36 +1640,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, - sizeof(struct iwl4965_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; - - memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - - priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed); - - 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 */ @@ -1687,21 +1647,22 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - int len; + struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; - struct iwl4965_shared *shared_data = priv->shared_virt; + 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); + scd_bc_tbl[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) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } /** @@ -1956,7 +1917,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); @@ -2037,7 +1998,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, @@ -2059,7 +2020,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); @@ -2070,9 +2031,9 @@ 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)? + 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 */ @@ -2158,12 +2119,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 +2140,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 +2155,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 +2166,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.retry_count = tx_resp->failure_frame; - info->flags |= - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + 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, 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 (qc && likely(sta_id != IWL_INVALID_STATION)) 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 && 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)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } @@ -2328,9 +2283,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, - .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, @@ -2347,7 +2299,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 = { @@ -2362,11 +2314,11 @@ 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, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .temperature = iwl4965_temperature_calib, }; @@ -2378,15 +2330,19 @@ static struct iwl_ops iwl4965_ops = { struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", - .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", + .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, + .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, }; /* Module firmware */ -MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode"); +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])"); @@ -2394,7 +2350,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); @@ -2402,9 +2358,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-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index c479ee211c5c..82c3859ce0f8 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -73,69 +73,27 @@ #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_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]; -} __attribute__ ((packed)); - -struct iwl5000_shared { - struct iwl5000_sched_queue_byte_cnt_tbl - queues_byte_cnt_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; +/** + * 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_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; } __attribute__ ((packed)); -/* calibrations defined for 5000 */ -/* defines the order in which results should be sent to the runtime uCode */ -enum iwl5000_calib { - 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 5155b8a760a7..66d053d28a74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -44,7 +44,21 @@ #include "iwl-helpers.h" #include "iwl-5000-hw.h" -#define IWL5000_UCODE_API "-1" +/* Highest firmware API version supported */ +#define IWL5000_UCODE_API_MAX 1 +#define IWL5150_UCODE_API_MAX 1 + +/* 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, @@ -59,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); @@ -67,17 +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_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + 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; } @@ -92,7 +101,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 */ @@ -106,9 +115,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; @@ -132,7 +140,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; @@ -175,9 +183,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; @@ -217,7 +224,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 */ @@ -291,30 +298,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; } @@ -348,10 +342,14 @@ 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.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, @@ -373,14 +371,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 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; - 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"); @@ -390,8 +393,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; @@ -426,31 +429,41 @@ 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 */ -static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) +static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { + struct iwl_calib_xtal_freq_cmd cmd; 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 = 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], + (u8 *)&cmd, sizeof(cmd)); } 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, }; @@ -467,7 +480,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; @@ -478,14 +491,20 @@ 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_DC_CMD: + index = IWL_CALIB_DC; + break; + 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; + case IWL_PHY_CALIBRATE_BASE_BAND_CMD: + index = IWL_CALIB_BASE_BAND; break; default: IWL_ERROR("Unknown calibration notification %d\n", @@ -535,7 +554,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, @@ -547,7 +566,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); @@ -561,14 +580,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"); @@ -682,7 +700,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) | @@ -710,9 +728,10 @@ 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; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -734,11 +753,21 @@ 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_byte_cnt_tbls)) >> 10); + 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); + + /* 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)); + IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); /* initiate the queues */ @@ -765,6 +794,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]; @@ -784,10 +814,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; } @@ -802,7 +830,9 @@ 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.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; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; @@ -814,10 +844,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; @@ -840,43 +874,36 @@ 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; } - 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; + /* 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(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + 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 = + BIT(IWL_CALIB_DC) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); - memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); + break; + } - priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); 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); -} - -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 */ @@ -884,16 +911,18 @@ 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; - 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) { @@ -909,40 +938,35 @@ 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); + scd_bc_tbl[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) + 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_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; - struct iwl5000_shared *shared_data = priv->shared_virt; - u8 sta = 0; + 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)); + scd_bc_tbl[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) + scd_bc_tbl[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, @@ -996,7 +1020,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); @@ -1089,7 +1113,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) @@ -1136,10 +1160,10 @@ 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; + 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 */ @@ -1225,9 +1249,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 " @@ -1240,25 +1264,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); @@ -1268,58 +1280,58 @@ 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 { - info->status.retry_count = tx_resp->failure_frame; - info->flags = - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + 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; 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"); } -/* 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; @@ -1466,9 +1478,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, - .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, @@ -1482,13 +1491,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 = { @@ -1503,7 +1512,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, }, }; @@ -1517,7 +1526,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 */ @@ -1526,50 +1534,84 @@ 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_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, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_bg_cfg = { .name = "5100BG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .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, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_abg_cfg = { .name = "5100ABG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .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, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_agn_cfg = { .name = "5100AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .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, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5350_agn_cfg = { .name = "5350AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .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, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5150_agn_cfg = { + .name = "5150AGN", + .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, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; -MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode"); +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, @@ -1577,12 +1619,10 @@ 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"); -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-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c new file mode 100644 index 000000000000..b8137eeae1db --- /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: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include <linux/kernel.h> +#include <net/mac80211.h> +#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-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e2a58e477036..f3f17929ca0b 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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" @@ -188,7 +187,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 }; @@ -281,10 +280,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 @@ -357,11 +355,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); } } @@ -775,7 +771,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; @@ -787,12 +783,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 */ @@ -800,13 +796,11 @@ 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; - lq_sta = (struct iwl_lq_sta *)priv_sta; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) goto out; @@ -832,21 +826,20 @@ 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); + /* 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; } @@ -1135,11 +1128,10 @@ 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_info.ht_supported) + if (!conf->ht.enabled || !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; @@ -1203,8 +1195,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_info.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); @@ -1684,7 +1675,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; @@ -1699,13 +1689,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; @@ -2003,9 +1992,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); @@ -2081,15 +2069,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); @@ -2103,40 +2089,38 @@ 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; - __le16 fc; - struct iwl_lq_sta *lq_sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + 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) { - sel->rate_idx = rate_lowest_index(sband, 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) { 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); } @@ -2148,14 +2132,12 @@ 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); - 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; - sel->rate_idx = i; + info->control.rates[0].idx = rate_idx; } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, @@ -2189,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]; @@ -2205,15 +2188,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); } @@ -2225,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); @@ -2244,19 +2214,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 = 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_conf.supp_mcs_set[1] << 1; - lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[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_conf.supp_mcs_set[2] << 1; - lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[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; @@ -2265,7 +2235,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; @@ -2273,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); } @@ -2405,19 +2386,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) { @@ -2552,7 +2520,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, @@ -2605,7 +2573,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.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index d148d73635eb..78ee83adf742 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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 */ @@ -284,7 +284,17 @@ static inline u8 num_of_ant(u8 mask) !!((mask) & ANT_C); } -static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) +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 iwl_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; @@ -294,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 * @@ -306,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-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c4c0371c763b..5da6b35cd26d 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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"); @@ -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,79 +108,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } /** - * iwl4965_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) -{ - 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; -} - -/** * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon * @@ -228,18 +155,17 @@ 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; - DECLARE_MAC_BUF(mac); int ret; bool new_assoc = !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); @@ -253,14 +179,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_agn_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); @@ -300,12 +226,12 @@ 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); + 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 @@ -375,16 +301,16 @@ 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 = { + struct iwl_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, @@ -393,7 +319,7 @@ static int iwl4965_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) @@ -445,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) && @@ -460,16 +386,16 @@ 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; /* 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; @@ -485,7 +411,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; @@ -498,7 +424,6 @@ static unsigned int iwl4965_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); @@ -517,7 +442,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; @@ -532,9 +457,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]); @@ -550,20 +475,33 @@ 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_ht_info *ht_conf = bss_conf->ht_conf; - 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,29 +512,36 @@ 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); - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + + /* + * 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_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->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); + iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_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_IE_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"); } @@ -608,9 +553,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 && @@ -637,23 +579,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; @@ -661,49 +602,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, @@ -715,7 +639,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 @@ -733,13 +657,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 iwl_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; @@ -762,7 +686,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; } @@ -808,11 +732,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) 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) { - priv->iw_mode = mode; - - iwl4965_connection_init_rx_config(priv); + iwl_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl_clear_stations_table(priv); @@ -828,12 +750,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; @@ -880,138 +802,6 @@ static void iwl4965_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 iwl4965_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 iwl4965_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 iwl4965_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 = - iwl4965_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 = - iwl4965_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 /****************************************************************************** * @@ -1054,7 +844,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; @@ -1070,47 +860,29 @@ 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; - 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; priv->staging_rxon.channel = csa->channel; } -static void iwl4965_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 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 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 } -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; @@ -1120,7 +892,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); @@ -1142,11 +914,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. * @@ -1155,22 +927,27 @@ 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; 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); } -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 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 " @@ -1189,7 +966,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; @@ -1258,7 +1035,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; @@ -1290,7 +1067,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. @@ -1301,14 +1078,12 @@ 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[SPECTRUM_MEASURE_NOTIFICATION] = - iwl4965_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + 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 @@ -1318,10 +1093,11 @@ 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 */ - 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; @@ -1334,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 * @@ -1364,7 +1130,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 */ @@ -1400,13 +1166,14 @@ 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); /* 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); @@ -1451,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; } } @@ -1463,10 +1230,9 @@ 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; - DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); @@ -1478,50 +1244,26 @@ 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 -static void iwl4965_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) { - /* 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); } -static inline void iwl4965_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"); -} - - /** - * 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. */ @@ -1531,7 +1273,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 @@ -1555,14 +1297,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); @@ -1572,7 +1314,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; @@ -1618,9 +1360,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; @@ -1652,14 +1394,17 @@ static void iwl4965_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 * 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; } @@ -1674,7 +1419,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; } @@ -1720,7 +1465,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)) { @@ -1734,7 +1479,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; @@ -1766,7 +1511,7 @@ static irqreturn_t iwl4965_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; } @@ -1775,7 +1520,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); @@ -1787,7 +1532,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; } @@ -1798,7 +1543,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); @@ -1808,7 +1553,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); @@ -1816,31 +1561,47 @@ 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; + 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 ver, 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)) { @@ -1852,14 +1613,40 @@ static int iwl4965_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); + 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 = 0x%x\n", ver); + /* 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", @@ -1964,7 +1751,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); @@ -2002,7 +1789,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); @@ -2011,6 +1798,10 @@ static int iwl4965_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 @@ -2047,7 +1838,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)) @@ -2067,17 +1858,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); + 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); @@ -2089,12 +1880,21 @@ 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); + /* 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)) - iwl4965_set_mode(priv, priv->iw_mode); + iwl_set_mode(priv, priv->iw_mode); return; @@ -2104,7 +1904,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); @@ -2131,14 +1931,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,8 +1992,6 @@ static void __iwl4965_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)); @@ -2205,10 +2003,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); @@ -2216,7 +2014,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; @@ -2238,7 +2036,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; @@ -2246,12 +2044,6 @@ static int __iwl4965_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"); @@ -2265,7 +2057,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); @@ -2295,7 +2087,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"); @@ -2303,7 +2095,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 @@ -2345,7 +2137,7 @@ static void iwl_bg_alive_start(struct work_struct *data) mutex_unlock(&priv->mutex); } -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); @@ -2379,28 +2171,6 @@ 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) -{ - 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 = iwl4965_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); - } - - 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, @@ -2424,7 +2194,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); @@ -2432,23 +2202,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); @@ -2463,11 +2233,10 @@ 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; - DECLARE_MAC_BUF(mac); unsigned long flags; if (priv->iw_mode == NL80211_IFTYPE_AP) { @@ -2475,9 +2244,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)) @@ -2493,10 +2261,9 @@ 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); - 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) @@ -2529,7 +2296,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: @@ -2541,7 +2308,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; @@ -2578,7 +2345,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; @@ -2600,7 +2367,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); @@ -2615,7 +2382,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); @@ -2623,7 +2390,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) } } - ret = __iwl4965_up(priv); + ret = __iwl_up(priv); mutex_unlock(&priv->mutex); @@ -2669,7 +2436,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; @@ -2691,7 +2458,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); @@ -2702,7 +2469,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; @@ -2718,12 +2485,11 @@ 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; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -2734,17 +2500,18 @@ 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); 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); } - 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); @@ -2755,16 +2522,17 @@ 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, struct ieee80211_conf *conf) +static int iwl_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; @@ -2772,6 +2540,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co 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; @@ -2829,13 +2599,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co /* 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 @@ -2863,11 +2633,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co 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"); @@ -2878,7 +2648,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; @@ -2887,15 +2657,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); + iwl_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) @@ -2928,29 +2697,25 @@ 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, * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl4965_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) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; int rc; if (conf == NULL) @@ -2966,26 +2731,20 @@ 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); + mutex_lock(&priv->mutex); + rc = iwl_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) 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; 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: @@ -2998,8 +2757,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); @@ -3030,9 +2789,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); @@ -3041,45 +2800,63 @@ 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: - 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); 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) { struct iwl_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; } -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; @@ -3091,13 +2868,11 @@ 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; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); @@ -3106,7 +2881,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) @@ -3133,8 +2908,7 @@ 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_ht_conf(priv, bss_conf); iwl_set_rxon_chain(priv); } @@ -3157,7 +2931,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; @@ -3187,12 +2961,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. @@ -3233,64 +3001,24 @@ 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) { - struct iwl_priv *priv = hw->priv; - u8 sta_id = IWL_INVALID_STATION; - unsigned long flags; - __le16 key_flags = 0; - int i; - DECLARE_MAC_BUF(mac); + 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 - %s not in station map.\n", - print_mac(mac, 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"); } -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) { 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; @@ -3308,8 +3036,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; } @@ -3357,7 +3085,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; @@ -3376,11 +3104,6 @@ static int iwl4965_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); @@ -3405,15 +3128,14 @@ 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) { 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; @@ -3421,10 +3143,10 @@ static int iwl4965_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); @@ -3438,7 +3160,8 @@ 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; @@ -3473,7 +3196,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; @@ -3485,7 +3208,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; @@ -3529,7 +3252,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); @@ -3552,31 +3275,28 @@ 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; __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; } @@ -3596,9 +3316,8 @@ 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); return 0; } @@ -3613,7 +3332,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk /* * 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. @@ -3699,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, @@ -3750,7 +3473,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); @@ -3791,7 +3514,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); @@ -3802,79 +3525,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); - iwl4965_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) @@ -3953,7 +3603,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; @@ -3962,68 +3613,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) @@ -4086,12 +3675,11 @@ 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->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); @@ -4104,10 +3692,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) @@ -4123,13 +3711,9 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) del_timer_sync(&priv->statistics_periodic); } -static struct attribute *iwl4965_sysfs_entries[] = { - &dev_attr_channels.attr, +static struct attribute *iwl_sysfs_entries[] = { &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, @@ -4144,39 +3728,38 @@ 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; 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 @@ -4188,10 +3771,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; @@ -4285,7 +3868,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); /************************ @@ -4319,10 +3902,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; @@ -4358,7 +3941,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: @@ -4376,7 +3959,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; @@ -4387,10 +3970,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); @@ -4398,20 +3981,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); @@ -4424,7 +4007,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); @@ -4445,13 +4028,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; } @@ -4460,14 +4043,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; @@ -4502,7 +4085,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); @@ -4510,15 +4097,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; @@ -4544,11 +4131,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-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 72fbf47229db..f836ecc55758 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -70,7 +70,16 @@ * INIT calibrations framework *****************************************************************************/ - int iwl_send_calib_results(struct iwl_priv *priv) +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; int i = 0; @@ -80,14 +89,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-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 94c8e316382a..1abe84bb74ad 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 8d04e966ad48..52966ffbef6e 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -66,8 +66,14 @@ * 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__ + +/* 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, @@ -88,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, @@ -98,6 +105,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 */ @@ -129,7 +141,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 */ @@ -167,8 +179,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 @@ -180,7 +192,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 @@ -208,10 +220,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 * @@ -225,8 +238,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 * @@ -247,8 +261,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 @@ -278,18 +292,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 @@ -340,7 +356,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 @@ -359,7 +375,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) /* @@ -376,7 +392,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 @@ -477,11 +493,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) @@ -492,7 +503,7 @@ struct iwl_error_resp { u8 reserved1; __le16 bad_cmd_seq_num; __le32 error_info; - union tsf timestamp; + __le64 timestamp; } __attribute__ ((packed)); /****************************************************************************** @@ -513,75 +524,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) @@ -620,7 +631,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; @@ -679,8 +690,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; @@ -691,7 +702,7 @@ struct iwl4965_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; @@ -704,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 */ @@ -741,9 +752,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 @@ -780,34 +791,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 */ @@ -1013,33 +1024,14 @@ 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 __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) @@ -1062,26 +1054,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 @@ -1111,7 +1083,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)); @@ -1167,24 +1139,24 @@ 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) +#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). @@ -1192,40 +1164,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. @@ -1233,14 +1205,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) /* @@ -1266,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; @@ -1297,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_* */ @@ -1411,21 +1383,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); } @@ -1450,10 +1422,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 @@ -1526,6 +1497,28 @@ struct iwl4965_tx_resp { } u; } __attribute__ ((packed)); +/* + * definitions for initial rate index field + * 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 + * 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) */ @@ -1540,14 +1533,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 @@ -1742,7 +1738,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. @@ -1881,9 +1877,9 @@ 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 { +struct iwl_bt_cmd { u8 flags; u8 lead_time; u8 max_kill; @@ -1909,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 */ @@ -1933,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 @@ -1947,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, @@ -1965,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), @@ -1989,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 */ @@ -1997,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. */ @@ -2007,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)); /****************************************************************************** @@ -2043,15 +2039,15 @@ 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 -#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; @@ -2067,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; @@ -2097,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)); @@ -2125,8 +2121,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 @@ -2167,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 { @@ -2177,8 +2173,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 /* @@ -2267,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 @@ -2278,7 +2274,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 @@ -2422,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 */ @@ -2540,8 +2538,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)); @@ -2561,8 +2559,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; @@ -2578,7 +2576,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; @@ -2778,8 +2776,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 @@ -2849,56 +2847,26 @@ 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 */ - -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, -}; +/* Phy calibration command for series */ enum { - CALIBRATION_CFG_CMD = 0x65, - CALIBRATION_RES_NOTIFICATION = 0x66, - CALIBRATION_COMPLETE_NOTIFICATION = 0x67 + 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_crystal_freq_cmd { - 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) +#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff) struct iwl_calib_cfg_elmnt_s { __le32 is_enable; @@ -2914,32 +2882,52 @@ 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_calibration_chain_noise_reset_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ - u8 flags; /* not used */ - __le16 reserved; +struct iwl_calib_cmd { + struct iwl_calib_hdr hdr; + u8 data[0]; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_gain_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ - u8 flags; /* not used */ - __le16 reserved; +/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ +struct iwl_calib_diff_gain_cmd { + 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_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 { + struct iwl_calib_hdr hdr; u8 delta_gain_1; u8 delta_gain_2; - __le16 reserved1; + u8 pad[2]; } __attribute__ ((packed)); /****************************************************************************** @@ -2999,11 +2987,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) @@ -3025,26 +3013,22 @@ 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; + 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 iwl5000_calibration calib; + struct iwl_missed_beacon_notif missed_beacon; __le32 status; u8 raw[0]; } 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 /* __iwl4965_commands_h__ */ +#endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 01a845851338..73d7973707eb 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -30,19 +30,19 @@ #include <linux/module.h> #include <net/mac80211.h> -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" #include "iwl-power.h" +#include "iwl-sta.h" 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) \ @@ -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); @@ -119,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; @@ -140,7 +143,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); @@ -177,52 +190,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; @@ -271,55 +238,30 @@ 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)); - - /* clean ucode key table bit map */ - priv->ucode_key_table = 0; - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} -EXPORT_SYMBOL(iwl_clear_stations_table); - 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; } @@ -385,10 +327,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; @@ -396,45 +338,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); } } @@ -498,7 +441,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]; @@ -508,7 +451,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; @@ -598,8 +541,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, @@ -612,10 +555,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); @@ -623,24 +566,24 @@ 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; } 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); @@ -665,22 +608,15 @@ 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_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; @@ -694,14 +630,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", - ht_info->supp_mcs_set[0], - ht_info->supp_mcs_set[1], - ht_info->supp_mcs_set[2], + "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); @@ -745,7 +679,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; @@ -871,11 +805,14 @@ 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) | BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->fw_handles_regulatory = true; + /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ @@ -948,16 +885,12 @@ 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 */ 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; @@ -1025,6 +958,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; @@ -1172,24 +1129,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; - return "UNKNOWN"; + if (i < 0 || i > max) + i = max; + + return desc_lookup_text[i]; } #define ERROR_START_OFFSET (1 * sizeof(u32)) @@ -1235,9 +1215,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, @@ -1377,6 +1357,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rf_kill_ct_config); + /* * CARD_STATE_CMD * @@ -1465,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. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 288b6a800e03..7c3a20a986bb 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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 "<ilw@linux.intel.com>" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -100,12 +101,8 @@ 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); - 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, @@ -157,22 +154,53 @@ 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 */ - 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) */ 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<api>.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; + u16 eeprom_calib_ver; const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; }; @@ -184,22 +212,17 @@ 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); 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); 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 @@ -212,8 +235,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); @@ -237,7 +258,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 +279,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; @@ -289,6 +316,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 * *****************************************************/ @@ -308,11 +343,18 @@ 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); 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-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 662edf4f8d22..f34ede44ed10 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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) @@ -214,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) @@ -286,4 +290,4 @@ #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - +#endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e548d67f87fd..56c13b458de7 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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; @@ -53,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; @@ -70,6 +78,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 */ @@ -85,29 +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 - * - * % cat /proc/net/iwl/debug_level - * - * you simply need to add your entry to the iwl_debug_levels array. + * The active debug levels can be accessed via files * - * If you do not see debug_level in /proc/net/iwl then you do not have - * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration + * /sys/module/iwlagn/parameters/debug{50} + * /sys/class/net/wlan0/device/debug_level * + * when CONFIG_IWLWIFI_DEBUG=y. */ #define IWL_DL_INFO (1 << 0) @@ -183,6 +190,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-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 20db0eb636a8..d5253a179dec 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -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) @@ -228,7 +229,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 +242,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", @@ -349,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 @@ -388,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); @@ -416,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); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9966d4e384ce..0468fcc1ea98 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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 */ @@ -113,11 +114,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]; }; /** @@ -135,12 +134,13 @@ 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; - int sched_retry; - int active; + u8 need_update; + u8 sched_retry; + u8 active; + u8 swq_id; }; #define IWL_NUM_SCAN_RATES (2) @@ -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 @@ -253,7 +247,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 @@ -269,24 +264,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 iwl4965_rxon_time_cmd rxon_time; - 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; @@ -309,7 +296,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 @@ -324,26 +310,19 @@ 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; }; #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 @@ -413,9 +392,8 @@ 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; u8 tx_chan_width; u8 ht_protection; @@ -444,7 +422,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; @@ -470,7 +447,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 */ @@ -511,11 +488,15 @@ 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 + * @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 * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) @@ -528,11 +509,13 @@ 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 calibrations 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; + u8 max_txq_num; + u8 dma_chnl_num; + u16 scd_bc_tbls_size; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; @@ -549,22 +532,10 @@ 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; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#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) /****************************************************************************** * @@ -581,13 +552,8 @@ 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_ht_info *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); @@ -611,19 +577,15 @@ 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; }; +#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 @@ -638,7 +600,6 @@ struct iwl_kw { #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 @@ -691,13 +652,20 @@ 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 + * defines the order in which results of initial calibrations + * should be sent to the runtime uCode + */ +enum iwl_calib { + IWL_CALIB_XTAL, + IWL_CALIB_DC, + IWL_CALIB_LO, + IWL_CALIB_TX_IQ, + IWL_CALIB_TX_IQ_PERD, + IWL_CALIB_BASE_BAND, + IWL_CALIB_MAX }; /* Opaque calibration results */ @@ -766,7 +734,6 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ -#define IWL_CALIB_MAX 3 struct iwl_priv { @@ -790,7 +757,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 */ @@ -801,10 +768,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; @@ -818,12 +781,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 */ @@ -840,6 +804,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 */ @@ -850,7 +816,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 @@ -882,7 +848,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; @@ -903,12 +868,14 @@ 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; - 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 */ @@ -923,8 +890,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; @@ -965,11 +930,7 @@ struct iwl_priv { struct ieee80211_vif *vif; struct iwl_hw_params hw_params; - /* driver/uCode shared Tx Byte Counts and Rx status */ - void *shared_virt; - int rb_closed_offset; - /* Physical Pointer to Tx Byte Counts and Rx status */ - dma_addr_t shared_phys; + /* Current association information needed to configure the * hardware */ @@ -992,7 +953,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; @@ -1004,9 +964,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 */ @@ -1091,26 +1048,4 @@ 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); - -/* Requires full declaration of iwl_priv before including */ - #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 37155755efc5..ce2f47306cea 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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); @@ -210,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 */ @@ -241,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; @@ -279,7 +273,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("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; + } 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 d3a2a5b4ac56..603c84bed630 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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) */ @@ -147,6 +144,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) @@ -174,6 +172,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 +372,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); }; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index a72efdf6d1dd..d7da19864550 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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 */ @@ -70,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. @@ -264,6 +266,7 @@ #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_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ /** * Rx Shared Status Registers (RSSR) @@ -290,6 +293,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) * @@ -316,34 +326,41 @@ #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) + +/* 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) \ + (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_MSG_MODE_TXF (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001) -#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_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008) -#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_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_CHNL_NUM (7) +#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_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_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_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_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) -#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_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) @@ -360,7 +377,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) @@ -369,25 +386,99 @@ (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) +#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) -/* TCSR: tx_config register values */ -#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ +/** + * 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)); + + +#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) +{ + 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-15 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-4 number of active tbs + * 5 reserved + * 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. + */ +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-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 8300f3d00a06..01a2169cecec 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 <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -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-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 41eed6793328..ca4f638ab9d0 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -32,110 +32,6 @@ #include <linux/ctype.h> -/* - * 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)))) @@ -159,11 +55,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-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 9740fcc1805e..0a92e7431ada 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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. * @@ -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; - mdelay(10); - i += 10; - } while (i < timeout); + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); return -ETIMEDOUT; } @@ -109,7 +110,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) \ @@ -269,19 +270,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; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -308,6 +300,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 @@ -330,6 +323,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 @@ -392,12 +386,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); } @@ -405,6 +401,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); } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 4eee1b163cd2..11eccd7d268c 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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[] = { @@ -278,7 +277,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", @@ -293,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; } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 588c9ad20e83..021e00bcd1be 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 60a03d2d2d0e..75ca6a542174 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -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 @@ -80,7 +79,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 +90,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 +100,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 +182,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) @@ -257,15 +256,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 +308,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; } @@ -325,7 +323,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 +350,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 +389,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 +441,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-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df484a90ae64..fa098d8975ce 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 ee5afd48d3af..b7a5f23351c3 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -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 5d642298f04c..4b69da30665c 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include <linux/kernel.h> @@ -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) @@ -64,7 +62,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 +81,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 +97,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 +125,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-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index 402fd4c781da..86dc055a2e94 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * 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 0509c16dbe75..c5f1aa0feac8 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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); @@ -245,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( @@ -277,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) { @@ -317,7 +325,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 +345,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 +362,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,10 +434,10 @@ 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 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 @@ -426,6 +448,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_MSK | rb_size| (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); @@ -453,10 +476,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); @@ -470,7 +491,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) { @@ -485,49 +506,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 @@ -651,20 +629,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; @@ -676,20 +658,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; @@ -699,22 +670,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); @@ -768,11 +730,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), @@ -784,24 +748,17 @@ 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); -} -#else -static inline void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) -{ + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #endif @@ -995,46 +952,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); -} - - -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) @@ -1157,9 +1074,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 */ - /* FIXME: need to optimze the call: */ - iwl_dbg_report_frame(priv, pkt, header, 1); - +#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); @@ -1168,12 +1086,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 c89365e2ca58..3c803f6922ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -22,11 +22,13 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler <tomas.winkler@intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ -#include <net/mac80211.h> +#include <linux/types.h> #include <linux/etherdevice.h> +#include <net/lib80211.h> +#include <net/mac80211.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -64,54 +66,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 */ - 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, "<hidden>", sizeof("<hidden>")); - 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 * @@ -455,10 +409,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) @@ -550,7 +505,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 +514,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); } @@ -670,23 +625,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 +637,13 @@ 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; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -714,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; @@ -796,20 +736,13 @@ 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)); + 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, 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", - iwl_escape_essid(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"); } @@ -822,23 +755,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 +777,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-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c new file mode 100644 index 000000000000..836c3c80b69e --- /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 <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> + +#include <net/mac80211.h> + +#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 iwl_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 a40a2174df98..b7d7943e476b 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -88,4 +88,5 @@ struct ieee80211_measurement_report { struct ieee80211_basic_report basic[0]; } u; } __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 26f7084d3011..412f66bac1af 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -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 */ @@ -45,7 +43,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 +60,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 +83,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 +90,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); } @@ -104,7 +100,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"); @@ -132,7 +130,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,10 +178,9 @@ 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_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { __le32 sta_flags; u8 mimo_ps_mode; @@ -231,13 +228,12 @@ 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; 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 +269,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 +297,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); @@ -326,7 +319,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"); @@ -415,7 +410,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 +429,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; } @@ -467,6 +461,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; @@ -717,6 +734,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) @@ -809,7 +875,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); @@ -870,7 +936,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 */ @@ -886,15 +952,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); + r = iwl_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); @@ -910,24 +977,35 @@ 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) { + 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_ht_info *cur_ht_config = &conf->ht_conf; - - 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); @@ -945,7 +1023,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) || @@ -980,9 +1057,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; @@ -999,9 +1076,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; @@ -1014,5 +1091,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 221b93e670a6..9bb7cefc1f3c 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -47,9 +47,21 @@ 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); +void iwl_clear_stations_table(struct iwl_priv *priv); 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__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 907a53ebc6e4..b0ee86c62685 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -56,96 +56,132 @@ 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]; + + 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; - /* Host command buffers stay mapped in memory, nothing to clean */ - if (txq->q.id == IWL_CMD_QUEUE_NUM) - return 0; + 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); + /* 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); - /* 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]; - - 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; } @@ -210,7 +246,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,21 +257,15 @@ 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) - 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); @@ -245,6 +275,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) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -340,13 +404,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; @@ -370,26 +434,21 @@ 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 */ 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_VAL); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -468,16 +527,20 @@ 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); + iwl_free_dma_ptr(priv, &priv->kw); + + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); } 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 @@ -488,13 +551,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; @@ -509,17 +576,12 @@ 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++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? @@ -537,8 +599,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; } @@ -547,11 +611,9 @@ 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 */ spin_lock_irqsave(&priv->lock, flags); if (iwl_grab_nic_access(priv)) { @@ -562,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), + 1000); } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -584,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; @@ -647,11 +708,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); @@ -694,14 +755,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; @@ -723,7 +778,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: @@ -767,7 +822,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; @@ -776,10 +831,10 @@ 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; + u8 hdr_len; u8 sta_id; u8 wait_write_ptr = 0; u8 tid = 0; @@ -799,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 @@ -830,10 +883,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; } @@ -856,23 +907,22 @@ 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); /* 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); /* 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)); @@ -912,12 +962,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) @@ -940,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); @@ -950,7 +1002,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; @@ -983,7 +1035,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); } } @@ -1011,7 +1063,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; @@ -1040,7 +1092,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)); @@ -1061,9 +1113,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 @@ -1113,8 +1169,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]); @@ -1138,44 +1195,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++; } } @@ -1201,8 +1248,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]; @@ -1215,7 +1267,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); @@ -1248,15 +1300,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 +1352,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"); @@ -1362,8 +1412,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"); @@ -1414,7 +1464,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; @@ -1436,7 +1486,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); } @@ -1464,10 +1514,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; - DECLARE_MAC_BUF(mac); + int index; + int sta_id; + int tid; /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); @@ -1482,17 +1533,19 @@ 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 %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", @@ -1513,18 +1566,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); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 45a6b0c35695..d64580805d6e 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 <ipw2100-admin@linux.intel.com> + * Intel Linux Wireless <ilw@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -41,6 +41,7 @@ #include <linux/if_arp.h> #include <net/ieee80211_radiotap.h> +#include <net/lib80211.h> #include <net/mac80211.h> #include <asm/div64.h> @@ -64,11 +65,10 @@ 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 */ -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 */ /* @@ -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 "<ilw@linux.intel.com>" #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( @@ -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, "<hidden>", sizeof("<hidden>")); - 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 * @@ -446,7 +407,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 +440,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++; @@ -559,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) { @@ -1063,7 +1023,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 +1083,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, @@ -1443,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 || @@ -1459,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 & IWL_CCK_RATES_MASK; + else + 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) { @@ -1469,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) @@ -1487,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); @@ -1544,10 +1505,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 @@ -1562,29 +1521,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); - - 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); - } + u32 r; - 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)); } @@ -1634,7 +1592,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; @@ -1664,20 +1622,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; @@ -1746,17 +1690,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; } @@ -1828,9 +1776,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; @@ -1846,7 +1791,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, @@ -1870,7 +1815,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}, @@ -1880,7 +1825,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), @@ -2156,11 +2101,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; @@ -2230,13 +2170,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; @@ -2259,7 +2200,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; } @@ -2282,8 +2223,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); @@ -2316,14 +2256,12 @@ 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); - /* 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; @@ -2352,7 +2290,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: @@ -2397,6 +2335,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)) { @@ -2423,10 +2362,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; } @@ -2482,8 +2421,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 +2431,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 +2516,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 +3954,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 +3964,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 @@ -4050,7 +3981,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); } @@ -4373,35 +4304,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", @@ -4502,7 +4404,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; } @@ -4805,7 +4707,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, @@ -4876,17 +4778,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; @@ -5387,25 +5305,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 ver, 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)) { @@ -5417,20 +5351,46 @@ 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); + 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 = 0x%x\n", ver); + /* 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 + @@ -5607,7 +5567,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); @@ -5665,6 +5625,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 @@ -5699,7 +5663,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; } @@ -5709,7 +5673,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++; @@ -5747,7 +5711,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); } @@ -5768,6 +5732,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: @@ -5902,7 +5874,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; } @@ -6046,24 +6018,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) @@ -6101,6 +6055,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); @@ -6111,7 +6066,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; @@ -6201,21 +6156,13 @@ 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)); + 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, 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", - iwl3945_escape_essid(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"); @@ -6223,7 +6170,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; @@ -6333,7 +6280,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__); @@ -6341,9 +6287,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; @@ -6398,10 +6343,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) ? @@ -6439,7 +6381,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) { @@ -6452,7 +6394,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); @@ -6604,7 +6546,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); @@ -6615,13 +6556,14 @@ 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); 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); } @@ -6641,10 +6583,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; @@ -6782,16 +6725,11 @@ 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) { struct iwl3945_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; int rc; if (conf == NULL) @@ -6808,28 +6746,20 @@ 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; } - /* 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; 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: @@ -6842,8 +6772,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); @@ -6889,15 +6819,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); @@ -6910,16 +6831,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; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + 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; + } + + /* 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; } @@ -6940,8 +6888,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); @@ -7010,6 +6956,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"); @@ -7022,12 +6969,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)) { @@ -7043,7 +6984,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); + print_ssid(ssid_buf, ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) @@ -7084,10 +7025,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; } @@ -7143,11 +7082,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); @@ -7219,14 +7153,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; @@ -7292,18 +7218,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; } @@ -7323,7 +7246,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; } @@ -7792,7 +7714,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); /***************************************************************************** * - * driver setup and teardown + * driver setup and tear down * *****************************************************************************/ @@ -7810,7 +7732,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); @@ -7869,7 +7790,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 @@ -7882,7 +7802,10 @@ 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); + + /*********************** + * 1. Allocating HW data + * ********************/ /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ @@ -7907,48 +7830,41 @@ 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 | IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->fw_handles_regulatory = true; + /* 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; @@ -7956,14 +7872,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); @@ -7977,10 +7885,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; @@ -7991,97 +7898,144 @@ 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_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; + } - 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; } - if (iwl3945_param_qos_enable) - priv->qos_data.qos_enable = 1; + /*********************** + * 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; iwl3945_reset_qos(priv); 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: %s\n", print_mac(mac, 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) @@ -8090,12 +8044,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); @@ -8222,7 +8177,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) { @@ -8237,7 +8192,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: @@ -8379,7 +8334,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])"); @@ -8388,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)"); @@ -8396,9 +8351,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); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 92be60415d04..a0e440cd8967 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1,6 +1,10 @@ /* Copyright (C) 2006, Red Hat, Inc. */ +#include <linux/types.h> #include <linux/etherdevice.h> +#include <linux/ieee80211.h> +#include <linux/if_arp.h> +#include <net/lib80211.h> #include "assoc.h" #include "decl.h" @@ -151,18 +155,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_MAC_BUF(mac); + 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_essid(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_essid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ @@ -226,8 +230,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) { @@ -307,6 +311,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); @@ -326,7 +331,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), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->ssid_len); cmd.bsstype = CMD_BSS_TYPE_IBSS; @@ -338,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; @@ -427,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 @@ -450,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) */ ) @@ -463,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) */ ) @@ -477,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 @@ -694,6 +699,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); @@ -705,7 +711,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)); + 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); @@ -752,17 +758,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 +1212,7 @@ 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); + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -1228,13 +1232,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), + print_ssid(ssid, 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 +1361,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 +1482,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 +1508,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 +1773,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_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_JOIN); @@ -1819,9 +1822,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", - escape_essid(bss->ssid, bss->ssid_len), - print_mac(mac, priv->curbssparams.bssid), + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", + print_ssid(ssid, bss->ssid, bss->ssid_len), + priv->curbssparams.bssid, priv->curbssparams.channel); done: diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8265c7d25edc..639dd02d3d31 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,7 +4,7 @@ */ #include <net/iw_handler.h> -#include <net/ieee80211.h> +#include <net/lib80211.h> #include <linux/kfifo.h> #include "host.h" #include "hostcmd.h" @@ -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, @@ -160,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; @@ -170,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); } @@ -1063,6 +1074,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); @@ -1070,7 +1082,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; @@ -1082,7 +1094,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; @@ -1093,7 +1105,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)); + 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/cmd.h b/drivers/net/wireless/libertas/cmd.h index 36be4c9703e0..392e578ca095 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/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 0aa0ce3b2c42..ec4efd7ff3c8 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -5,6 +5,7 @@ #include <linux/mm.h> #include <linux/string.h> #include <net/iw_handler.h> +#include <net/lib80211.h> #include "dev.h" #include "decl.h" @@ -65,7 +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_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -77,17 +78,17 @@ 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' : ' ', 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)); + print_ssid(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 1a8888cceadc..0b84bdca0726 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/defs.h b/drivers/net/wireless/libertas/defs.h index 076a636e8f62..c364e4c01d1b 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) @@ -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/dev.h b/drivers/net/wireless/libertas/dev.h index f6f3753da303..dd682c4cfde8 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -10,7 +10,6 @@ #include <linux/wireless.h> #include <linux/ethtool.h> #include <linux/debugfs.h> -#include <net/ieee80211.h> #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/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 688d60de55cb..61d2f50470c8 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) @@ -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 5004d7679c02..277ff1975bde 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, @@ -237,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/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d9f9a12a739e..e173b1b46c23 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_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b54e2ea8346b..4519d7314f47 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 <linux/kernel.h> #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/netdevice.h> @@ -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; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cafbccb74143..2fc637ad85c7 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; @@ -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); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 73dc8c72402a..3dba83679444 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -12,9 +12,8 @@ #include <linux/kthread.h> #include <linux/kfifo.h> #include <linux/stddef.h> - +#include <linux/ieee80211.h> #include <net/iw_handler.h> -#include <net/ieee80211.h> #include "host.h" #include "decl.h" @@ -223,7 +222,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 +241,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; @@ -258,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); @@ -270,7 +321,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 +332,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 +383,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 +393,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; @@ -376,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, }; @@ -393,7 +452,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 +494,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 +521,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 +538,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 +590,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 +599,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; @@ -588,7 +647,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 +654,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); @@ -674,7 +732,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); } @@ -690,7 +748,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); @@ -1125,7 +1183,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"); @@ -1378,7 +1436,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; @@ -1591,7 +1649,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; } @@ -1632,7 +1690,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); @@ -1647,33 +1705,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, "<hidden>", sizeof("<hidden>")); - 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/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 3309a9c3cfef..d42b7a5a1b3f 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; @@ -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); @@ -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/radiotap.h b/drivers/net/wireless/libertas/radiotap.h index 5d118f40cfbc..f8eb9097ff0a 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 ( \ diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 22c4c6110521..57f6c12cda20 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -4,8 +4,11 @@ * IOCTL handlers as well as command preperation and response routines * for sending scan commands to the firmware. */ +#include <linux/types.h> #include <linux/etherdevice.h> +#include <linux/if_arp.h> #include <asm/unaligned.h> +#include <net/lib80211.h> #include "host.h" #include "decl.h" @@ -52,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); @@ -359,7 +364,7 @@ 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); + DECLARE_SSID_BUF(ssid); #endif lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); @@ -451,9 +456,9 @@ 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, - escape_essid(iter->ssid, iter->ssid_len)); + lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", + i++, iter->bssid, iter->rssi, + print_ssid(ssid, iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif @@ -512,7 +517,7 @@ 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); + 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; @@ -544,7 +549,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) { @@ -588,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", - escape_essid(bss->ssid, bss->ssid_len), + 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, @@ -627,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, @@ -642,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) @@ -659,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 @@ -670,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 */ @@ -741,10 +745,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_essid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); if (!ssid_len) goto out; @@ -939,7 +944,8 @@ out: int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct lbs_private *priv = dev->priv; + DECLARE_SSID_BUF(ssid); + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -968,7 +974,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)); + print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len)); } else { priv->scan_ssid_len = 0; } @@ -1002,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; @@ -1151,7 +1157,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 +1195,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/scan.h b/drivers/net/wireless/libertas/scan.h index 9e07b0464a8e..fab7d5d097fc 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 <net/iw_handler.h> + +#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/tx.c b/drivers/net/wireless/libertas/tx.c index a4972fed2941..dac462641170 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; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index e0c2599da92f..fb7a2d1a2525 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,7 +7,6 @@ #include <linux/if_ether.h> #include <asm/byteorder.h> #include <linux/wireless.h> -#include <net/ieee80211.h> 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 82c3e5a50ea6..c6102e08179e 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -8,7 +8,7 @@ #include <linux/wireless.h> #include <linux/bitops.h> -#include <net/ieee80211.h> +#include <net/lib80211.h> #include <net/iw_handler.h> #include "host.h" @@ -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,12 +1971,13 @@ 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; struct assoc_request * assoc_req; int in_ssid_len = dwrq->length; + DECLARE_SSID_BUF(ssid_buf); lbs_deb_enter(LBS_DEB_WEXT); @@ -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)); + print_ssid(ssid_buf, ssid, ssid_len)); } out: @@ -2039,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); @@ -2057,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); @@ -2101,10 +2102,9 @@ 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; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_WEXT); @@ -2114,7 +2114,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 fdbcf8ba3e8a..3d3914c83b14 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/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index feff945ad856..d1fc305de5fe 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); @@ -590,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 1a019e98dac3..f83d69e813d3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -21,6 +21,7 @@ #include <linux/if_arp.h> #include <linux/rtnetlink.h> #include <linux/etherdevice.h> +#include <linux/debugfs.h> 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 @@ -63,13 +67,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) @@ -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) { @@ -209,9 +247,12 @@ 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) */ + 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; @@ -269,13 +311,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; } @@ -294,6 +332,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__); } @@ -301,10 +340,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 +351,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); } @@ -331,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); @@ -361,10 +399,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__, @@ -409,7 +447,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: %pM\n", + wiphy_name(hw->wiphy), __func__, + conf->bssid); + memcpy(vp->bssid, conf->bssid, ETH_ALEN); + } return 0; } @@ -418,7 +465,46 @@ 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", + 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); + vp->assoc = info->assoc; + vp->aid = 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: op_mode=0x%x\n", + wiphy_name(hw->wiphy), + 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, @@ -434,6 +520,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; } } @@ -445,6 +535,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, @@ -458,6 +559,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, }; @@ -474,6 +576,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); @@ -499,13 +603,131 @@ 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 %pM for aid %d\n", + wiphy_name(data->hw->wiphy), __func__, 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 %pM ps=%d\n", + wiphy_name(data->hw->wiphy), __func__, 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; u8 addr[ETH_ALEN]; struct mac80211_hwsim_data *data; struct ieee80211_hw *hw; - DECLARE_MAC_BUF(mac); if (radios < 1 || radios > 100) return -EINVAL; @@ -553,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 */ @@ -566,19 +789,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); @@ -588,9 +810,15 @@ 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); + + 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); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index a670f36b5f3f..24caec6caf1f 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", @@ -1308,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/Makefile b/drivers/net/wireless/orinoco/Makefile new file mode 100644 index 000000000000..791366e08c50 --- /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/airport.c b/drivers/net/wireless/orinoco/airport.c index ce03a2e865fa..28f1cae48439 100644 --- a/drivers/net/wireless/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); diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/orinoco/hermes.c index bfa375369df3..bfa375369df3 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/orinoco/hermes.c diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/orinoco/hermes.h index 8b13c8fef3dc..8b13c8fef3dc 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/orinoco/hermes.h diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c index d8c626e61a3a..d8c626e61a3a 100644 --- a/drivers/net/wireless/hermes_dld.c +++ b/drivers/net/wireless/orinoco/hermes_dld.c diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h index 6fcb26277999..6fcb26277999 100644 --- a/drivers/net/wireless/hermes_dld.h +++ b/drivers/net/wireless/orinoco/hermes_dld.h diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h index 42eb67dea1df..42eb67dea1df 100644 --- a/drivers/net/wireless/hermes_rid.h +++ b/drivers/net/wireless/orinoco/hermes_rid.h diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c index e0512e49d6d3..bc84e2792f8a 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -84,10 +84,11 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/firmware.h> +#include <linux/suspend.h> #include <linux/if_arp.h> #include <linux/wireless.h> +#include <linux/ieee80211.h> #include <net/iw_handler.h> -#include <net/ieee80211.h> #include <linux/scatterlist.h> #include <linux/crypto.h> @@ -143,7 +144,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 +393,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 +410,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; @@ -431,9 +432,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,13 +488,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) { + 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; + } + } else + fw_entry = priv->cached_fw; hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -535,7 +540,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, hermes_present(hw)); abort: - release_firmware(fw_entry); + /* If we requested the firmware, release it. */ + if (!priv->cached_fw) + release_firmware(fw_entry); free: kfree(pda); @@ -639,34 +646,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); @@ -699,6 +713,45 @@ 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; + 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; + } +} + +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; +} +#else +#define orinoco_cache_fw(priv, ap) +#define orinoco_uncache_fw(priv) +#endif + /********************************************************************/ /* Device methods */ /********************************************************************/ @@ -800,7 +853,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; } } @@ -830,7 +883,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; @@ -1158,7 +1212,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); } @@ -1245,7 +1299,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++; @@ -1280,7 +1334,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; @@ -1374,7 +1427,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++; @@ -1477,12 +1530,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 */ @@ -1530,7 +1582,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) @@ -1699,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; @@ -1722,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; @@ -1752,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; @@ -2301,6 +2352,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); @@ -2926,12 +2982,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", @@ -3056,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 */ /********************************************************************/ @@ -3277,11 +3371,10 @@ 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() */ - priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; + priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; /* Initialize the firmware */ err = hermes_init(hw); @@ -3299,6 +3392,10 @@ 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) priv->do_fw_download = 0; @@ -3348,8 +3445,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, @@ -3535,6 +3632,13 @@ struct net_device netif_carrier_off(dev); priv->last_linkstatus = 0xffff; + 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; } @@ -3546,6 +3650,10 @@ 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); + + unregister_pm_notifier(&priv->pm_notifier); + orinoco_uncache_fw(priv); + priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); @@ -4672,7 +4780,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 @@ -4777,7 +4885,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 @@ -4940,7 +5048,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; @@ -5433,7 +5542,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; @@ -5580,7 +5689,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; @@ -5623,7 +5732,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 */ @@ -5673,7 +5782,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; @@ -5681,7 +5790,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; @@ -5976,7 +6085,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.h b/drivers/net/wireless/orinoco/orinoco.h index 981570bd3b9d..00750c8ba7db 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -10,6 +10,7 @@ #define DRIVER_VERSION "0.15" #include <linux/interrupt.h> +#include <linux/suspend.h> #include <linux/netdevice.h> #include <linux/wireless.h> #include <net/iw_handler.h> @@ -66,6 +67,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 +167,12 @@ 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 during ->resume. */ + const struct firmware *cached_pri_fw; + const struct firmware *cached_fw; + + struct notifier_block pm_notifier; }; #ifdef ORINOCO_DEBUG diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 6fcf2bda7cdf..f127602670ec 100644 --- a/drivers/net/wireless/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; } @@ -308,7 +312,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_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 2fc86596302e..2fc86596302e 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 4ebd638a073e..4ebd638a073e 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h index f4e5e06760c1..f4e5e06760c1 100644 --- a/drivers/net/wireless/orinoco_pci.h +++ b/drivers/net/wireless/orinoco/orinoco_pci.h diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index ef761857bb38..ef761857bb38 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index ede24ec309c0..ede24ec309c0 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 852789ad34b3..b2ca2e39c2cb 100644 --- a/drivers/net/wireless/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; } @@ -383,7 +387,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); @@ -450,10 +454,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; } diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1d0704fe146f..ab79e32f0b27 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 { - P54_CONTROL_TYPE_FILTER_SET = 0, - P54_CONTROL_TYPE_CHANNEL_CHANGE, - P54_CONTROL_TYPE_FREQDONE, +enum p54_control_frame_types { + P54_CONTROL_TYPE_SETUP = 0, + 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,18 +37,44 @@ 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; +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + +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)); +#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; + __le16 cwmax; + __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 @@ -59,49 +85,53 @@ struct p54_control_hdr { #define FW_LM20 0x4c4d3230 struct p54_common { + struct ieee80211_hw *hw; 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 (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u16 seqno; u16 rx_mtu; u8 headroom; u8 tailroom; struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __le16 filter_type; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; 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; 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; + 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; - struct timer_list stats_timer; - struct completion stats_comp; - void *cached_stats; + struct delayed_work work; + struct sk_buff *cached_beacon; 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); +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 827ca0384a4c..82354b974a04 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1,12 +1,15 @@ - /* * Common code for mac80211 Prism54 drivers * * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de> + * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. + * - stlc45xx driver + * 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 @@ -22,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 <flamingice@sourmilk.net>"); MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); @@ -152,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: @@ -182,8 +188,10 @@ 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(bootrec->rx_mtu); + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else priv->rx_mtu = (size_t) 0x620 - priv->tx_hdr_len; @@ -208,18 +216,35 @@ 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 "%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", + wiphy_name(dev->wiphy)); 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; } + 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); @@ -310,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; @@ -320,7 +375,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) int err; u8 *end = (u8 *)eeprom + len; u16 synth = 0; - DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -377,8 +431,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; @@ -409,12 +464,40 @@ 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; 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_REGULATORY_POWER_LIMITS: + 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", + printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", + wiphy_name(dev->wiphy), le16_to_cpu(entry->code)); break; } @@ -424,17 +507,18 @@ 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; } - 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)) { @@ -446,9 +530,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; @@ -469,36 +553,56 @@ 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; } 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) { 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 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; else 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? */ 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; @@ -513,7 +617,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); @@ -521,6 +625,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; } @@ -529,88 +636,197 @@ 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 (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; + 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); + dev_kfree_skb_any(skb); + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + p54_wake_free_queues(dev); +} +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; - 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; 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) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - range = (void *)info->driver_data; - if (range->start_addr == addr) { - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; - int pad = 0; - - 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->driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; + int pad = 0; + range = (void *)info->rate_driver_data; + if (range->start_addr != addr) { last_addr = range->end_addr; - __skb_unlink(entry, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + entry = entry->next; + continue; + } - memset(&info->status, 0, sizeof(info->status)); - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - 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; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = payload->retries - 1; - 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; + 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 - last_addr = range->end_addr; - entry = entry->next; + 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); + + 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); + priv->cached_beacon = NULL; + goto out; + } + + /* + * 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); + + 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->tries; + 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; + } + } + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + 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); + 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_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } 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; 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); } @@ -618,10 +834,14 @@ 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); + 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; @@ -631,19 +851,50 @@ 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) +{ + 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_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: 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: @@ -664,9 +915,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); @@ -682,12 +933,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, - struct p54_control_hdr *data, u32 len) +static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, + struct p54_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; @@ -695,12 +948,37 @@ 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); + 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); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_TIMEOUT)); + + 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; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->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; @@ -715,64 +993,102 @@ 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->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->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 -ENOSPC; } + + 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_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_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_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->tries = hdr->rts_tries = 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) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = NULL; + struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; - size_t eeprom_size = 0x2020, offset = 0, blocksize; + struct sk_buff *skb; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; void *eeprom = NULL; - hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!hdr) - goto free; + 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; 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) + maxblocksize); 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); + 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); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -790,166 +1106,422 @@ 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; } 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); + 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); + return 0; +} + +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; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ + 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; + 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); + 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) +{ + 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: + case NL80211_IFTYPE_MESH_POINT: + 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 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); - struct ieee80211_tx_queue_stats *current_queue; + struct ieee80211_tx_queue_stats *current_queue = NULL; 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; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; + size_t padding, len, tim_len = 0; + int i, j, ridx, ret; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue, crypt_offset = 0; 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)) + queue = 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) + 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; - txhdr = (struct p54_tx_control_allocdata *) - skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + 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->magic1 = cpu_to_le16(0x4010); - else - 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; - - /* 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) { - rate |= 0x10; - cts_rate |= 0x10; + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; + hdr->type = cpu_to_le16(aid); + hdr->rts_tries = 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 (info->flags & IEEE80211_TX_CTL_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) { - 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; + } + + 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++; + } + } + + 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->rts_rate_idx = 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; } - memset(txhdr->rateset, rate, 8); - txhdr->key_type = 0; - txhdr->key_len = 0; - txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->crypt_offset = crypt_offset; + txhdr->hw_queue = queue; + 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; 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; - /* 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); - } + hdr->len = cpu_to_le16(len); /* modifies skb->cb and with it info, so must be last! */ - p54_assign_address(dev, skb, hdr, skb->len); + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) + goto err; + priv->tx(dev, skb); + + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); - priv->tx(dev, hdr, skb->len, 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_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_filter *filter; - size_t data_len; + struct sk_buff *skb; + struct p54_setup_mac *setup; + u16 mode; - hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + - priv->tx_hdr_len, GFP_ATOMIC); - if (!hdr) + 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; - hdr = (void *)hdr + priv->tx_hdr_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); - - priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); - memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); - if (!bssid) - memset(filter->bssid, ~0, ETH_ALEN); - else - memcpy(filter->bssid, bssid, ETH_ALEN); - - filter->rx_antenna = priv->rx_antenna; + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + 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); + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2; /* automatic */ + setup->rx_align = 0; 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); + 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(priv->wakeup_timer); + setup->v1.unalloc0 = cpu_to_le16(0); } 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); + 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(priv->wakeup_timer); + setup->v2.truncate = cpu_to_le16(48896); + 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; + 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); } - - 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); return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_channel *chan; + struct sk_buff *skb; + struct p54_scan *chan; unsigned int i; - size_t data_len; void *entry; + __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); + int band = dev->conf.channel->band; - hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + 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; - 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->flags = cpu_to_le16(0x1); - chan->dwell = cpu_to_le16(0x0); + chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); + memset(chan->padding1, 0, sizeof(chan->padding1)); + 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) @@ -990,61 +1562,50 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) } 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; } 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); + 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 { - 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); + 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); } - - 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); 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 p54_tx_control_led *led; + struct sk_buff *skb; + struct p54_led *led; - hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + 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; - 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_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); return 0; } @@ -1056,88 +1617,144 @@ 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; - - /* all USB V1 adapters need a extra headroom */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*vdcf)); - 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); + struct sk_buff *skb; + struct p54_edcf *edcf; + + 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; + + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + if (priv->use_short_slot) { + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; + } else { + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; + } + /* (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); + return 0; } -static void p54_set_vdcf(struct ieee80211_hw *dev) +static int p54_beacon_tim(struct sk_buff *skb) { - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; + /* + * 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! + */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); + if (skb->len <= sizeof(mgmt)) + return -EINVAL; - vdcf = (struct p54_tx_control_vdcf *) hdr->data; + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return -EINVAL; - if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - vdcf->slottime = 9; - vdcf->magic1 = 0x10; - vdcf->magic2 = 0x00; - } else { - vdcf->slottime = 20; - vdcf->magic1 = 0x0a; - vdcf->magic2 = 0x06; - } + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; - /* (see prism54/isl_oid.h for further details) */ - vdcf->frameburst = cpu_to_le16(0); + if (dtim_len < 3) + return -EINVAL; + + memmove(pos, next, end - next); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); + 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_start(struct ieee80211_hw *dev) +static int p54_beacon_update(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { 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); + struct sk_buff *beacon; + int ret; - if (!priv->cached_vdcf) - return -ENOMEM; + if (priv->cached_beacon) { + p54_tx_cancel(dev, priv->cached_beacon); + /* wait for the last beacon the be freed */ + msleep(10); } - if (!priv->cached_stats) { - priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + 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; - if (!priv->cached_stats) { - kfree(priv->cached_vdcf); - priv->cached_vdcf = NULL; - return -ENOMEM; - } - } + return 0; +} +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; + 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) + 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; + } - p54_init_vdcf(dev); + queue_delayed_work(dev->workqueue, &priv->work, 0); - mod_timer(&priv->stats_timer, jiffies + HZ); +out: + mutex_unlock(&priv->conf_mutex); return err; } @@ -1146,12 +1763,18 @@ static void p54_stop(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct sk_buff *skb; - del_timer(&priv->stats_timer); + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + cancel_delayed_work_sync(&priv->work); + 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->stop(dev); + priv->cached_beacon = NULL; 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, @@ -1159,32 +1782,28 @@ 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: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: priv->mode = conf->type; break; default: + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - - p54_set_filter(dev, 0, NULL); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - p54_set_filter(dev, 1, NULL); - break; - default: - BUG(); /* impossible */ - break; - } - + p54_setup_mac(dev); p54_set_leds(dev, 1, 0, 0); - + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1192,22 +1811,38 @@ 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); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(dev); + mutex_unlock(&priv->conf_mutex); } -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 = (conf->antenna_sel_rx == 0) ? - 2 : conf->antenna_sel_tx - 1; - priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); - p54_set_vdcf(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); + if (ret) + goto out; + } + +out: mutex_unlock(&priv->conf_mutex); return ret; } @@ -1217,13 +1852,36 @@ 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_set_filter(dev, 0, conf->bssid); - p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); - memcpy(priv->bssid, conf->bssid, ETH_ALEN); + if (conf->changed & IEEE80211_IFCC_BSSID) { + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + ret = p54_setup_mac(dev); + if (ret) + goto out; + 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 0; + return ret; } static void p54_configure_filter(struct ieee80211_hw *dev, @@ -1233,94 +1891,78 @@ 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_set_filter(dev, le16_to_cpu(priv->filter_type), - NULL); - else - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - 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); - else - p54_set_filter(dev, le16_to_cpu(priv->filter_type) & - ~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, 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); + int ret; + mutex_lock(&priv->conf_mutex); 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); + ret = p54_set_edcf(dev); } else - return -EINVAL; - - p54_set_vdcf(dev); - - return 0; + ret = -EINVAL; + mutex_unlock(&priv->conf_mutex); + return ret; } static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_xbow_synth *xbow; + struct sk_buff *skb; + struct p54_xbow_synth *xbow; - hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + 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; - 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_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); 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_control_hdr *hdr; - struct p54_statistics *stats; + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + struct ieee80211_hw *dev = priv->hw; + struct sk_buff *skb; - BUG_ON(!priv->cached_stats); + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; - 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); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ + + 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, hdr, sizeof(*hdr) + sizeof(*stats), 0); + priv->tx(dev, skb); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1328,17 +1970,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; } @@ -1352,14 +1984,133 @@ 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_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); + if (priv->fw_var >= 0x500) + p54_scan(dev, P54_SCAN_EXIT, 0); + } + 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); + } + } + +} + +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); + mutex_unlock(&priv->conf_mutex); + return 0; +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, + .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, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -1376,32 +2127,43 @@ 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); - 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; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + 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; - 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; - dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + - sizeof(struct p54_tx_control_allocdata); + /* + * 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_hdr) + 4 + + sizeof(struct p54_tx_data); 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; } @@ -1410,11 +2172,9 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - kfree(priv->cached_stats); 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 2fa994cfcfed..f5729de83fe1 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -7,8 +7,12 @@ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de> * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, 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 @@ -19,9 +23,24 @@ struct bootrec { __le32 code; __le32 len; u32 data[10]; - __le16 rx_mtu; } __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; @@ -30,6 +49,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; @@ -37,8 +63,15 @@ 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; } __attribute__((packed)); #define BR_CODE_MIN 0x80000000 @@ -51,6 +84,31 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF +#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 { @@ -117,6 +175,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 @@ -165,6 +228,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; @@ -172,41 +248,108 @@ 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)); -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_MICHAEL, + 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 = 4 +}; + +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; @@ -214,8 +357,23 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); -struct p54_tx_control_filter { - __le16 filter_type; +/* 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) +#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]; u8 bssid[ETH_ALEN]; u8 rx_antenna; @@ -235,17 +393,29 @@ 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) +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) -struct p54_tx_control_channel { - __le16 flags; +#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; @@ -261,45 +431,35 @@ struct p54_tx_control_channel { 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; + u8 rts_rates[8]; + struct pda_rssi_cal_entry rssi; } 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 0x70 +#define P54_SCAN_V2_LEN 0x7c -struct p54_tx_control_led { +struct p54_led { __le16 mode; __le16 led_temporary; __le16 led_permanent; __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 { @@ -312,14 +472,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_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 88b3cad8b65e..aa367a0ddc49 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); 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 */ @@ -46,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; @@ -72,21 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); - if (err) { - printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886)\n", pci_name(priv->pdev)); - 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; @@ -104,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); @@ -235,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - kfree(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), @@ -306,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 p54_control_hdr *data, - size_t len, 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; @@ -322,28 +315,21 @@ 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); + 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]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = data->req_id; - desc->len = cpu_to_le16(len); + desc->device_addr = ((struct p54_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; - spin_unlock_irqrestore(&priv->lock, flags); 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) - printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); } static void p54p_stop(struct ieee80211_hw *dev) @@ -393,7 +379,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 +391,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; } @@ -481,7 +467,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) { @@ -495,15 +480,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) || @@ -556,6 +540,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; @@ -574,6 +569,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); @@ -587,6 +583,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; } @@ -601,6 +598,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 4a6778070afc..fbb683953fb2 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; diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 75d749bccb0d..c44a200059d2 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); 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) */ @@ -84,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) @@ -103,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; } @@ -113,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); @@ -128,40 +128,56 @@ 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_cb(struct urb *urb) { - usb_free_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; + + skb_pull(skb, priv->common.tx_hdr_len); + if (FREE_AFTER_TX(skb)) + p54_free_skb(dev, skb); } -static void p54u_tx_free_cb(struct urb *urb) +static void p54u_tx_dummy_cb(struct urb *urb) { } + +static void p54u_free_urbs(struct ieee80211_hw *dev) { - kfree(urb->transfer_buffer); - usb_free_urb(urb); + 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), @@ -170,33 +186,32 @@ 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 p54_control_hdr *data, - size_t len, 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; + int err = 0; addr_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!addr_urb) @@ -209,59 +224,85 @@ 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_hdr *)skb->data)->req_id, 4, + p54u_tx_dummy_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, p54u_tx_cb, skb); + + 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_submit_urb(addr_urb, GFP_ATOMIC); - usb_submit_urb(data_urb, GFP_ATOMIC); + 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 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); } 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) { 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_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((__le32 *)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_submit_urb(data_urb, GFP_ATOMIC); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + 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 p54_control_hdr *data, - size_t len, 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; 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) @@ -284,21 +325,47 @@ 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->len = len; + hdr->device_addr = addr; 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), hdr, len + sizeof(*hdr), - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + 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, @@ -375,7 +442,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; } @@ -383,14 +451,18 @@ 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_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; + dev_err(&priv->udev->dev, "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); @@ -441,7 +513,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; } @@ -452,10 +525,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))) { @@ -463,25 +535,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; } @@ -521,15 +595,21 @@ 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, "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; + dev_err(&priv->udev->dev, "(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); @@ -648,8 +728,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; } @@ -682,8 +762,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; } @@ -786,11 +866,11 @@ 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) { - printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); + dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n"); return -ENOMEM; } @@ -842,6 +922,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); @@ -851,7 +932,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; } diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 5b8fe91379c3..54ee738bf2af 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 */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 16e68f4b654a..57a150a22de5 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/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index af2e4f2405f2..9a72b1e3e163 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); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1404a5717520..99ec7d622518 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; @@ -829,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; @@ -2285,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; @@ -2595,7 +2593,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 +2620,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 2b414899dfa0..607ce9f61b54 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -37,11 +37,11 @@ #include <linux/usb.h> #include <linux/usb/cdc.h> #include <linux/wireless.h> +#include <linux/ieee80211.h> #include <linux/if_arp.h> #include <linux/ctype.h> #include <linux/spinlock.h> #include <net/iw_handler.h> -#include <net/ieee80211.h> #include <linux/usb/usbnet.h> #include <linux/usb/rndis_host.h> @@ -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,15 +1273,14 @@ 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; - 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: <not associated>"); @@ -1295,12 +1294,11 @@ 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; - 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); @@ -1318,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; @@ -1399,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) { @@ -1431,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) { @@ -1454,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); @@ -1479,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; @@ -1542,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; @@ -1627,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; @@ -1652,19 +1650,18 @@ 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 - struct ieee80211_info_element *ie; + u8 *ie; char *current_val; int bssid_len, ie_len, i; 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); @@ -1753,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; @@ -1776,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; @@ -1822,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; @@ -1856,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"); @@ -1879,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"); @@ -1892,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; @@ -1913,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"); @@ -1927,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; @@ -1947,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"); @@ -1964,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; @@ -1980,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; @@ -2011,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; @@ -2028,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; @@ -2062,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; @@ -2114,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; @@ -2132,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]; @@ -2157,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; @@ -2287,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/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 95511ac22470..178b313293b4 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/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 08cb9eec16a6..6a977679124d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -49,45 +49,33 @@ * 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) { u32 reg; - /* - * 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; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + 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); + } - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,66 +83,58 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * 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; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + 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); - 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)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - 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); - } - - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; + mutex_lock(&rt2x00dev->csr_mutex); -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); + /* + * 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); + } - 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) @@ -188,43 +168,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), }, @@ -331,7 +302,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); @@ -376,32 +347,94 @@ 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); + + 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 +493,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 +511,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 +528,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); } @@ -628,36 +606,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) @@ -1313,10 +1302,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); @@ -1504,20 +1491,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) { @@ -1576,7 +1549,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, @@ -1589,8 +1561,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, @@ -1604,6 +1576,7 @@ 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, }; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index bbff381ce396..9aefda4ab3c2 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 ef42cc04a2d7..d3bc218ec85c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -49,45 +49,33 @@ * 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) { u32 reg; - /* - * 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; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + 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); + } - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,66 +83,58 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * 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; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + 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); - 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)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - 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); - } - - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; + mutex_lock(&rt2x00dev->csr_mutex); -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); + /* + * 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); + } - 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) @@ -188,43 +168,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), }, @@ -336,7 +307,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); @@ -382,32 +353,114 @@ 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); + + 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 +542,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 +560,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 +577,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); } @@ -723,32 +702,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) @@ -1451,11 +1441,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); @@ -1830,20 +1817,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; @@ -1877,7 +1850,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, @@ -1890,8 +1862,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, @@ -1905,6 +1877,7 @@ 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, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 8c26bef6cf49..e135247f7f89 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 d3bf7bba611a..30028e2422fc 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. @@ -47,7 +54,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, @@ -57,7 +64,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 +75,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 +96,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 +106,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,53 +119,53 @@ 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) { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + 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 = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - 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->usb_cache_mutex); - - return; + 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); -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + } - ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -166,122 +173,107 @@ 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. + * 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 = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the request into the BBP. - */ - 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->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); - *value = 0xff; + mutex_unlock(&rt2x00dev->csr_mutex); } 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->usb_cache_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_lock(&rt2x00dev->csr_mutex); - mutex_unlock(&rt2x00dev->usb_cache_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->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); } #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), }, @@ -338,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) { @@ -380,7 +448,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, @@ -423,57 +491,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_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; + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); - 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 +582,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 +638,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); } @@ -866,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, ®); @@ -1088,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); @@ -1101,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, @@ -1115,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); } @@ -1130,7 +1197,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; @@ -1156,7 +1223,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, @@ -1178,8 +1245,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; @@ -1187,8 +1253,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; } @@ -1227,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 = @@ -1254,6 +1321,33 @@ 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]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + + /* 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, @@ -1261,8 +1355,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)) @@ -1319,10 +1413,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); @@ -1752,6 +1844,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); /* @@ -1771,6 +1867,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, @@ -1781,8 +1878,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, @@ -1793,9 +1889,12 @@ 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, + .config_ant = rt2500usb_config_ant, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 89e5ed24e4f7..4347dfdabcd4 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 /* @@ -445,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 1359a3768404..39ecf3b82ca1 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.3" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -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 @@ -348,13 +358,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]; @@ -433,18 +436,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 +447,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; }; /* @@ -533,10 +533,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. @@ -557,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); @@ -589,16 +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 + const unsigned int changed_flags); }; /* @@ -661,6 +653,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_CRYPTO_COPY_IV, }; /* @@ -738,8 +731,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; @@ -754,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. + * 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 usb_cache_mutex; + struct mutex csr_mutex; /* * Current packet filter configuration for the device. @@ -808,14 +799,15 @@ struct rt2x00_dev { short lna_gain; /* - * USB Max frame size (for rt2500usb & rt73usb). + * Current TX power value. */ - u16 usb_maxpacket; + u16 tx_power; /* - * Current TX power value. + * Current retry values. */ - u16 tx_power; + u8 short_retry; + u8 long_retry; /* * Rssi <-> Dbm offset @@ -938,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. @@ -997,7 +972,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/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 4d5e87b015a0..e66fb316cd61 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,19 +103,39 @@ 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); } +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, - enum antenna rx, enum antenna tx) + struct antenna_setup *ant) { - struct rt2x00lib_conf libconf; + struct antenna_setup *def = &rt2x00dev->default_ant; + struct antenna_setup *active = &rt2x00dev->link.ant.active; - libconf.ant.rx = rx; - libconf.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. + * 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. + */ + ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); + ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); - if (rx == rt2x00dev->link.ant.active.rx && - tx == rt2x00dev->link.ant.active.tx) + if (ant->rx == active->rx && ant->tx == active->tx) return; /* @@ -129,119 +150,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(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 (!conf->antenna_sel_rx && - 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 && - 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; - - /* - * 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)); @@ -251,61 +181,23 @@ config: sizeof(libconf.channel)); } - 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) - 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) - 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; + rt2x00dev->short_retry = conf->short_frame_max_tx_count; + rt2x00dev->long_retry = conf->long_frame_max_tx_count; - 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/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 5a858e5106c4..37ad0d2fb64c 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; @@ -69,6 +92,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); @@ -78,10 +113,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 +130,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 +141,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 +201,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 +219,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/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 5cf4c859e39d..54dd10060bf1 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; @@ -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; \ @@ -587,29 +597,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 +629,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 +638,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 +652,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); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index c4ce895aa1c7..a92104dfee9a 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/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 86840e3585e8..6d92542fcf0d 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. @@ -176,13 +175,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 +200,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 +231,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) @@ -249,11 +250,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) && @@ -419,7 +418,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; @@ -500,7 +499,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. @@ -530,14 +531,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)) @@ -546,7 +551,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)) @@ -570,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); @@ -631,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) { @@ -702,7 +708,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); } @@ -713,31 +719,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, @@ -749,7 +755,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, @@ -761,7 +767,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, @@ -1046,16 +1052,24 @@ 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. */ 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. @@ -1247,7 +1261,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/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index b362a1cf3f8d..68f4e0fc35b9 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,7 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, int retval; led->led_dev.name = name; + led->led_dev.brightness = LED_OFF; retval = led_classdev_register(device, &led->led_dev); if (retval) { @@ -199,7 +184,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 +207,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); } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 797eb619aa0a..03024327767b 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; @@ -94,9 +93,10 @@ 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 int force_config); + struct ieee80211_conf *conf, + const unsigned int changed_flags); /** * DOC: Queue handlers @@ -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); @@ -210,7 +218,10 @@ 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); void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, @@ -222,11 +233,21 @@ 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; } +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) { @@ -242,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/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2c6cc5c374ff..38edee5fe168 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; @@ -79,12 +79,10 @@ 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->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)); @@ -132,8 +130,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; } /* @@ -146,8 +143,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; @@ -335,10 +332,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; - int radio_on; + struct ieee80211_conf *conf = &hw->conf; int status; /* @@ -355,7 +352,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * 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); @@ -369,7 +365,18 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * 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); + + /* + * 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); @@ -480,12 +487,15 @@ 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); 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; @@ -528,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 @@ -625,7 +646,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 @@ -633,7 +654,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); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index adf2876ed8ab..d52b22b82d1f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -32,24 +32,46 @@ #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) { + 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 +98,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; /* @@ -222,8 +242,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; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 80bf97c03e2d..9c0a4d77bc1b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -44,21 +44,10 @@ #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, - const unsigned long offset, + const unsigned int offset, u32 *value) { *value = readl(rt2x00dev->csr.base + offset); @@ -66,14 +55,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,13 +70,31 @@ 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); } /** + * 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/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 451d410ecdae..eaec6bd93ed5 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 @@ -230,8 +211,8 @@ 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; + if (txdesc->retry_limit >= rt2x00dev->long_retry) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -312,8 +293,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++; @@ -371,13 +352,15 @@ 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; + return -ENOBUFS; if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, @@ -399,13 +382,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. */ - skbdesc = get_skb_frame_desc(entry->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(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 @@ -414,19 +402,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { - rt2x00crypto_tx_remove_iv(skb, iv_len); + 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 - * 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)) @@ -556,7 +546,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); @@ -575,40 +565,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/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 9dbf04f0f04c..282937153408 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -104,22 +104,25 @@ 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. - * @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. */ 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; - __le32 eiv; + __le32 iv[2]; dma_addr_t skb_dma; @@ -143,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, }; /** @@ -163,8 +170,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 { @@ -177,8 +183,7 @@ struct rxdone_entry_desc { u8 cipher; u8 cipher_status; - __le32 iv; - __le32 eiv; + __le32 iv[2]; __le32 icv; }; @@ -375,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; @@ -396,6 +403,9 @@ struct data_queue { unsigned short data_size; unsigned short desc_size; + + unsigned short usb_endpoint; + unsigned short usb_maxpacket; }; /** @@ -439,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. @@ -448,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 b73a7e0aeed4..83df312ac56f 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,12 +148,34 @@ 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; } 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. */ @@ -212,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); @@ -351,28 +373,96 @@ 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; + int pipe; - 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) { + 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); - set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + 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_rxentry); +EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2x00usb_assign_endpoint(struct data_queue *queue, + struct usb_endpoint_descriptor *ep_desc) { - entry->flags = 0; + 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; } -EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) @@ -445,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) { @@ -534,12 +631,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); - if (!rt2x00dev->usb_maxpacket) - rt2x00dev->usb_maxpacket = 1; retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 3b4a67417f95..2bd4ac855f52 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 */ @@ -286,10 +422,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 a461620b489f..987e89009f74 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -55,45 +55,36 @@ 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) { u32 reg; - /* - * 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; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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); + 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); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + } - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -101,66 +92,58 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * 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; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + 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); - 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)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - 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_lock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; + /* + * 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); -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); + 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); } #ifdef CONFIG_RT2X00_LIB_LEDS @@ -175,25 +158,27 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); + mutex_lock(&rt2x00dev->csr_mutex); - 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; + /* + * 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); + + 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); } - 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); + mutex_unlock(&rt2x00dev->csr_mutex); - 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); } #endif /* CONFIG_RT2X00_LIB_LEDS */ @@ -228,43 +213,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), }, @@ -643,95 +619,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); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - 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); + 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 +805,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 +853,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 +974,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); } @@ -1263,33 +1246,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); + + 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 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) @@ -1784,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); @@ -1934,7 +1928,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; @@ -1955,9 +1949,12 @@ 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]); + 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 @@ -2175,10 +2172,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); @@ -2630,20 +2625,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) { @@ -2726,7 +2707,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, @@ -2741,8 +2721,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, @@ -2758,6 +2738,7 @@ 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, }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 8ec1451308cc..65fe3332364a 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 934f8e03c5aa..d638a8a59370 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, @@ -55,113 +55,35 @@ 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) -{ - __le32 reg; - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), 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(u32), 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(u32), 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(u32), 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 u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - 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; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __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) { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + 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->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_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); + + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + } - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -169,123 +91,95 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + 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); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + rt2x00usb_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->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; + mutex_unlock(&rt2x00dev->csr_mutex); } 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->usb_cache_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->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + mutex_lock(&rt2x00dev->csr_mutex); /* - * 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); - mutex_unlock(&rt2x00dev->usb_cache_mutex); -} - -#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); -} + 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); + + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } -static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); + mutex_unlock(&rt2x00dev->csr_mutex); } +#ifdef CONFIG_RT2X00_LIB_DEBUGFS static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt73usb_read_csr, - .write = rt73usb_write_csr, + .read = rt2x00usb_register_read, + .write = rt2x00usb_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), }, @@ -341,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; } @@ -387,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) @@ -424,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); } /* @@ -456,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; } @@ -486,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; } @@ -517,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)); /* @@ -532,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 @@ -557,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; @@ -588,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, @@ -606,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, @@ -625,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) { @@ -642,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)); } @@ -651,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)); } } @@ -661,95 +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); -} - -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); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - 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); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - 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); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); - 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); + 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); + rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -869,8 +694,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; @@ -895,14 +720,14 @@ static void rt73usb_config_antenna(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)) @@ -912,33 +737,111 @@ 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); + 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); + rt2x00usb_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, ®); + 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, @@ -948,16 +851,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); } @@ -972,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); } @@ -1138,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); @@ -1180,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 */ @@ -1195,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); @@ -1209,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 @@ -1287,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; } @@ -1394,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) @@ -1415,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); } @@ -1433,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. @@ -1444,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; @@ -1526,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); @@ -1584,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. @@ -1606,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; @@ -1615,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; } @@ -1635,14 +1536,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); } } @@ -1685,7 +1586,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); @@ -1717,9 +1618,12 @@ 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]); + 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 @@ -1781,10 +1685,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); @@ -1883,7 +1785,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)) { @@ -2211,20 +2113,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) { @@ -2251,33 +2139,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; } @@ -2295,9 +2183,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; @@ -2317,7 +2205,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, @@ -2331,8 +2218,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, @@ -2348,6 +2234,7 @@ 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, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 868386c457f6..46e1405eb0e2 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 /* diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile new file mode 100644 index 000000000000..c113b3e69046 --- /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/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h index 8721282a8185..8721282a8185 100644 --- a/drivers/net/wireless/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180.h diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index df7e78ee8a88..5f887fb137a9 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/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) @@ -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); @@ -719,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, @@ -759,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, }; @@ -806,7 +819,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) { @@ -855,7 +867,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); @@ -1002,8 +1014,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/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c index 947ee55f18b2..947ee55f18b2 100644 --- a/drivers/net/wireless/rtl8180_grf5101.c +++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h index 76647111bcff..76647111bcff 100644 --- a/drivers/net/wireless/rtl8180_grf5101.h +++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c index 6c825fd7f3b6..6c825fd7f3b6 100644 --- a/drivers/net/wireless/rtl8180_max2820.c +++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h index 61cf6d1e7d57..61cf6d1e7d57 100644 --- a/drivers/net/wireless/rtl8180_max2820.h +++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.h diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c index cd22781728a9..4d2be0d9672b 100644 --- a/drivers/net/wireless/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/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h index 310013a2d726..310013a2d726 100644 --- a/drivers/net/wireless/rtl8180_rtl8225.h +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c index cea4e0ccb92d..cea4e0ccb92d 100644 --- a/drivers/net/wireless/rtl8180_sa2400.c +++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h index a4aaa0d413f1..a4aaa0d413f1 100644 --- a/drivers/net/wireless/rtl8180_sa2400.h +++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index e82bb4d289e8..3b1e1c2aad26 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -99,8 +99,8 @@ struct rtl8187_priv { struct ieee80211_supported_band band; struct usb_device *udev; u32 rx_conf; + struct usb_anchor anchored; u16 txpwr_base; - u16 seqno; u8 asic_rev; u8 is_rtl8187b; enum { @@ -112,6 +112,12 @@ struct rtl8187_priv { u8 signal; u8 quality; u8 noise; + u8 slot_time; + u8 aifsn[4]; + struct { + __le64 buf; + 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/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 69eb0132593b..00ce3ef39abe 100644 --- a/drivers/net/wireless/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 <andreamrl@tiscali.it>, et al. * + * The driver was extended to the RTL8187B in 2008 by: + * Herton Ronaldo Krzesinski <herton@mandriva.com.br> + * Hin-Tak Leung <htl10@users.sourceforge.net> + * Larry Finger <Larry.Finger@lwfinger.net> + * * 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 <flamingice@sourmilk.net>"); MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>"); +MODULE_AUTHOR("Herton Ronaldo Krzesinski <herton@mandriva.com.br>"); +MODULE_AUTHOR("Hin-Tak Leung <htl10@users.sourceforge.net>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); @@ -91,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, @@ -128,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, @@ -155,30 +164,45 @@ 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) { 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]); skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); - memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(hw, skb); + ieee80211_tx_info_clear_status(info); + + 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) { 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; @@ -189,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; @@ -198,12 +222,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; } @@ -214,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.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); buf = hdr; ep = 2; @@ -232,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.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); @@ -244,32 +268,20 @@ 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; + 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); + 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; + return rc; } static void rtl8187_rx_cb(struct urb *urb) @@ -282,50 +294,35 @@ 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)) { - 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; + /* 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)); @@ -343,18 +340,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; @@ -366,7 +363,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; } @@ -378,24 +374,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, @@ -406,10 +410,129 @@ 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) +{ + 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)) + 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 + 1; + + ieee80211_tx_status_irqsafe(hw, skb); + } + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); + } + + 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; + + 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_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) + usb_unanchor_urb(entry); + usb_free_urb(entry); + + return ret; } static int rtl8187_cmd_reset(struct ieee80211_hw *dev) @@ -687,7 +810,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); @@ -721,6 +844,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; } @@ -736,6 +866,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 | @@ -757,6 +890,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; } @@ -809,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; @@ -828,11 +961,10 @@ 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; - usb_kill_urb(info->urb); - kfree_skb(skb); - } + while ((skb = skb_dequeue(&priv->b_tx_status.queue))) + dev_kfree_skb_any(skb); + + usb_kill_anchored_urbs(&priv->anchored); mutex_unlock(&priv->conf_mutex); } @@ -876,9 +1008,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); @@ -889,27 +1022,10 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) */ 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); - 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); @@ -944,6 +1060,89 @@ 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; + u16 ack_timeout; + int queue; + + if (use_short_slot) { + priv->slot_time = 0x9; + difs = 0x1c; + eifs = 0x53; + } else { + priv->slot_time = 0x14; + difs = 0x32; + eifs = 0x5b; + } + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->SLOT, priv->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)); + + 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); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + } + } +} + +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, @@ -976,6 +1175,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, @@ -984,7 +1219,9 @@ 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, + .conf_tx = rtl8187_conf_tx }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1029,7 +1266,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) { @@ -1065,6 +1301,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; @@ -1180,16 +1417,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*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; - } + if (priv->is_rtl8187b) + printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); + /* + * 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) @@ -1211,9 +1445,10 @@ 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 %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/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index 1bae89903410..4e75e8e7fa90 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/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) @@ -333,21 +331,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); @@ -375,91 +373,89 @@ 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]); 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_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + 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); @@ -629,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, @@ -687,22 +683,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); @@ -736,94 +733,92 @@ 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]); 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_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + 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); @@ -835,40 +830,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); - msleep(3000); + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x2, 0xC4D); msleep(1); - msleep(2000); + 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); @@ -885,24 +878,10 @@ 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); - 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) @@ -910,7 +889,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); diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h index 20c5b6ead0f6..20c5b6ead0f6 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.h +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 3538b15211b1..34a5555cc19c 100644 --- a/drivers/net/wireless/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 */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 417e9e675fac..dd0de3a9ed4e 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 || @@ -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. */ @@ -1997,7 +1996,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); } } @@ -2261,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 @@ -2455,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); /* @@ -2490,7 +2487,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; @@ -2498,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; @@ -2598,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. @@ -2669,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. @@ -2695,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. diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index e939a73ff794..832679396b6c 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() */ @@ -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); @@ -927,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 */ @@ -1107,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:"); @@ -1153,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; @@ -1195,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); @@ -1220,14 +1213,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 @@ -1256,11 +1248,8 @@ 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; -#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 +1266,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) @@ -1369,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; } /*------------------------------------------------------------------*/ @@ -1382,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", @@ -1716,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; @@ -1753,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; @@ -1812,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; @@ -1844,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; @@ -1874,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; @@ -1920,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; @@ -1956,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; @@ -1987,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; @@ -2057,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; @@ -2104,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; @@ -2179,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; @@ -2211,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; @@ -2239,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) { @@ -2282,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; @@ -2386,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; @@ -2461,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; @@ -2537,7 +2526,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; @@ -2556,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; @@ -2738,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; @@ -2869,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]; @@ -2937,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; @@ -3108,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; @@ -3200,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; @@ -3301,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 */ @@ -3433,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; @@ -3565,15 +3553,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 } @@ -3613,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; @@ -3650,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 @@ -3751,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 @@ -3894,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; @@ -3974,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 @@ -4029,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 @@ -4128,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; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e124b1d6267a..de717f8ffd61 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) @@ -2243,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; @@ -2892,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; @@ -3647,12 +3632,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.h b/drivers/net/wireless/wl3501.h index 65ceb088f700..59bb3a55ab48 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -2,7 +2,7 @@ #define __WL3501_H__ #include <linux/spinlock.h> -#include <net/ieee80211.h> +#include <linux/ieee80211.h> /* 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/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 68789c6e1ce9..c99a1b6b948f 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); } @@ -1014,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); @@ -1965,7 +1963,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 +2021,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/zd1201.c b/drivers/net/wireless/zd1201.c index b16ec6e5f0e3..b45c27d42fd8 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -17,11 +17,11 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/wireless.h> +#include <linux/ieee80211.h> #include <net/iw_handler.h> #include <linux/string.h> #include <linux/if_arp.h> #include <linux/firmware.h> -#include <net/ieee80211.h> #include "zd1201.h" static struct usb_device_id zd1201_table[] = { @@ -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); @@ -346,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; @@ -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); @@ -745,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) @@ -783,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; @@ -833,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; @@ -848,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) @@ -865,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; @@ -899,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); } @@ -914,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; @@ -939,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; @@ -955,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; @@ -1017,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; @@ -1093,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)) { @@ -1121,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; @@ -1213,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; @@ -1228,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; @@ -1249,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; @@ -1282,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; @@ -1315,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; @@ -1335,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; @@ -1352,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; @@ -1373,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; @@ -1402,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; @@ -1459,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; @@ -1492,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; @@ -1531,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; @@ -1618,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; @@ -1629,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; @@ -1648,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) @@ -1664,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) @@ -1679,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; @@ -1731,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; @@ -1738,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; @@ -1775,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; @@ -1810,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; } @@ -1846,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); @@ -1865,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 diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index e0ac58b8ff1f..f1519143f8a6 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 cac732f4047f..9caa96a13586 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: @@ -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(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))) { __skb_unlink(skb, q); - tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); + tx_status(hw, skb, stats->signal, 1); goto out; } } @@ -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); } @@ -852,14 +854,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; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a3ccd8c1c716..04c139666965 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -909,7 +909,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); |