From 38e3b0d86eaa0bf90a74677b6d6c442ec66daa0c Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 16 Jul 2008 11:44:18 -0300 Subject: rtl818x: merge tx/rx descriptor flags Tx/Rx descriptor flags are common between rtl818x devices, only with additions for newer chips, thus use same flags in the code. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8180.h | 31 ------------------------------- drivers/net/wireless/rtl8180_dev.c | 34 +++++++++++++++++----------------- drivers/net/wireless/rtl8187.h | 6 ------ drivers/net/wireless/rtl8187_dev.c | 10 +++++----- drivers/net/wireless/rtl818x.h | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h index 082a11f93be..8721282a818 100644 --- a/drivers/net/wireless/rtl8180.h +++ b/drivers/net/wireless/rtl8180.h @@ -24,20 +24,6 @@ #define ANAPARAM_PWR1_SHIFT 20 #define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) -enum rtl8180_tx_desc_flags { - RTL8180_TX_DESC_FLAG_NO_ENC = (1 << 15), - RTL8180_TX_DESC_FLAG_TX_OK = (1 << 15), - RTL8180_TX_DESC_FLAG_SPLCP = (1 << 16), - RTL8180_TX_DESC_FLAG_RX_UNDER = (1 << 16), - RTL8180_TX_DESC_FLAG_MOREFRAG = (1 << 17), - RTL8180_TX_DESC_FLAG_CTS = (1 << 18), - RTL8180_TX_DESC_FLAG_RTS = (1 << 23), - RTL8180_TX_DESC_FLAG_LS = (1 << 28), - RTL8180_TX_DESC_FLAG_FS = (1 << 29), - RTL8180_TX_DESC_FLAG_DMA = (1 << 30), - RTL8180_TX_DESC_FLAG_OWN = (1 << 31) -}; - struct rtl8180_tx_desc { __le32 flags; __le16 rts_duration; @@ -52,23 +38,6 @@ struct rtl8180_tx_desc { u32 reserved[2]; } __attribute__ ((packed)); -enum rtl8180_rx_desc_flags { - RTL8180_RX_DESC_FLAG_ICV_ERR = (1 << 12), - RTL8180_RX_DESC_FLAG_CRC32_ERR = (1 << 13), - RTL8180_RX_DESC_FLAG_PM = (1 << 14), - RTL8180_RX_DESC_FLAG_RX_ERR = (1 << 15), - RTL8180_RX_DESC_FLAG_BCAST = (1 << 16), - RTL8180_RX_DESC_FLAG_PAM = (1 << 17), - RTL8180_RX_DESC_FLAG_MCAST = (1 << 18), - RTL8180_RX_DESC_FLAG_SPLCP = (1 << 25), - RTL8180_RX_DESC_FLAG_FOF = (1 << 26), - RTL8180_RX_DESC_FLAG_DMA_FAIL = (1 << 27), - RTL8180_RX_DESC_FLAG_LS = (1 << 28), - RTL8180_RX_DESC_FLAG_FS = (1 << 29), - RTL8180_RX_DESC_FLAG_EOR = (1 << 30), - RTL8180_RX_DESC_FLAG_OWN = (1 << 31) -}; - struct rtl8180_rx_desc { __le32 flags; __le32 flags2; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index b7172a12c05..861c76a65d6 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -110,12 +110,12 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; u32 flags = le32_to_cpu(entry->flags); - if (flags & RTL8180_RX_DESC_FLAG_OWN) + if (flags & RTL818X_RX_DESC_FLAG_OWN) return; - if (unlikely(flags & (RTL8180_RX_DESC_FLAG_DMA_FAIL | - RTL8180_RX_DESC_FLAG_FOF | - RTL8180_RX_DESC_FLAG_RX_ERR))) + if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | + RTL818X_RX_DESC_FLAG_FOF | + RTL818X_RX_DESC_FLAG_RX_ERR))) goto done; else { u32 flags2 = le32_to_cpu(entry->flags2); @@ -140,7 +140,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(entry->tsft); rx_status.flag |= RX_FLAG_TSFT; - if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR) + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); @@ -154,10 +154,10 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) done: entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); - entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN | + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE); if (priv->rx_idx == 31) - entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR); + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); priv->rx_idx = (priv->rx_idx + 1) % 32; } } @@ -173,7 +173,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) struct ieee80211_tx_info *info; u32 flags = le32_to_cpu(entry->flags); - if (flags & RTL8180_TX_DESC_FLAG_OWN) + if (flags & RTL818X_TX_DESC_FLAG_OWN) return; ring->idx = (ring->idx + 1) % ring->entries; @@ -185,7 +185,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) memset(&info->status, 0, sizeof(info->status)); if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (flags & RTL8180_TX_DESC_FLAG_TX_OK) + if (flags & RTL818X_TX_DESC_FLAG_TX_OK) info->flags |= IEEE80211_TX_STAT_ACK; else info->status.excessive_retries = 1; @@ -252,20 +252,20 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | - RTL8180_TX_DESC_FLAG_LS | + tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | + RTL818X_TX_DESC_FLAG_LS | (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | skb->len; if (priv->r8185) - tx_flags |= RTL8180_TX_DESC_FLAG_DMA | - RTL8180_TX_DESC_FLAG_NO_ENC; + tx_flags |= RTL818X_TX_DESC_FLAG_DMA | + RTL818X_TX_DESC_FLAG_NO_ENC; if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { - tx_flags |= RTL8180_TX_DESC_FLAG_RTS; + 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) { - tx_flags |= RTL8180_TX_DESC_FLAG_CTS; + tx_flags |= RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -446,10 +446,10 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); entry->rx_buf = cpu_to_le32(*mapping); - entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN | + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE); } - entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR); + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); return 0; } diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 5a9515c9996..e82bb4d289e 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -58,12 +58,6 @@ struct rtl8187b_rx_hdr { /* {rtl8187,rtl8187b}_tx_info is in skb */ -/* Tx flags are common between rtl8187 and rtl8187b */ -#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) -#define RTL8187_TX_FLAG_MORE_FRAG (1 << 17) -#define RTL8187_TX_FLAG_CTS (1 << 18) -#define RTL8187_TX_FLAG_RTS (1 << 23) - struct rtl8187_tx_hdr { __le32 flags; __le16 rts_duration; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index ca5deb6244e..060a2650535 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -187,18 +187,18 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) } flags = skb->len; - flags |= RTL8187_TX_FLAG_NO_ENCRYPT; + flags |= RTL818X_TX_DESC_FLAG_NO_ENC; flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) - flags |= RTL8187_TX_FLAG_MORE_FRAG; + flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { - flags |= RTL8187_TX_FLAG_RTS; + 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) { - flags |= RTL8187_TX_FLAG_CTS; + flags |= RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -354,7 +354,7 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; rx_status.flag |= RX_FLAG_TSFT; - if (flags & (1 << 13)) + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 00900fe16fc..3538b15211b 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -193,4 +193,39 @@ struct rtl818x_rf_ops { void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); }; +/* Tx/Rx flags are common between RTL818X chips */ + +enum rtl818x_tx_desc_flags { + RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), + RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), + RTL818X_TX_DESC_FLAG_SPLCP = (1 << 16), + RTL818X_TX_DESC_FLAG_RX_UNDER = (1 << 16), + RTL818X_TX_DESC_FLAG_MOREFRAG = (1 << 17), + RTL818X_TX_DESC_FLAG_CTS = (1 << 18), + RTL818X_TX_DESC_FLAG_RTS = (1 << 23), + RTL818X_TX_DESC_FLAG_LS = (1 << 28), + RTL818X_TX_DESC_FLAG_FS = (1 << 29), + RTL818X_TX_DESC_FLAG_DMA = (1 << 30), + RTL818X_TX_DESC_FLAG_OWN = (1 << 31) +}; + +enum rtl818x_rx_desc_flags { + RTL818X_RX_DESC_FLAG_ICV_ERR = (1 << 12), + RTL818X_RX_DESC_FLAG_CRC32_ERR = (1 << 13), + RTL818X_RX_DESC_FLAG_PM = (1 << 14), + RTL818X_RX_DESC_FLAG_RX_ERR = (1 << 15), + RTL818X_RX_DESC_FLAG_BCAST = (1 << 16), + RTL818X_RX_DESC_FLAG_PAM = (1 << 17), + RTL818X_RX_DESC_FLAG_MCAST = (1 << 18), + RTL818X_RX_DESC_FLAG_QOS = (1 << 19), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_TRSW = (1 << 24), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_SPLCP = (1 << 25), + RTL818X_RX_DESC_FLAG_FOF = (1 << 26), + RTL818X_RX_DESC_FLAG_DMA_FAIL = (1 << 27), + RTL818X_RX_DESC_FLAG_LS = (1 << 28), + RTL818X_RX_DESC_FLAG_FS = (1 << 29), + RTL818X_RX_DESC_FLAG_EOR = (1 << 30), + RTL818X_RX_DESC_FLAG_OWN = (1 << 31) +}; + #endif /* RTL818X_H */ -- cgit v1.2.3 From 1556c0f22df77800d2e99342ce354a4ce94c5a0f Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Mon, 21 Jul 2008 11:02:46 -0700 Subject: libertas: support boot commands to write persistent firmware and bootloader Add locking and non-locking versions of if_usb_prog_firmware to support programming firmware after and before driver bring-up respectively. Add more suitable error codes for firmware programming process. Add capability checks for persistent features before attempting to use them. Based on patches from Brajesh Dave and Priyank Singh. Signed-off-by: Brian Cavagnolo Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 21 +++++-- drivers/net/wireless/libertas/defs.h | 6 +- drivers/net/wireless/libertas/if_usb.c | 112 +++++++++++++++++++++++++++------ drivers/net/wireless/libertas/if_usb.h | 5 ++ 4 files changed, 119 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 75427e61898..af5fd709887 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1033,9 +1033,9 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, return ret; } -int lbs_mesh_config_send(struct lbs_private *priv, - struct cmd_ds_mesh_config *cmd, - uint16_t action, uint16_t type) +static int __lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) { int ret; @@ -1054,6 +1054,19 @@ int lbs_mesh_config_send(struct lbs_private *priv, return ret; } +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + + if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG)) + return -EOPNOTSUPP; + + ret = __lbs_mesh_config_send(priv, cmd, action, type); + return ret; +} + /* This function is the CMD_MESH_CONFIG legacy function. It only handles the * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG * are all handled by preparing a struct cmd_ds_mesh_config and passing it to @@ -1095,7 +1108,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) action, priv->mesh_tlv, chan, escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); - return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); + return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 12e687550bc..4b2428ac222 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -243,6 +243,9 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define CMD_F_HOSTCMD (1 << 0) #define FW_CAPINFO_WPA (1 << 0) +#define FW_CAPINFO_FIRMWARE_UPGRADE (1 << 13) +#define FW_CAPINFO_BOOT2_UPGRADE (1<<14) +#define FW_CAPINFO_PERSISTENT_CONFIG (1<<15) #define KEY_LEN_WPA_AES 16 #define KEY_LEN_WPA_TKIP 32 @@ -316,7 +319,8 @@ enum PS_STATE { enum DNLD_STATE { DNLD_RES_RECEIVED, DNLD_DATA_SENT, - DNLD_CMD_SENT + DNLD_CMD_SENT, + DNLD_BOOTCMD_SENT, }; /** LBS_MEDIA_STATE */ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 632c291404a..b5013ce31b9 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -39,7 +39,10 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_prog_firmware(struct if_usb_card *cardp); +static int __if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd); +static int if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd); static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, uint8_t *payload, uint16_t nb); static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, @@ -66,10 +69,10 @@ static void if_usb_write_bulk_callback(struct urb *urb) lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n", urb->actual_length); - /* Used for both firmware TX and regular TX. priv isn't - * valid at firmware load time. + /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not + * passed up to the lbs level. */ - if (priv) + if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT) lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ @@ -231,7 +234,7 @@ static int if_usb_probe(struct usb_interface *intf, } /* Upload firmware */ - if (if_usb_prog_firmware(cardp)) { + if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) { lbs_deb_usbd(&udev->dev, "FW upload failed\n"); goto err_prog_firmware; } @@ -510,7 +513,7 @@ static void if_usb_receive_fwload(struct urb *urb) if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); - cardp->bootcmdresp = 1; + cardp->bootcmdresp = BOOT_CMD_RESP_OK; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); return; @@ -526,7 +529,9 @@ static void if_usb_receive_fwload(struct urb *urb) lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", le32_to_cpu(bootcmdresp.magic)); } - } else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) { + } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) && + (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) && + (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) { lbs_pr_info("boot cmd response cmd_tag error (%d)\n", bootcmdresp.cmd); } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { @@ -564,8 +569,8 @@ static void if_usb_receive_fwload(struct urb *urb) kfree_skb(skb); - /* reschedule timer for 200ms hence */ - mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); + /* Give device 5s to either write firmware to its RAM or eeprom */ + mod_timer(&cardp->fw_timeout, jiffies + (HZ*5)); if (cardp->fwfinalblk) { cardp->fwdnldover = 1; @@ -809,7 +814,54 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) } -static int if_usb_prog_firmware(struct if_usb_card *cardp) +/** +* @brief This function programs the firmware subject to cmd +* +* @param cardp the if_usb_card descriptor +* fwname firmware or boot2 image file name +* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, +* or BOOT_CMD_UPDATE_BOOT2. +* @return 0 or error code +*/ +static int if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd) +{ + struct lbs_private *priv = cardp->priv; + unsigned long flags, caps; + int ret; + + caps = priv->fwcapinfo; + if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) || + ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE))) + return -EOPNOTSUPP; + + /* Ensure main thread is idle. */ + spin_lock_irqsave(&priv->driver_lock, flags); + while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + if (wait_event_interruptible(priv->waitq, + (priv->cur_cmd == NULL && + priv->dnld_sent == DNLD_RES_RECEIVED))) { + return -ERESTARTSYS; + } + spin_lock_irqsave(&priv->driver_lock, flags); + } + priv->dnld_sent = DNLD_BOOTCMD_SENT; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + ret = __if_usb_prog_firmware(cardp, fwname, cmd); + + spin_lock_irqsave(&priv->driver_lock, flags); + priv->dnld_sent = DNLD_RES_RECEIVED; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + wake_up_interruptible(&priv->waitq); + + return ret; +} + +static int __if_usb_prog_firmware(struct if_usb_card *cardp, + const char *fwname, int cmd) { int i = 0; static int reset_count = 10; @@ -817,20 +869,32 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp) lbs_deb_enter(LBS_DEB_USB); - if ((ret = request_firmware(&cardp->fw, lbs_fw_name, - &cardp->udev->dev)) < 0) { + ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev); + if (ret < 0) { lbs_pr_err("request_firmware() failed with %#x\n", ret); - lbs_pr_err("firmware %s not found\n", lbs_fw_name); + lbs_pr_err("firmware %s not found\n", fwname); goto done; } - if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) + if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) { + ret = -EINVAL; goto release_fw; + } + + /* Cancel any pending usb business */ + usb_kill_urb(cardp->rx_urb); + usb_kill_urb(cardp->tx_urb); + + cardp->fwlastblksent = 0; + cardp->fwdnldover = 0; + cardp->totalbytes = 0; + cardp->fwfinalblk = 0; + cardp->bootcmdresp = 0; restart: if (if_usb_submit_rx_urb_fwload(cardp) < 0) { lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); - ret = -1; + ret = -EIO; goto release_fw; } @@ -838,8 +902,7 @@ restart: do { int j = 0; i++; - /* Issue Boot command = 1, Boot from Download-FW */ - if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); + if_usb_issue_boot_command(cardp, cmd); /* wait for command response */ do { j++; @@ -847,12 +910,21 @@ restart: } while (cardp->bootcmdresp == 0 && j < 10); } while (cardp->bootcmdresp == 0 && i < 5); - if (cardp->bootcmdresp <= 0) { + if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) { + /* Return to normal operation */ + ret = -EOPNOTSUPP; + usb_kill_urb(cardp->rx_urb); + usb_kill_urb(cardp->tx_urb); + if (if_usb_submit_rx_urb(cardp) < 0) + ret = -EIO; + goto release_fw; + } else if (cardp->bootcmdresp <= 0) { if (--reset_count >= 0) { if_usb_reset_device(cardp); goto restart; } - return -1; + ret = -EIO; + goto release_fw; } i = 0; @@ -882,7 +954,7 @@ restart: } lbs_pr_info("FW download failure, time = %d ms\n", i * 100); - ret = -1; + ret = -EIO; goto release_fw; } diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 5771a83a43f..5ba0aee0eb2 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -30,6 +30,7 @@ struct bootcmd #define BOOT_CMD_RESP_OK 0x0001 #define BOOT_CMD_RESP_FAIL 0x0000 +#define BOOT_CMD_RESP_NOT_SUPPORTED 0x0002 struct bootcmdresp { @@ -50,6 +51,10 @@ struct if_usb_card { uint8_t ep_in; uint8_t ep_out; + /* bootcmdresp == 0 means command is pending + * bootcmdresp < 0 means error + * bootcmdresp > 0 is a BOOT_CMD_RESP_* from firmware + */ int8_t bootcmdresp; int ep_in_size; -- cgit v1.2.3 From 1ff41eb0d9a937957d481d4f058a91230851ae17 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Mon, 21 Jul 2008 11:03:16 -0700 Subject: libertas: add sysfs hooks to update boot2 and persistent firmware To use these features, copy the boot2 and firmware images to /lib/firmware and: echo > /sys/class/net/ethX/lbs_flash_boot2 echo > /sys/class/net/ethX/lbs_flash_fw Signed-off-by: Brian Cavagnolo Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_usb.c | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index b5013ce31b9..7b02d612b07 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -51,6 +51,62 @@ static void if_usb_free(struct if_usb_card *cardp); static int if_usb_submit_rx_urb(struct if_usb_card *cardp); static int if_usb_reset_device(struct if_usb_card *cardp); +/* sysfs hooks */ + +/** + * Set function to write firmware to device's persistent memory + */ +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 if_usb_card *cardp = priv->card; + char fwname[FIRMWARE_NAME_MAX]; + int ret; + + sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */ + ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW); + if (ret == 0) + return count; + + return ret; +} + +/** + * lbs_flash_fw attribute to be exported per ethX interface through sysfs + * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to + * the device's persistent memory: + * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_fw + */ +static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); + +/** + * Set function to write firmware to device's persistent memory + */ +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 if_usb_card *cardp = priv->card; + char fwname[FIRMWARE_NAME_MAX]; + int ret; + + sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */ + ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2); + if (ret == 0) + return count; + + return ret; +} + +/** + * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs + * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware + * to the device's persistent memory: + * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_boot2 + */ +static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); + /** * @brief call back function to handle the status of the URB * @param urb pointer to urb structure @@ -263,6 +319,12 @@ static int if_usb_probe(struct usb_interface *intf, usb_get_dev(udev); usb_set_intfdata(intf, cardp); + if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw)) + lbs_pr_err("cannot register lbs_flash_fw attribute\n"); + + if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) + lbs_pr_err("cannot register lbs_flash_boot2 attribute\n"); + return 0; err_start_card: @@ -288,6 +350,9 @@ static void if_usb_disconnect(struct usb_interface *intf) lbs_deb_enter(LBS_DEB_MAIN); + device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2); + device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_fw); + cardp->surprise_removed = 1; if (priv) { -- cgit v1.2.3 From 8e5f3d0aaa3ae5305613553f869727b0361cd472 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 17 Jul 2008 13:12:24 -0700 Subject: ath5k: add Mesh Point support This enables draft-802.11s Mesh Point operation. For that we need mesh beaconing. Tested with AR5212/AR5213 PCI card against Zydas and b43 mesh nodes. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 4 +++- drivers/net/wireless/ath5k/hw.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index b20a45aa868..8bc9b92ad6a 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1432,7 +1432,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc) ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); if (ret) return ret; - if (sc->opmode == IEEE80211_IF_TYPE_AP) { + if (sc->opmode == IEEE80211_IF_TYPE_AP || + sc->opmode == IEEE80211_IF_TYPE_MESH_POINT) { /* * Always burst out beacon and CAB traffic * (aifs = cwmin = cwmax = 0) @@ -2932,6 +2933,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (sc->opmode != IEEE80211_IF_TYPE_STA) rfilt |= AR5K_RX_FILTER_PROBEREQ; if (sc->opmode != IEEE80211_IF_TYPE_AP && + sc->opmode != IEEE80211_IF_TYPE_MESH_POINT && test_bit(ATH_STAT_PROMISC, sc->status)) rfilt |= AR5K_RX_FILTER_PROM; if (sc->opmode == IEEE80211_IF_TYPE_STA || diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index ad1a5b422c8..b335d332305 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -2387,6 +2387,7 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) break; case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_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); -- cgit v1.2.3 From b9740c2396851178b99c03c2260a0adfe7f52e36 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 23 Jul 2008 19:17:01 +0200 Subject: rt2x00mac: In error case stop netdev queue, free skb and return NETDEV_TX_OK It is not allowed to use NETDEV_TX_BUSY in tx path anymore. Signed-off-by: Daniel Wagner Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 43 +++++++++++++++------------------ 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index d0650738863..4b9fde903cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -37,6 +37,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_info *rts_info; struct sk_buff *skb; int size; + int retval = 0; if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) size = sizeof(struct ieee80211_cts); @@ -44,9 +45,9 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, size = sizeof(struct ieee80211_rts); skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); - if (!skb) { + if (unlikely(!skb)) { WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); - return NETDEV_TX_BUSY; + return -ENOMEM; } skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); @@ -82,13 +83,13 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, frag_skb->data, size, tx_info, (struct ieee80211_rts *)(skb->data)); - if (rt2x00queue_write_tx_frame(queue, skb)) { + retval = rt2x00queue_write_tx_frame(queue, skb); + if (retval) { dev_kfree_skb_any(skb); WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); - return NETDEV_TX_BUSY; } - return NETDEV_TX_OK; + return retval; } int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) @@ -106,11 +107,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * Note that we can only stop the TX queues inside the TX path * due to possible race conditions in mac80211. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { - ieee80211_stop_queues(hw); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + goto exit_fail; /* * Determine which queue to put packet on. @@ -141,26 +139,25 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | IEEE80211_TX_CTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { - if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, qid); - return NETDEV_TX_BUSY; - } - - if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, qid); - return NETDEV_TX_BUSY; - } - } + if (rt2x00queue_available(queue) <= 1) + goto exit_fail; - if (rt2x00queue_write_tx_frame(queue, skb)) { - ieee80211_stop_queue(rt2x00dev->hw, qid); - return NETDEV_TX_BUSY; + if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) + goto exit_fail; } + if (rt2x00queue_write_tx_frame(queue, skb)) + goto exit_fail; + if (rt2x00queue_threshold(queue)) ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_OK; + + exit_fail: + ieee80211_stop_queue(rt2x00dev->hw, qid); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(rt2x00mac_tx); -- cgit v1.2.3 From d7dc100374df0c21afd8a198336ecd7999697159 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 23 Jul 2008 13:17:35 +0200 Subject: Ath5k: unify resets There were 3 code copy and pastes of reset. Unify the resets and place in separate function. Signed-off-by: Jiri Slaby Cc: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 124 +++++++++++++------------------------- 1 file changed, 42 insertions(+), 82 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 8bc9b92ad6a..e8564095b2f 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -162,7 +162,8 @@ static struct pci_driver ath5k_pci_driver = { * Prototypes - MAC 802.11 stack related functions */ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -static int ath5k_reset(struct ieee80211_hw *hw); +static int ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel); +static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); static int ath5k_add_interface(struct ieee80211_hw *hw, @@ -977,9 +978,6 @@ ath5k_getchannels(struct ieee80211_hw *hw) static int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) { - struct ath5k_hw *ah = sc->ah; - int ret; - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", sc->curchan->center_freq, chan->center_freq); @@ -995,41 +993,7 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ - ath5k_hw_set_intr(ah, 0); /* disable interrupts */ - ath5k_txq_cleanup(sc); /* clear pending tx frames */ - ath5k_rx_stop(sc); /* turn off frame recv */ - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); - if (ret) { - ATH5K_ERR(sc, "%s: unable to reset channel " - "(%u Mhz)\n", __func__, chan->center_freq); - return ret; - } - - ath5k_hw_set_txpower_limit(sc->ah, 0); - - /* - * Re-enable rx framework. - */ - ret = ath5k_rx_start(sc); - if (ret) { - ATH5K_ERR(sc, "%s: unable to restart recv logic\n", - __func__); - return ret; - } - - /* - * Change channels and update the h/w rate map - * if we're switching; e.g. 11a to 11b/g. - * - * XXX needed? - */ -/* ath5k_chan_change(sc, chan); */ - - ath5k_beacon_config(sc); - /* - * Re-enable interrupts. - */ - ath5k_hw_set_intr(ah, sc->imask); + return ath5k_reset(sc, true, true); } return 0; @@ -2217,36 +2181,13 @@ ath5k_init(struct ath5k_softc *sc) */ sc->curchan = sc->hw->conf.channel; sc->curband = &sc->sbands[sc->curchan->band]; - ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false); - if (ret) { - ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret); - goto done; - } - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath5k_hw_set_txpower_limit(sc->ah, 0); - - /* - * Setup the hardware after reset: the key cache - * is filled as needed and 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. - */ - ret = ath5k_rx_start(sc); - if (ret) - goto done; - - /* - * Enable interrupts. - */ sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; + ret = ath5k_reset(sc, false, false); + if (ret) + goto done; - ath5k_hw_set_intr(sc->ah, sc->imask); /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(sc->ah, false); @@ -2446,7 +2387,7 @@ ath5k_tasklet_reset(unsigned long data) { struct ath5k_softc *sc = (void *)data; - ath5k_reset(sc->hw); + ath5k_reset_wake(sc); } /* @@ -2469,7 +2410,7 @@ ath5k_calibrate(unsigned long data) * to load new gain values. */ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset(sc->hw); + ath5k_reset_wake(sc); } if (ath5k_hw_phy_calibrate(ah, sc->curchan)) ATH5K_ERR(sc, "calibration of channel %u failed\n", @@ -2670,48 +2611,67 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } static int -ath5k_reset(struct ieee80211_hw *hw) +ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel) { - struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; int ret; ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); - ath5k_hw_set_intr(ah, 0); - ath5k_txq_cleanup(sc); - ath5k_rx_stop(sc); - + if (stop) { + ath5k_hw_set_intr(ah, 0); + ath5k_txq_cleanup(sc); + ath5k_rx_stop(sc); + } ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); - if (unlikely(ret)) { + if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); goto err; } + + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ ath5k_hw_set_txpower_limit(sc->ah, 0); ret = ath5k_rx_start(sc); - if (unlikely(ret)) { + if (ret) { ATH5K_ERR(sc, "can't start recv logic\n"); goto err; } + /* - * We may be doing a reset in response to an ioctl - * that changes the channel so update any state that - * might change as a result. + * Change channels and update the h/w rate map if we're switching; + * e.g. 11a to 11b/g. + * + * We may be doing a reset in response to an ioctl that changes the + * channel so update any state that might change as a result. * * XXX needed? */ /* ath5k_chan_change(sc, c); */ - ath5k_beacon_config(sc); - /* intrs are started by ath5k_beacon_config */ - ieee80211_wake_queues(hw); + ath5k_beacon_config(sc); + /* intrs are enabled by ath5k_beacon_config */ return 0; err: return ret; } +static int +ath5k_reset_wake(struct ath5k_softc *sc) +{ + int ret; + + ret = ath5k_reset(sc, true, true); + if (!ret) + ieee80211_wake_queues(sc->hw); + + return ret; +} + static int ath5k_start(struct ieee80211_hw *hw) { return ath5k_init(hw->priv); @@ -2820,7 +2780,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&sc->lock); - return ath5k_reset(hw); + return ath5k_reset_wake(sc); unlock: mutex_unlock(&sc->lock); return ret; -- cgit v1.2.3 From 63266a653589e1a237527479f10212ea77ce7844 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 30 Jul 2008 17:12:58 +0200 Subject: ath5k: rates cleanup cleanup the rates structures used by ath5k. instead of separate driver and mac80211 rate structures we now setup a static ieee80211_rate array and use it directly. no conversion between two different rate structures has to be done any more. a lot of unused and confusing junk was deleted. renamed ath5k_getchannels into ath5k_setup_bands because this is what it does. rewrote it to copy the bitrates correctly for each band. this is necessary for running different hardware with the same driver (e.g. 5211 and 5212 based cards). add special handling of rates for AR5211 chipsets: it uses different rate codes for CCK rates (which are actually like the other chips but with a 0xF mask). setup a hardware code to rate index reverse mapping table for getting the rate index of received frames. the rates for control frames which have to be set in ath5k_hw_write_rate_duration are now in one single array. drivers/net/wireless/ath5k/ath5k.h: Changes-licensed-under: ISC drivers/net/wireless/ath5k/base.c: Changes-licensed-under: 3-Clause-BSD drivers/net/wireless/ath5k/base.h: Changes-licensed-under: 3-Clause-BSD drivers/net/wireless/ath5k/hw.c: Changes-licensed-under: ISC Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 162 +++++------------------ drivers/net/wireless/ath5k/base.c | 254 +++++++++++++++++-------------------- drivers/net/wireless/ath5k/base.h | 8 +- drivers/net/wireless/ath5k/hw.c | 76 +++-------- 4 files changed, 171 insertions(+), 329 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 9102eea3c8b..c1b49787366 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -271,11 +271,6 @@ enum ath5k_driver_mode { /* adding this flag to rate_code enables short preamble, see ar5212_reg.h */ #define AR5K_SET_SHORT_PREAMBLE 0x04 -#define HAS_SHPREAMBLE(_ix) \ - (rt->rates[_ix].modulation == IEEE80211_RATE_SHORT_PREAMBLE) -#define SHPREAMBLE_FLAG(_ix) \ - (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) - /****************\ TX DEFINITIONS @@ -568,152 +563,61 @@ struct ath5k_athchan_2ghz { u16 a2_athchan; }; + /* * Rate definitions - * TODO: Clean them up or move them on mac80211 -most of these infos are - * used by the rate control algorytm on MadWiFi. */ -/* Max number of rates on the rate table and what it seems - * Atheros hardware supports */ -#define AR5K_MAX_RATES 32 - /** - * struct ath5k_rate - rate structure - * @valid: is this a valid rate for rate control (remove) - * @modulation: respective mac80211 modulation - * @rate_kbps: rate in kbit/s - * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on - * &struct ath5k_rx_status.rs_rate and on TX on - * &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports - * up to 32 rates, indexed by 1-32. This means we really only need - * 6 bits for the rate_code. - * @dot11_rate: respective IEEE-802.11 rate value - * @control_rate: index of rate assumed to be used to send control frames. - * This can be used to set override the value on the rate duration - * registers. This is only useful if we can override in the harware at - * what rate we want to send control frames at. Note that IEEE-802.11 - * Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we - * should send ACK/CTS, if we change this value we can be breaking - * the spec. + * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32. * - * This structure is used to get the RX rate or set the TX rate on the + * The rate code is used to get the RX rate or set the TX rate on the * hardware descriptors. It is also used for internal modulation control * and settings. * - * On RX after the &struct ath5k_desc is parsed by the appropriate - * ah_proc_rx_desc() the respective hardware rate value is set in - * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in - * &struct ath5k_tx_status.ts_rate which is later used to setup the - * &struct ath5k_desc correctly. This is the hardware rate map we are - * aware of: + * This is the hardware rate map we are aware of: * - * rate_code 1 2 3 4 5 6 7 8 + * rate_code 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 * rate_kbps 3000 1000 ? ? ? 2000 500 48000 * - * rate_code 9 10 11 12 13 14 15 16 + * rate_code 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 * rate_kbps 24000 12000 6000 54000 36000 18000 9000 ? * * rate_code 17 18 19 20 21 22 23 24 * rate_kbps ? ? ? ? ? ? ? 11000 * * rate_code 25 26 27 28 29 30 31 32 - * rate_kbps 5500 2000 1000 ? ? ? ? ? + * rate_kbps 5500 2000 1000 11000S 5500S 2000S ? ? * + * "S" indicates CCK rates with short preamble. + * + * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the + * lowest 4 bits, so they are the same as below with a 0xF mask. + * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M). + * We handle this in ath5k_setup_bands(). */ -struct ath5k_rate { - u8 valid; - u32 modulation; - u16 rate_kbps; - u8 rate_code; - u8 dot11_rate; - u8 control_rate; -}; - -/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */ -struct ath5k_rate_table { - u16 rate_count; - u8 rate_code_to_index[AR5K_MAX_RATES]; /* Back-mapping */ - struct ath5k_rate rates[AR5K_MAX_RATES]; -}; - -/* - * Rate tables... - * TODO: CLEAN THIS !!! - */ -#define AR5K_RATES_11A { 8, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ - 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, 0, 6000, 11, 140, 0 }, \ - { 1, 0, 9000, 15, 18, 0 }, \ - { 1, 0, 12000, 10, 152, 2 }, \ - { 1, 0, 18000, 14, 36, 2 }, \ - { 1, 0, 24000, 9, 176, 4 }, \ - { 1, 0, 36000, 13, 72, 4 }, \ - { 1, 0, 48000, 8, 96, 4 }, \ - { 1, 0, 54000, 12, 108, 4 } } \ -} - -#define AR5K_RATES_11B { 4, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ - 3, 2, 1, 0, 255, 255, 255, 255 }, { \ - { 1, 0, 1000, 27, 130, 0 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 132, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 139, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 150, 1 } } \ -} - -#define AR5K_RATES_11G { 12, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \ - 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ - 3, 2, 1, 0, 255, 255, 255, 255 }, { \ - { 1, 0, 1000, 27, 2, 0 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 2000, 26, 4, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 5500, 25, 11, 1 }, \ - { 1, IEEE80211_RATE_SHORT_PREAMBLE, 11000, 24, 22, 1 }, \ - { 0, 0, 6000, 11, 12, 4 }, \ - { 0, 0, 9000, 15, 18, 4 }, \ - { 1, 0, 12000, 10, 24, 6 }, \ - { 1, 0, 18000, 14, 36, 6 }, \ - { 1, 0, 24000, 9, 48, 8 }, \ - { 1, 0, 36000, 13, 72, 8 }, \ - { 1, 0, 48000, 8, 96, 8 }, \ - { 1, 0, 54000, 12, 108, 8 } } \ -} +#define AR5K_MAX_RATES 32 -#define AR5K_RATES_TURBO { 8, { \ - 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ - 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, MODULATION_TURBO, 6000, 11, 140, 0 }, \ - { 1, MODULATION_TURBO, 9000, 15, 18, 0 }, \ - { 1, MODULATION_TURBO, 12000, 10, 152, 2 }, \ - { 1, MODULATION_TURBO, 18000, 14, 36, 2 }, \ - { 1, MODULATION_TURBO, 24000, 9, 176, 4 }, \ - { 1, MODULATION_TURBO, 36000, 13, 72, 4 }, \ - { 1, MODULATION_TURBO, 48000, 8, 96, 4 }, \ - { 1, MODULATION_TURBO, 54000, 12, 108, 4 } } \ -} +/* B */ +#define ATH5K_RATE_CODE_1M 0x1B +#define ATH5K_RATE_CODE_2M 0x1A +#define ATH5K_RATE_CODE_5_5M 0x19 +#define ATH5K_RATE_CODE_11M 0x18 +/* A and G */ +#define ATH5K_RATE_CODE_6M 0x0B +#define ATH5K_RATE_CODE_9M 0x0F +#define ATH5K_RATE_CODE_12M 0x0A +#define ATH5K_RATE_CODE_18M 0x0E +#define ATH5K_RATE_CODE_24M 0x09 +#define ATH5K_RATE_CODE_36M 0x0D +#define ATH5K_RATE_CODE_48M 0x08 +#define ATH5K_RATE_CODE_54M 0x0C +/* XR */ +#define ATH5K_RATE_CODE_XR_500K 0x07 +#define ATH5K_RATE_CODE_XR_1M 0x02 +#define ATH5K_RATE_CODE_XR_2M 0x06 +#define ATH5K_RATE_CODE_XR_3M 0x01 -#define AR5K_RATES_XR { 12, { \ - 255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4, \ - 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ - 255, 255, 255, 255, 255, 255, 255, 255 }, { \ - { 1, MODULATION_XR, 500, 7, 129, 0 }, \ - { 1, MODULATION_XR, 1000, 2, 139, 1 }, \ - { 1, MODULATION_XR, 2000, 6, 150, 2 }, \ - { 1, MODULATION_XR, 3000, 1, 150, 3 }, \ - { 1, 0, 6000, 11, 140, 4 }, \ - { 1, 0, 9000, 15, 18, 4 }, \ - { 1, 0, 12000, 10, 152, 6 }, \ - { 1, 0, 18000, 14, 36, 6 }, \ - { 1, 0, 24000, 9, 176, 8 }, \ - { 1, 0, 36000, 13, 72, 8 }, \ - { 1, 0, 48000, 8, 96, 8 }, \ - { 1, 0, 54000, 12, 108, 8 } } \ -} /* * Crypto definitions diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index e8564095b2f..114520258b7 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -132,6 +132,48 @@ static struct ath5k_srev_name srev_names[] = { { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, }; +static struct ieee80211_rate ath5k_rates[] = { + { .bitrate = 10, + .hw_value = ATH5K_RATE_CODE_1M, }, + { .bitrate = 20, + .hw_value = ATH5K_RATE_CODE_2M, + .hw_value_short = ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = ATH5K_RATE_CODE_5_5M, + .hw_value_short = ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = ATH5K_RATE_CODE_11M, + .hw_value_short = ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = ATH5K_RATE_CODE_6M, + .flags = 0 }, + { .bitrate = 90, + .hw_value = ATH5K_RATE_CODE_9M, + .flags = 0 }, + { .bitrate = 120, + .hw_value = ATH5K_RATE_CODE_12M, + .flags = 0 }, + { .bitrate = 180, + .hw_value = ATH5K_RATE_CODE_18M, + .flags = 0 }, + { .bitrate = 240, + .hw_value = ATH5K_RATE_CODE_24M, + .flags = 0 }, + { .bitrate = 360, + .hw_value = ATH5K_RATE_CODE_36M, + .flags = 0 }, + { .bitrate = 480, + .hw_value = ATH5K_RATE_CODE_48M, + .flags = 0 }, + { .bitrate = 540, + .hw_value = ATH5K_RATE_CODE_54M, + .flags = 0 }, + /* XR missing */ +}; + /* * Prototypes - PCI stack related functions */ @@ -219,20 +261,16 @@ static void ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw); /* Channel/mode setup */ static inline short ath5k_ieee2mhz(short chan); -static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates, - const struct ath5k_rate_table *rt, - unsigned int max); static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, unsigned int mode, unsigned int max); -static int ath5k_getchannels(struct ieee80211_hw *hw); +static int ath5k_setup_bands(struct ieee80211_hw *hw); static int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan); static void ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode); static void ath5k_mode_setup(struct ath5k_softc *sc); -static void ath5k_set_total_hw_rates(struct ath5k_softc *sc); /* Descriptor setup */ static int ath5k_desc_alloc(struct ath5k_softc *sc, @@ -646,7 +684,6 @@ err_no_irq: #endif /* CONFIG_PM */ - /***********************\ * Driver Initialization * \***********************/ @@ -688,15 +725,12 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) * on settings like the phy mode and regulatory * domain restrictions. */ - ret = ath5k_getchannels(hw); + ret = ath5k_setup_bands(hw); if (ret) { ATH5K_ERR(sc, "can't get channels\n"); goto err; } - /* Set *_rates so we can map hw rate index */ - ath5k_set_total_hw_rates(sc); - /* NB: setup here so ath5k_rate_update is happy */ if (test_bit(AR5K_MODE_11A, ah->ah_modes)) ath5k_setcurmode(sc, AR5K_MODE_11A); @@ -812,27 +846,6 @@ ath5k_ieee2mhz(short chan) return 2212 + chan * 20; } -static unsigned int -ath5k_copy_rates(struct ieee80211_rate *rates, - const struct ath5k_rate_table *rt, - unsigned int max) -{ - unsigned int i, count; - - if (rt == NULL) - return 0; - - for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) { - rates[count].bitrate = rt->rates[i].rate_kbps / 100; - rates[count].hw_value = rt->rates[i].rate_code; - rates[count].flags = rt->rates[i].modulation; - count++; - max--; - } - - return count; -} - static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, @@ -895,74 +908,97 @@ ath5k_copy_channels(struct ath5k_hw *ah, return count; } +static void +ath5k_setup_rate_idx(struct ath5k_softc *sc, struct ieee80211_supported_band *b) +{ + u8 i; + + for (i = 0; i < AR5K_MAX_RATES; i++) + sc->rate_idx[b->band][i] = -1; + + for (i = 0; i < b->n_bitrates; i++) { + sc->rate_idx[b->band][b->bitrates[i].hw_value] = i; + if (b->bitrates[i].hw_value_short) + sc->rate_idx[b->band][b->bitrates[i].hw_value_short] = i; + } +} + static int -ath5k_getchannels(struct ieee80211_hw *hw) +ath5k_setup_bands(struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - struct ieee80211_supported_band *sbands = sc->sbands; - const struct ath5k_rate_table *hw_rates; - unsigned int max_r, max_c, count_r, count_c; - int mode2g = AR5K_MODE_11G; + struct ieee80211_supported_band *sband; + int max_c, count_c = 0; + int i; BUILD_BUG_ON(ARRAY_SIZE(sc->sbands) < IEEE80211_NUM_BANDS); - - max_r = ARRAY_SIZE(sc->rates); max_c = ARRAY_SIZE(sc->channels); - count_r = count_c = 0; /* 2GHz band */ - if (!test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { - mode2g = AR5K_MODE_11B; - if (!test_bit(AR5K_MODE_11B, - sc->ah->ah_capabilities.cap_mode)) - mode2g = -1; - } + sband = &sc->sbands[IEEE80211_BAND_2GHZ]; + sband->band = IEEE80211_BAND_2GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_2GHZ][0]; - if (mode2g > 0) { - struct ieee80211_supported_band *sband = - &sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(AR5K_MODE_11G, sc->ah->ah_capabilities.cap_mode)) { + /* G mode */ + memcpy(sband->bitrates, &ath5k_rates[0], + sizeof(struct ieee80211_rate) * 12); + sband->n_bitrates = 12; - sband->bitrates = sc->rates; sband->channels = sc->channels; - - sband->band = IEEE80211_BAND_2GHZ; sband->n_channels = ath5k_copy_channels(ah, sband->channels, - mode2g, max_c); - - hw_rates = ath5k_hw_get_rate_table(ah, mode2g); - sband->n_bitrates = ath5k_copy_rates(sband->bitrates, - hw_rates, max_r); + AR5K_MODE_11G, max_c); + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; count_c = sband->n_channels; - count_r = sband->n_bitrates; + max_c -= count_c; + } else if (test_bit(AR5K_MODE_11B, sc->ah->ah_capabilities.cap_mode)) { + /* B mode */ + memcpy(sband->bitrates, &ath5k_rates[0], + sizeof(struct ieee80211_rate) * 4); + sband->n_bitrates = 4; + + /* 5211 only supports B rates and uses 4bit rate codes + * (e.g normally we have 0x1B for 1M, but on 5211 we have 0x0B) + * fix them up here: + */ + if (ah->ah_version == AR5K_AR5211) { + for (i = 0; i < 4; i++) { + sband->bitrates[i].hw_value = + sband->bitrates[i].hw_value & 0xF; + sband->bitrates[i].hw_value_short = + sband->bitrates[i].hw_value_short & 0xF; + } + } - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + sband->channels = sc->channels; + sband->n_channels = ath5k_copy_channels(ah, sband->channels, + AR5K_MODE_11B, max_c); - max_r -= count_r; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + count_c = sband->n_channels; max_c -= count_c; - } + ath5k_setup_rate_idx(sc, sband); - /* 5GHz band */ - + /* 5GHz band, A mode */ if (test_bit(AR5K_MODE_11A, sc->ah->ah_capabilities.cap_mode)) { - struct ieee80211_supported_band *sband = - &sbands[IEEE80211_BAND_5GHZ]; + sband = &sc->sbands[IEEE80211_BAND_5GHZ]; + sband->band = IEEE80211_BAND_5GHZ; + sband->bitrates = &sc->rates[IEEE80211_BAND_5GHZ][0]; - sband->bitrates = &sc->rates[count_r]; - sband->channels = &sc->channels[count_c]; + memcpy(sband->bitrates, &ath5k_rates[4], + sizeof(struct ieee80211_rate) * 8); + sband->n_bitrates = 8; - sband->band = IEEE80211_BAND_5GHZ; + sband->channels = &sc->channels[count_c]; sband->n_channels = ath5k_copy_channels(ah, sband->channels, AR5K_MODE_11A, max_c); - hw_rates = ath5k_hw_get_rate_table(ah, AR5K_MODE_11A); - sband->n_bitrates = ath5k_copy_rates(sband->bitrates, - hw_rates, max_r); - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; } + ath5k_setup_rate_idx(sc, sband); ath5k_debug_dump_bands(sc); @@ -1031,75 +1067,13 @@ ath5k_mode_setup(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); } -/* - * Match the hw provided rate index (through descriptors) - * to an index for sc->curband->bitrates, so it can be used - * by the stack. - * - * This one is a little bit tricky but i think i'm right - * about this... - * - * We have 4 rate tables in the following order: - * XR (4 rates) - * 802.11a (8 rates) - * 802.11b (4 rates) - * 802.11g (12 rates) - * that make the hw rate table. - * - * Lets take a 5211 for example that supports a and b modes only. - * First comes the 802.11a table and then 802.11b (total 12 rates). - * When hw returns eg. 11 it points to the last 802.11b rate (11Mbit), - * if it returns 2 it points to the second 802.11a rate etc. - * - * Same goes for 5212 who has xr/a/b/g support (total 28 rates). - * First comes the XR table, then 802.11a, 802.11b and 802.11g. - * When hw returns eg. 27 it points to the last 802.11g rate (54Mbits) etc - */ -static void -ath5k_set_total_hw_rates(struct ath5k_softc *sc) { - - struct ath5k_hw *ah = sc->ah; - - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - sc->a_rates = 8; - - if (test_bit(AR5K_MODE_11B, ah->ah_modes)) - sc->b_rates = 4; - - if (test_bit(AR5K_MODE_11G, ah->ah_modes)) - sc->g_rates = 12; - - /* XXX: Need to see what what happens when - xr disable bits in eeprom are set */ - if (ah->ah_version >= AR5K_AR5212) - sc->xr_rates = 4; - -} - static inline int -ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) { - - int mac80211_rix; - - if(sc->curband->band == IEEE80211_BAND_2GHZ) { - /* We setup a g ratetable for both b/g modes */ - mac80211_rix = - hw_rix - sc->b_rates - sc->a_rates - sc->xr_rates; - } else { - mac80211_rix = hw_rix - sc->xr_rates; - } - - /* Something went wrong, fallback to basic rate for this band */ - if ((mac80211_rix >= sc->curband->n_bitrates) || - (mac80211_rix <= 0 )) - mac80211_rix = 1; - - return mac80211_rix; +ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) +{ + WARN_ON(hw_rix < 0 || hw_rix > AR5K_MAX_RATES); + return sc->rate_idx[sc->curband->band][hw_rix]; } - - - /***************\ * Buffers setup * \***************/ @@ -1788,6 +1762,12 @@ accept: rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); +#if 0 /* add rxs.flag SHORTPRE once it is in mac80211 */ + if (rs.rs_rate >= ATH5K_RATE_CODE_2M && + rs.rs_rate <= ATH5K_RATE_CODE_11M && + rs.rs_rate & AR5K_SET_SHORT_PREAMBLE) + rxs.flag |= RX_FLAG_SHORTPRE; +#endif ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index d7e03e6b827..248e32eb6cb 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -111,17 +111,13 @@ struct ath5k_softc { struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels[ATH_CHAN_MAX]; - struct ieee80211_rate rates[AR5K_MAX_RATES * IEEE80211_NUM_BANDS]; + struct ieee80211_rate rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; + u8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; enum ieee80211_if_types opmode; struct ath5k_hw *ah; /* Atheros HW */ struct ieee80211_supported_band *curband; - u8 a_rates; - u8 b_rates; - u8 g_rates; - u8 xr_rates; - #ifdef CONFIG_ATH5K_DEBUG struct ath5k_dbg_info debug; /* debug info */ #endif /* CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index b335d332305..b987aa1e0f7 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -31,13 +31,6 @@ #include "base.h" #include "debug.h" -/* Rate tables */ -static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A; -static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B; -static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G; -static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO; -static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR; - /* Prototypes */ static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); @@ -520,34 +513,6 @@ static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) return 0; } -/* - * Get the rate table for a specific operation mode - */ -const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, - unsigned int mode) -{ - ATH5K_TRACE(ah->ah_sc); - - if (!test_bit(mode, ah->ah_capabilities.cap_mode)) - return NULL; - - /* Get rate tables */ - switch (mode) { - case AR5K_MODE_11A: - return &ath5k_rt_11a; - case AR5K_MODE_11A_TURBO: - return &ath5k_rt_turbo; - case AR5K_MODE_11B: - return &ath5k_rt_11b; - case AR5K_MODE_11G: - return &ath5k_rt_11g; - case AR5K_MODE_11G_TURBO: - return &ath5k_rt_xr; - } - - return NULL; -} - /* * Free the ath5k_hw struct */ @@ -618,45 +583,42 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, return 0; } + +/* + * index into rates for control rates, we can set it up like this because + * this is only used for AR5212 and we know it supports G mode + */ +static int control_rates[] = + { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; + /** * ath5k_hw_write_rate_duration - set rate duration during hw resets * * @ah: the &struct ath5k_hw * @mode: one of enum ath5k_driver_mode * - * Write the rate duration table for the current mode upon hw reset. This - * is a helper for ath5k_hw_reset(). It seems all this is doing is setting - * an ACK timeout for the hardware for the current mode for each rate. The - * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, - * and 11Mbps) have another register for the short preamble ACK timeout - * calculation. - * + * Write the rate duration table upon hw reset. This is a helper for + * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for + * the hardware for the current mode for each rate. The rates which are capable + * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another + * register for the short preamble ACK timeout calculation. */ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, unsigned int mode) { struct ath5k_softc *sc = ah->ah_sc; - const struct ath5k_rate_table *rt; - struct ieee80211_rate srate = {}; + struct ieee80211_rate *rate; unsigned int i; - /* Get rate table for the current operating mode */ - rt = ath5k_hw_get_rate_table(ah, mode); - /* Write rate duration table */ - for (i = 0; i < rt->rate_count; i++) { - const struct ath5k_rate *rate, *control_rate; - + for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { u32 reg; u16 tx_time; - rate = &rt->rates[i]; - control_rate = &rt->rates[rate->control_rate]; + rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; /* Set ACK timeout */ - reg = AR5K_RATE_DUR(rate->rate_code); - - srate.bitrate = control_rate->rate_kbps/100; + reg = AR5K_RATE_DUR(rate->hw_value); /* An ACK frame consists of 10 bytes. If you add the FCS, * which ieee80211_generic_frame_duration() adds, @@ -665,11 +627,11 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, - sc->vif, 10, &srate)); + sc->vif, 10, rate)); ath5k_hw_reg_write(ah, tx_time, reg); - if (!HAS_SHPREAMBLE(i)) + if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) continue; /* -- cgit v1.2.3 From 6f0a2c4dfc96d268233a6a882f3805975f91216c Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 30 Jul 2008 17:20:14 +0200 Subject: iwlwifi: use generic mac80211 radiotap headers remove drivers own implementation of radiotap in favor of the generic one provided by mac80211. also remove priv->add_radiotap because it is not used any more. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 104 ++--------------------- drivers/net/wireless/iwlwifi/iwl-3945.h | 1 - drivers/net/wireless/iwlwifi/iwl-agn.c | 2 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-rx.c | 125 +++++----------------------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 - 6 files changed, 27 insertions(+), 208 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 3f51f363534..8dc26adc197 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -531,99 +531,6 @@ static int iwl3945_is_network_packet(struct iwl3945_priv *priv, } } -static void iwl3945_add_radiotap(struct iwl3945_priv *priv, - struct sk_buff *skb, - struct iwl3945_rx_frame_hdr *rx_hdr, - struct ieee80211_rx_status *stats) -{ - /* First cache any information we need before we overwrite - * the information provided in the skb from the hardware */ - s8 signal = stats->signal; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 phy_flags_hw = rx_hdr->phy_flags, antenna; - - struct iwl3945_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl3945_rt; - - if (skb_headroom(skb) < sizeof(*iwl3945_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl3945_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt)); - - /* initialise radiotap header */ - iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl3945_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA), - &iwl3945_rt->rt_hdr.it_present); - - /* Zero the flags, we'll add to them as we go */ - iwl3945_rt->rt_flags = 0; - - put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf); - - iwl3945_rt->rt_dbmsignal = signal; - iwl3945_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, - &iwl3945_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, - &iwl3945_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, - &iwl3945_rt->rt_chbitmask); - - if (rate == -1) - iwl3945_rt->rt_rate = 0; - else { - if (stats->band == IEEE80211_BAND_5GHZ) - rate += IWL_FIRST_OFDM_RATE; - - iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee; - } - - /* antenna number */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl3945_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if we have it */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) @@ -657,9 +564,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, iwl3945_set_decrypted_flag(priv, rxb->skb, le32_to_cpu(rx_end->status), stats); - if (priv->add_radiotap) - iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); - #ifdef CONFIG_IWL3945_LEDS if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; @@ -684,7 +588,6 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); u8 network_packet; - rx_status.antenna = 0; rx_status.flag = 0; rx_status.mactime = le64_to_cpu(rx_end->timestamp); rx_status.freq = @@ -696,6 +599,13 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; + rx_status.antenna = le16_to_cpu(rx_hdr->phy_flags & + RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if appropriate */ + if (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + rx_status.flag |= RX_FLAG_SHORTPRE; + if ((unlikely(rx_stats->phy_count > 20))) { IWL_DEBUG_DROP ("dsp size out of range [0,20]: " diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index fa81ba1af3d..4dd3f0dbe07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -707,7 +707,6 @@ struct iwl3945_priv { enum ieee80211_band band; int alloc_rxb_skb; - bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 061ffba9c88..676fc0acede 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2790,8 +2790,6 @@ 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->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); - if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c19db438306..79203081950 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -829,7 +829,6 @@ struct iwl_priv { enum ieee80211_band band; int alloc_rxb_skb; - bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index f3f6ea49fdd..b92a580ed2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -789,107 +789,6 @@ static inline void iwl_dbg_report_frame(struct iwl_priv *priv, } #endif -static void iwl_add_radiotap(struct iwl_priv *priv, - struct sk_buff *skb, - struct iwl_rx_phy_res *rx_start, - struct ieee80211_rx_status *stats, - u32 ampdu_status) -{ - s8 signal = stats->signal; - s8 noise = 0; - int rate = stats->rate_idx; - u64 tsf = stats->mactime; - __le16 antenna; - __le16 phy_flags_hw = rx_start->phy_flags; - struct iwl4965_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - } __attribute__ ((packed)) *iwl4965_rt; - - /* TODO: We won't have enough headroom for HT frames. Fix it later. */ - if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { - if (net_ratelimit()) - printk(KERN_ERR "not enough headroom [%d] for " - "radiotap head [%zd]\n", - skb_headroom(skb), sizeof(*iwl4965_rt)); - return; - } - - /* put radiotap header in front of 802.11 header and data */ - iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); - - /* initialise radiotap header */ - iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl4965_rt->rt_hdr.it_pad = 0; - - /* total header + data */ - put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len); - - /* Indicate all the fields we add to the radiotap header */ - put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA), - &(iwl4965_rt->rt_hdr.it_present)); - - /* Zero the flags, we'll add to them as we go */ - iwl4965_rt->rt_flags = 0; - - put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf); - - iwl4965_rt->rt_dbmsignal = signal; - iwl4965_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, - &iwl4965_rt->rt_chbitmask); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, - &iwl4965_rt->rt_chbitmask); - else /* 802.11g */ - put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, - &iwl4965_rt->rt_chbitmask); - - if (rate == -1) - iwl4965_rt->rt_rate = 0; - else - iwl4965_rt->rt_rate = iwl_rates[rate].ieee; - - /* - * "antenna number" - * - * It seems that the antenna field in the phy flags value - * is actually a bitfield. 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 - * new 802.11n radiotap field "RX chains" that is defined - * as a bitmask. - */ - antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; - iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; - - /* set the preamble flag if appropriate */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - stats->flag |= RX_FLAG_RADIOTAP; -} - static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) { /* 0 - mgmt, 1 - cnt, 2 - data */ @@ -1074,9 +973,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - if (priv->add_radiotap) - iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); priv->alloc_rxb_skb--; @@ -1171,7 +1067,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - rx_status.antenna = 0; rx_status.flag = 0; rx_status.flag |= RX_FLAG_TSFT; @@ -1250,6 +1145,26 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); + /* + * "antenna number" + * + * It seems that the antenna field in the phy flags value + * is actually a bitfield. 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 + * new 802.11n radiotap field "RX chains" that is defined + * as a bitmask. + */ + rx_status.antenna = le16_to_cpu(rx_start->phy_flags & + RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if appropriate */ + if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + rx_status.flag |= RX_FLAG_SHORTPRE; + /* Take shortcut when only in monitor mode */ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { iwl_pass_packet_to_mac80211(priv, include_phy, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index b775d5bab66..5096abc66c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6650,8 +6650,6 @@ static int iwl3945_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->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); - if (!iwl3945_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); ret = -EIO; -- cgit v1.2.3 From 73ae98a1334c7ab7c4f01e8a1c0c773470979688 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Mon, 21 Jul 2008 20:29:52 -0400 Subject: iwl-4965: test below 0 on unsigned num_tbs num_tbs is unsigned so the test doesn't work. Signed-off-by: Roel Kluin Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d82823b5c8a..dac34aa8358 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -126,7 +126,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); /* Each TFD can point to a maximum 20 Tx buffers */ - if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + if (num_tbs >= MAX_NUM_OF_TBS) { IWL_ERROR("Error can not send more than %d chunks\n", MAX_NUM_OF_TBS); return -EINVAL; -- cgit v1.2.3 From 39351fa343289070f6f30bd0652e10c8d97f0a3b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 4 Aug 2008 16:00:41 +0800 Subject: iwlwifi: kill struct iwl4965_lq_mngr This patch removes struct iwl4965_lq_mngr it is not used. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 15 --------------- 2 files changed, 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c72f72579be..fbf75a62958 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -876,7 +876,6 @@ int iwl_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); - spin_lock_init(&priv->lq_mngr.lock); INIT_LIST_HEAD(&priv->free_frames); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 79203081950..f46e9cd1ca1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -672,18 +672,6 @@ struct iwl_kw { #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 -struct iwl4965_lq_mngr { - spinlock_t lock; - s32 max_window_size; - s32 *expected_tpt; - u8 *next_higher_rate; - u8 *next_lower_rate; - unsigned long stamp; - unsigned long stamp_last; - u32 flush_time; - u32 tx_packets; -}; - /* Sensitivity and chain noise calibration */ #define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) #define INITIALIZATION_VALUE 0xFFFF @@ -938,9 +926,6 @@ struct iwl_priv { struct iwl_ht_info current_ht_config; u8 last_phy_res[100]; - /* Rate scaling data */ - struct iwl4965_lq_mngr lq_mngr; - /* Rate scaling data */ s8 data_retry_limit; u8 retry_rate; -- cgit v1.2.3 From ded2ae7c1fbff22516fd55ff0edcf6cd86f76186 Mon Sep 17 00:00:00 2001 From: Esti Kummer Date: Mon, 4 Aug 2008 16:00:45 +0800 Subject: iwlwifi: add level for debugging host command This patch adds another level for debugging host command. This adds an option to suppress the debug prints for sensitivity and link quality commands. Signed-off-by: Esti Kummer Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 12 +++++++----- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 14 ++++++++++++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 26 ++++++++++++++++++++------ 3 files changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index d2daa174df2..e548d67f87f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -110,11 +110,12 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) * */ -#define IWL_DL_INFO (1 << 0) -#define IWL_DL_MAC80211 (1 << 1) -#define IWL_DL_HOST_COMMAND (1 << 2) -#define IWL_DL_STATE (1 << 3) +#define IWL_DL_INFO (1 << 0) +#define IWL_DL_MAC80211 (1 << 1) +#define IWL_DL_HCMD (1 << 2) +#define IWL_DL_STATE (1 << 3) #define IWL_DL_MACDUMP (1 << 4) +#define IWL_DL_HCMD_DUMP (1 << 5) #define IWL_DL_RADIO (1 << 7) #define IWL_DL_POWER (1 << 8) #define IWL_DL_TEMP (1 << 9) @@ -162,7 +163,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a) #define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a) #define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a) -#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a) +#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HCMD, f, ## a) +#define IWL_DEBUG_HC_DUMP(f, a...) IWL_DEBUG(IWL_DL_HCMD_DUMP, f, ## a) #define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a) #define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a) #define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 2eb03eea190..8300f3d00a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -120,8 +120,18 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv, return 1; } - IWL_DEBUG_HC("back from %s (0x%08X)\n", - get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); +#ifdef CONFIG_IWLWIFI_DEBUG + switch (cmd->hdr.cmd) { + case REPLY_TX_LINK_QUALITY_CMD: + case SENSITIVITY_CMD: + IWL_DEBUG_HC_DUMP("back from %s (0x%08X)\n", + get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); + break; + default: + IWL_DEBUG_HC("back from %s (0x%08X)\n", + get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); + } +#endif /* Let iwl_tx_complete free the response skb */ return 1; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index dac34aa8358..addf899df17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1065,12 +1065,26 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) phys_addr += offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); - IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); - +#ifdef CONFIG_IWLWIFI_DEBUG + switch (out_cmd->hdr.cmd) { + case REPLY_TX_LINK_QUALITY_CMD: + case SENSITIVITY_CMD: + IWL_DEBUG_HC_DUMP("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, + le16_to_cpu(out_cmd->hdr.sequence), fix_size, + q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + break; + default: + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, + le16_to_cpu(out_cmd->hdr.sequence), fix_size, + q->write_ptr, idx, IWL_CMD_QUEUE_NUM); + } +#endif txq->need_update = 1; /* Set up entry in queue's byte count circular buffer */ -- cgit v1.2.3 From ba5b6efe5d945f7a4c5b656051cc16698afdda24 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Tue, 15 Jul 2008 18:43:56 -0700 Subject: b43legacy: use le16 frame control directly, avoid byteswapping Acked-by: Michael Buesch Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/xmit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 68e1f8c7872..c5ca72aa59e 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -193,7 +193,6 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, { const struct ieee80211_hdr *wlhdr; int use_encryption = !!info->control.hw_key; - u16 fctl; u8 rate; struct ieee80211_rate *rate_fb; int rate_ofdm; @@ -204,7 +203,6 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct ieee80211_rate *tx_rate; wlhdr = (const struct ieee80211_hdr *)fragment_data; - fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); @@ -253,7 +251,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= (key->algorithm << B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; - wlhdr_len = ieee80211_get_hdrlen(fctl); + wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control); iv_len = min((size_t)info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); -- cgit v1.2.3 From 7294ec955cb0c3eeefca2f4dd271c8068ab4edc5 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Tue, 15 Jul 2008 18:43:59 -0700 Subject: iwlwifi: use le16 frame control directly, use QOS symbolic constant mask Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index addf899df17..6cba5e9c54e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -824,7 +824,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); + hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ sta_id = iwl_get_sta_id(priv, hdr); @@ -842,7 +842,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq_id = swq_id; if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5096abc66c0..a622fc33590 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2574,7 +2574,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) spin_unlock_irqrestore(&priv->lock, flags); - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(fc)); + hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); @@ -2590,7 +2590,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -2709,7 +2709,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) sizeof(out_cmd->cmd.tx)); iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, - ieee80211_get_hdrlen(le16_to_cpu(fc))); + ieee80211_hdrlen(fc)); /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); -- cgit v1.2.3 From 798ee9850e9bf94b4436f9c7238823322e326885 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Tue, 15 Jul 2008 18:44:02 -0700 Subject: ath5k: explicitly check skb->len ieee80211_get_hdrlen_from_skb internally checks that the skb is long enough to hold the full header, or it returns 0 if not. The check in ath5k does not check this case and assumes it always got the actual header length which it then checks against the skb->len plus some headroom. Change to ieee80211_hdrlen which always returns the hdrlen and keep the existing headroom check. Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 114520258b7..c1de1ef09e5 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1540,7 +1540,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, struct sk_buff *skb, struct ath5k_rx_status *rs) { struct ieee80211_hdr *hdr = (void *)skb->data; - unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); + unsigned int keyix, hlen; if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && rs->rs_keyix != AR5K_RXKEYIX_INVALID) @@ -1549,6 +1549,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, /* Apparently when a default key is used to decrypt the packet the hw does not set the index used to decrypt. In such cases get the index from the packet. */ + hlen = ieee80211_hdrlen(hdr->frame_control); if (ieee80211_has_protected(hdr->frame_control) && !(rs->rs_status & AR5K_RXERR_DECRYPT) && skb->len >= hlen + 4) { -- cgit v1.2.3 From 7670e62c7ed6d1a70a98c3047898712be6aa9ff8 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 14 Aug 2008 10:40:52 -0700 Subject: libertas_tf: header file Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/libertas_tf.h | 514 +++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 drivers/net/wireless/libertas_tf/libertas_tf.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h new file mode 100644 index 00000000000..8995cd7c29b --- /dev/null +++ b/drivers/net/wireless/libertas_tf/libertas_tf.h @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2007, Red Hat, Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#include +#include +#include +#include + +#ifndef DRV_NAME +#define DRV_NAME "libertas_tf" +#endif + +#define MRVL_DEFAULT_RETRIES 9 +#define MRVL_PER_PACKET_RATE 0x10 +#define MRVL_MAX_BCN_SIZE 440 +#define CMD_OPTION_WAITFORRSP 0x0002 + +/* Return command are almost always the same as the host command, but with + * bit 15 set high. There are a few exceptions, though... + */ +#define CMD_RET(cmd) (0x8000 | cmd) + +/* Command codes */ +#define CMD_GET_HW_SPEC 0x0003 +#define CMD_802_11_RESET 0x0005 +#define CMD_MAC_MULTICAST_ADR 0x0010 +#define CMD_802_11_RADIO_CONTROL 0x001c +#define CMD_802_11_RF_CHANNEL 0x001d +#define CMD_802_11_RF_TX_POWER 0x001e +#define CMD_MAC_CONTROL 0x0028 +#define CMD_802_11_MAC_ADDRESS 0x004d +#define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_802_11_BEACON_CTRL 0x00b0 +#define CMD_802_11_BEACON_SET 0x00cb +#define CMD_802_11_SET_MODE 0x00cc +#define CMD_802_11_SET_BSSID 0x00cd + +#define CMD_ACT_GET 0x0000 +#define CMD_ACT_SET 0x0001 + +/* Define action or option for CMD_802_11_RESET */ +#define CMD_ACT_HALT 0x0003 + +/* Define action or option for CMD_MAC_CONTROL */ +#define CMD_ACT_MAC_RX_ON 0x0001 +#define CMD_ACT_MAC_TX_ON 0x0002 +#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 + +/* Define action or option for CMD_802_11_RADIO_CONTROL */ +#define CMD_TYPE_AUTO_PREAMBLE 0x0001 +#define CMD_TYPE_SHORT_PREAMBLE 0x0002 +#define CMD_TYPE_LONG_PREAMBLE 0x0003 + +#define TURN_ON_RF 0x01 +#define RADIO_ON 0x01 +#define RADIO_OFF 0x00 + +#define SET_AUTO_PREAMBLE 0x05 +#define SET_SHORT_PREAMBLE 0x03 +#define SET_LONG_PREAMBLE 0x01 + +/* Define action or option for CMD_802_11_RF_CHANNEL */ +#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 +#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 + +/* Codes for CMD_802_11_SET_MODE */ +enum lbtf_mode { + LBTF_PASSIVE_MODE, + LBTF_STA_MODE, + LBTF_AP_MODE, +}; + +/** Card Event definition */ +#define MACREG_INT_CODE_FIRMWARE_READY 48 +/** Buffer Constants */ + +/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical +* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas +* driver has more local TxPDs. Each TxPD on the host memory is associated +* with a Tx control node. The driver maintains 8 RxPD descriptors for +* station firmware to store Rx packet information. +* +* Current version of MAC has a 32x6 multicast address buffer. +* +* 802.11b can have up to 14 channels, the driver keeps the +* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. +*/ + +#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 +#define LBS_NUM_CMD_BUFFERS 10 +#define LBS_CMD_BUFFER_SIZE (2 * 1024) +#define MRVDRV_MAX_CHANNEL_SIZE 14 +#define MRVDRV_SNAP_HEADER_LEN 8 + +#define LBS_UPLD_SIZE 2312 +#define DEV_NAME_LEN 32 + +/** Misc constants */ +/* This section defines 802.11 specific contants */ + +#define MRVDRV_MAX_REGION_CODE 6 +/** + * the table to keep region code + */ +#define LBTF_REGDOMAIN_US 0x10 +#define LBTF_REGDOMAIN_CA 0x20 +#define LBTF_REGDOMAIN_EU 0x30 +#define LBTF_REGDOMAIN_SP 0x31 +#define LBTF_REGDOMAIN_FR 0x32 +#define LBTF_REGDOMAIN_JP 0x40 + +#define SBI_EVENT_CAUSE_SHIFT 3 + +/** RxPD status */ + +#define MRVDRV_RXPD_STATUS_OK 0x0001 + + +/* This is for firmware specific length */ +#define EXTRA_LEN 36 + +#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN) + +#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct rxpd) \ + + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) + +#define CMD_F_HOSTCMD (1 << 0) +#define FW_CAPINFO_WPA (1 << 0) + +#define RF_ANTENNA_1 0x1 +#define RF_ANTENNA_2 0x2 +#define RF_ANTENNA_AUTO 0xFFFF + +#define LBTF_EVENT_BCN_SENT 55 + +/** Global Variable Declaration */ +/** mv_ms_type */ +enum mv_ms_type { + MVMS_DAT = 0, + MVMS_CMD = 1, + MVMS_TXDONE = 2, + MVMS_EVENT +}; + +extern struct workqueue_struct *lbtf_wq; + +struct lbtf_private; + +struct lbtf_offset_value { + u32 offset; + u32 value; +}; + +struct channel_range { + u8 regdomain; + u8 start; + u8 end; /* exclusive (channel must be less than end) */ +}; + +struct if_usb_card; + +/** Private structure for the MV device */ +struct lbtf_private { + void *card; + struct ieee80211_hw *hw; + + /* Command response buffer */ + u8 cmd_resp_buff[LBS_UPLD_SIZE]; + /* Download sent: + bit0 1/0=data_sent/data_tx_done, + bit1 1/0=cmd_sent/cmd_tx_done, + all other bits reserved 0 */ + struct ieee80211_vif *vif; + + struct work_struct cmd_work; + struct work_struct tx_work; + /** Hardware access */ + int (*hw_host_to_card) (struct lbtf_private *priv, u8 type, u8 *payload, u16 nb); + int (*hw_prog_firmware) (struct if_usb_card *cardp); + int (*hw_reset_device) (struct if_usb_card *cardp); + + + /** Wlan adapter data structure*/ + /** STATUS variables */ + u32 fwrelease; + u32 fwcapinfo; + /* protected with big lock */ + + struct mutex lock; + + /** command-related variables */ + u16 seqnum; + /* protected by big lock */ + + struct cmd_ctrl_node *cmd_array; + /** Current command */ + struct cmd_ctrl_node *cur_cmd; + /** command Queues */ + /** Free command buffers */ + struct list_head cmdfreeq; + /** Pending command buffers */ + struct list_head cmdpendingq; + + /** spin locks */ + spinlock_t driver_lock; + + /** Timers */ + struct timer_list command_timer; + int nr_retries; + int cmd_timed_out; + + u8 cmd_response_rxed; + + /** capability Info used in Association, start, join */ + u16 capability; + + /** MAC address information */ + u8 current_addr[ETH_ALEN]; + u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; + u32 nr_of_multicastmacaddr; + int cur_freq; + + struct sk_buff *skb_to_tx; + struct sk_buff *tx_skb; + + /** NIC Operation characteristics */ + u16 mac_control; + u16 regioncode; + struct channel_range range; + + u8 radioon; + u32 preamble; + + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct lbtf_offset_value offsetvalue; + + u8 fw_ready; + u8 surpriseremoved; + struct sk_buff_head bc_ps_buf; +}; + +/* 802.11-related definitions */ + +/* TxPD descriptor */ +struct txpd { + /* Current Tx packet status */ + __le32 tx_status; + /* Tx control */ + __le32 tx_control; + __le32 tx_packet_location; + /* Tx packet length */ + __le16 tx_packet_length; + /* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; + /* Last 4 byte of destination MAC address */ + u8 tx_dest_addr_low[4]; + /* Pkt Priority */ + u8 priority; + /* Pkt Trasnit Power control */ + u8 powermgmt; + /* Time the packet has been queued in the driver (units = 2ms) */ + u8 pktdelay_2ms; + /* reserved */ + u8 reserved1; +}; + +/* RxPD Descriptor */ +struct rxpd { + /* Current Rx packet status */ + __le16 status; + + /* SNR */ + u8 snr; + + /* Tx control */ + u8 rx_control; + + /* Pkt length */ + __le16 pkt_len; + + /* Noise Floor */ + u8 nf; + + /* Rx Packet Rate */ + u8 rx_rate; + + /* Pkt addr */ + __le32 pkt_ptr; + + /* Next Rx RxPD addr */ + __le32 next_rxpd_ptr; + + /* Pkt Priority */ + u8 priority; + u8 reserved[3]; +}; + +struct cmd_header { + __le16 command; + __le16 size; + __le16 seqnum; + __le16 result; +} __attribute__ ((packed)); + +struct cmd_ctrl_node { + struct list_head list; + int result; + /* command response */ + int (*callback)(struct lbtf_private *, + unsigned long, struct cmd_header *); + unsigned long callback_arg; + /* command data */ + struct cmd_header *cmdbuf; + /* wait queue */ + u16 cmdwaitqwoken; + wait_queue_head_t cmdwait_q; +}; + +/* + * Define data structure for CMD_GET_HW_SPEC + * This structure defines the response for the GET_HW_SPEC command + */ +struct cmd_ds_get_hw_spec { + struct cmd_header hdr; + + /* HW Interface version number */ + __le16 hwifversion; + /* HW version number */ + __le16 version; + /* Max number of TxPD FW can handle */ + __le16 nr_txpd; + /* Max no of Multicast address */ + __le16 nr_mcast_adr; + /* MAC address */ + u8 permanentaddr[6]; + + /* region Code */ + __le16 regioncode; + + /* Number of antenna used */ + __le16 nr_antenna; + + /* FW release number, example 0x01030304 = 2.3.4p1 */ + __le32 fwrelease; + + /* Base Address of TxPD queue */ + __le32 wcb_base; + /* Read Pointer of RxPd queue */ + __le32 rxpd_rdptr; + + /* Write Pointer of RxPd queue */ + __le32 rxpd_wrptr; + + /*FW/HW capability */ + __le32 fwcapinfo; +} __attribute__ ((packed)); + +struct cmd_ds_mac_control { + struct cmd_header hdr; + __le16 action; + u16 reserved; +}; + +struct cmd_ds_802_11_mac_address { + struct cmd_header hdr; + + __le16 action; + uint8_t macadd[ETH_ALEN]; +}; + +struct cmd_ds_mac_multicast_addr { + struct cmd_header hdr; + + __le16 action; + __le16 nr_of_adrs; + u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; +}; + +struct cmd_ds_set_mode { + struct cmd_header hdr; + + __le16 mode; +}; + +struct cmd_ds_set_bssid { + struct cmd_header hdr; + + u8 bssid[6]; + u8 activate; +}; + +struct cmd_ds_802_11_radio_control { + struct cmd_header hdr; + + __le16 action; + __le16 control; +}; + + +struct cmd_ds_802_11_rf_channel { + struct cmd_header hdr; + + __le16 action; + __le16 channel; + __le16 rftype; /* unused */ + __le16 reserved; /* unused */ + u8 channellist[32]; /* unused */ +}; + +struct cmd_ds_set_boot2_ver { + struct cmd_header hdr; + + __le16 action; + __le16 version; +}; + +struct cmd_ds_802_11_reset { + struct cmd_header hdr; + + __le16 action; +}; + +struct cmd_ds_802_11_beacon_control { + struct cmd_header hdr; + + __le16 action; + __le16 beacon_enable; + __le16 beacon_period; +}; + +struct cmd_ds_802_11_beacon_set { + struct cmd_header hdr; + + __le16 len; + u8 beacon[MRVL_MAX_BCN_SIZE]; +}; + +struct lbtf_private; +struct cmd_ctrl_node; + +/** Function Prototype Declaration */ +void lbtf_set_mac_control(struct lbtf_private *priv); + +int lbtf_free_cmd_buffer(struct lbtf_private *priv); + +int lbtf_allocate_cmd_buffer(struct lbtf_private *priv); +int lbtf_execute_next_command(struct lbtf_private *priv); +int lbtf_set_radio_control(struct lbtf_private *priv); +int lbtf_update_hw_spec(struct lbtf_private *priv); +int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv); +void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode); +void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid); +int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr); + +int lbtf_set_channel(struct lbtf_private *priv, u8 channel); + +int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon); +int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable, + int beacon_int); + + +int lbtf_process_rx_command(struct lbtf_private *priv); +void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd, + int result); +void lbtf_cmd_response_rx(struct lbtf_private *priv); + +/* main.c */ +struct chan_freq_power *lbtf_get_region_cfp_table(u8 region, + int *cfp_no); +struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev); +int lbtf_remove_card(struct lbtf_private *priv); +int lbtf_start_card(struct lbtf_private *priv); +int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb); +void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail); +void lbtf_bcn_sent(struct lbtf_private *priv); + +/* support functions for cmd.c */ +/* lbtf_cmd() infers the size of the buffer to copy data back into, from + the size of the target of the pointer. Since the command to be sent + may often be smaller, that size is set in cmd->size by the caller.*/ +#define lbtf_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \ + uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \ + (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd))); \ + __lbtf_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg); \ +}) + +#define lbtf_cmd_with_response(priv, cmdnr, cmd) \ + lbtf_cmd(priv, cmdnr, cmd, lbtf_cmd_copyback, (unsigned long) (cmd)) + +void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size); + +int __lbtf_cmd(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbtf_private *, unsigned long, + struct cmd_header *), + unsigned long callback_arg); + +int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra, + struct cmd_header *resp); -- cgit v1.2.3 From 06b16ae5319251c26377afcb401e46056d5673f4 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 14 Aug 2008 10:40:57 -0700 Subject: libertas_tf: main.c, data paths and mac80211 handlers This patch contains most of the libertastf driver, just lacking command helper functions and usb specific functions. Currently, monitor, managed, ap and mesh interfaces are supported. Even though this driver supports the same hardware as the "libertas" driver, it uses a different (thin) firmware, that makes it suitable for a mac80211 driver. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/main.c | 666 ++++++++++++++++++++++++++++++++ 1 file changed, 666 insertions(+) create mode 100644 drivers/net/wireless/libertas_tf/main.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c new file mode 100644 index 00000000000..2c1d680d2c5 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/main.c @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#include "libertas_tf.h" +#include "linux/etherdevice.h" + +#define DRIVER_RELEASE_VERSION "004.p0" +/* thinfirm version: 5.132.X.pX */ +#define LBTF_FW_VER_MIN 0x05840300 +#define LBTF_FW_VER_MAX 0x0584ffff +#define QOS_CONTROL_LEN 2 + +static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION; +struct workqueue_struct *lbtf_wq; + +static const struct ieee80211_channel lbtf_channels[] = { + { .center_freq = 2412, .hw_value = 1 }, + { .center_freq = 2417, .hw_value = 2 }, + { .center_freq = 2422, .hw_value = 3 }, + { .center_freq = 2427, .hw_value = 4 }, + { .center_freq = 2432, .hw_value = 5 }, + { .center_freq = 2437, .hw_value = 6 }, + { .center_freq = 2442, .hw_value = 7 }, + { .center_freq = 2447, .hw_value = 8 }, + { .center_freq = 2452, .hw_value = 9 }, + { .center_freq = 2457, .hw_value = 10 }, + { .center_freq = 2462, .hw_value = 11 }, + { .center_freq = 2467, .hw_value = 12 }, + { .center_freq = 2472, .hw_value = 13 }, + { .center_freq = 2484, .hw_value = 14 }, +}; + +/* This table contains the hardware specific values for the modulation rates. */ +static const struct ieee80211_rate lbtf_rates[] = { + { .bitrate = 10, + .hw_value = 0, }, + { .bitrate = 20, + .hw_value = 1, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 3, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 5, + .flags = 0 }, + { .bitrate = 90, + .hw_value = 6, + .flags = 0 }, + { .bitrate = 120, + .hw_value = 7, + .flags = 0 }, + { .bitrate = 180, + .hw_value = 8, + .flags = 0 }, + { .bitrate = 240, + .hw_value = 9, + .flags = 0 }, + { .bitrate = 360, + .hw_value = 10, + .flags = 0 }, + { .bitrate = 480, + .hw_value = 11, + .flags = 0 }, + { .bitrate = 540, + .hw_value = 12, + .flags = 0 }, +}; + +static void lbtf_cmd_work(struct work_struct *work) +{ + struct lbtf_private *priv = container_of(work, struct lbtf_private, + cmd_work); + spin_lock_irq(&priv->driver_lock); + /* command response? */ + if (priv->cmd_response_rxed) { + priv->cmd_response_rxed = 0; + spin_unlock_irq(&priv->driver_lock); + lbtf_process_rx_command(priv); + spin_lock_irq(&priv->driver_lock); + } + + if (priv->cmd_timed_out && priv->cur_cmd) { + struct cmd_ctrl_node *cmdnode = priv->cur_cmd; + + if (++priv->nr_retries > 10) { + lbtf_complete_command(priv, cmdnode, + -ETIMEDOUT); + priv->nr_retries = 0; + } else { + priv->cur_cmd = NULL; + + /* Stick it back at the _top_ of the pending + * queue for immediate resubmission */ + list_add(&cmdnode->list, &priv->cmdpendingq); + } + } + priv->cmd_timed_out = 0; + spin_unlock_irq(&priv->driver_lock); + + if (!priv->fw_ready) + return; + /* Execute the next command */ + if (!priv->cur_cmd) + lbtf_execute_next_command(priv); +} + +/** + * lbtf_setup_firmware: initialize firmware. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success. + */ +static int lbtf_setup_firmware(struct lbtf_private *priv) +{ + int ret = -1; + + /* + * Read priv address from HW + */ + memset(priv->current_addr, 0xff, ETH_ALEN); + ret = lbtf_update_hw_spec(priv); + if (ret) { + ret = -1; + goto done; + } + + lbtf_set_mac_control(priv); + lbtf_set_radio_control(priv); + + ret = 0; +done: + return ret; +} + +/** + * This function handles the timeout of command sending. + * It will re-send the same command again. + */ +static void command_timer_fn(unsigned long data) +{ + struct lbtf_private *priv = (struct lbtf_private *)data; + unsigned long flags; + + spin_lock_irqsave(&priv->driver_lock, flags); + + if (!priv->cur_cmd) { + printk(KERN_DEBUG "libertastf: command timer expired; " + "no pending command\n"); + goto out; + } + + printk(KERN_DEBUG "libertas: command %x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + + priv->cmd_timed_out = 1; + queue_work(lbtf_wq, &priv->cmd_work); +out: + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +static int lbtf_init_adapter(struct lbtf_private *priv) +{ + memset(priv->current_addr, 0xff, ETH_ALEN); + mutex_init(&priv->lock); + + priv->vif = NULL; + setup_timer(&priv->command_timer, command_timer_fn, + (unsigned long)priv); + + INIT_LIST_HEAD(&priv->cmdfreeq); + INIT_LIST_HEAD(&priv->cmdpendingq); + + spin_lock_init(&priv->driver_lock); + + /* Allocate the command buffers */ + if (lbtf_allocate_cmd_buffer(priv)) + return -1; + + return 0; +} + +static void lbtf_free_adapter(struct lbtf_private *priv) +{ + lbtf_free_cmd_buffer(priv); + del_timer(&priv->command_timer); +} + +static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct lbtf_private *priv = hw->priv; + + priv->skb_to_tx = skb; + queue_work(lbtf_wq, &priv->tx_work); + /* + * queue will be restarted when we receive transmission feedback if + * there are no buffered multicast frames to send + */ + ieee80211_stop_queues(priv->hw); + return 0; +} + +static void lbtf_tx_work(struct work_struct *work) +{ + struct lbtf_private *priv = container_of(work, struct lbtf_private, + tx_work); + unsigned int len; + struct ieee80211_tx_info *info; + struct txpd *txpd; + struct sk_buff *skb = NULL; + int err; + + if ((priv->vif->type == IEEE80211_IF_TYPE_AP) && + (!skb_queue_empty(&priv->bc_ps_buf))) + skb = skb_dequeue(&priv->bc_ps_buf); + else if (priv->skb_to_tx) { + skb = priv->skb_to_tx; + priv->skb_to_tx = NULL; + } else + return; + + len = skb->len; + info = IEEE80211_SKB_CB(skb); + txpd = (struct txpd *) skb_push(skb, sizeof(struct txpd)); + + if (priv->surpriseremoved) { + dev_kfree_skb_any(skb); + return; + } + + memset(txpd, 0, sizeof(struct txpd)); + /* Activate per-packet rate selection */ + txpd->tx_control |= cpu_to_le32(MRVL_PER_PACKET_RATE | + ieee80211_get_tx_rate(priv->hw, info)->hw_value); + + /* copy destination address from 802.11 header */ + memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4, + ETH_ALEN); + txpd->tx_packet_length = cpu_to_le16(len); + txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); + BUG_ON(priv->tx_skb); + spin_lock_irq(&priv->driver_lock); + priv->tx_skb = skb; + err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len); + spin_unlock_irq(&priv->driver_lock); + if (err) { + dev_kfree_skb_any(skb); + priv->tx_skb = NULL; + } +} + +static int lbtf_op_start(struct ieee80211_hw *hw) +{ + struct lbtf_private *priv = hw->priv; + void *card = priv->card; + int ret = -1; + + if (!priv->fw_ready) + /* Upload firmware */ + if (priv->hw_prog_firmware(card)) + goto err_prog_firmware; + + /* poke the firmware */ + priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; + priv->radioon = RADIO_ON; + priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + ret = lbtf_setup_firmware(priv); + if (ret) + goto err_prog_firmware; + + if ((priv->fwrelease < LBTF_FW_VER_MIN) || + (priv->fwrelease > LBTF_FW_VER_MAX)) { + ret = -1; + goto err_prog_firmware; + } + + printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n"); + return 0; + +err_prog_firmware: + priv->hw_reset_device(card); + return ret; +} + +static void lbtf_op_stop(struct ieee80211_hw *hw) +{ + struct lbtf_private *priv = hw->priv; + unsigned long flags; + struct sk_buff *skb; + + struct cmd_ctrl_node *cmdnode; + /* Flush pending command nodes */ + spin_lock_irqsave(&priv->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { + cmdnode->result = -ENOENT; + cmdnode->cmdwaitqwoken = 1; + wake_up_interruptible(&cmdnode->cmdwait_q); + } + + spin_unlock_irqrestore(&priv->driver_lock, flags); + cancel_work_sync(&priv->cmd_work); + cancel_work_sync(&priv->tx_work); + while ((skb = skb_dequeue(&priv->bc_ps_buf))) + dev_kfree_skb_any(skb); + priv->radioon = RADIO_OFF; + lbtf_set_radio_control(priv); + + return; +} + +static int lbtf_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + if (priv->vif != NULL) + return -EOPNOTSUPP; + + priv->vif = conf->vif; + switch (conf->type) { + case IEEE80211_IF_TYPE_MESH_POINT: + case IEEE80211_IF_TYPE_AP: + lbtf_set_mode(priv, LBTF_AP_MODE); + break; + case IEEE80211_IF_TYPE_STA: + lbtf_set_mode(priv, LBTF_STA_MODE); + break; + default: + priv->vif = NULL; + return -EOPNOTSUPP; + } + lbtf_set_mac_address(priv, (u8 *) conf->mac_addr); + return 0; +} + +static void lbtf_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + + if (priv->vif->type == IEEE80211_IF_TYPE_AP || + priv->vif->type == IEEE80211_IF_TYPE_MESH_POINT) + lbtf_beacon_ctrl(priv, 0, 0); + lbtf_set_mode(priv, LBTF_PASSIVE_MODE); + lbtf_set_bssid(priv, 0, NULL); + priv->vif = NULL; +} + +static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + if (conf->channel->center_freq != priv->cur_freq) { + priv->cur_freq = conf->channel->center_freq; + lbtf_set_channel(priv, conf->channel->hw_value); + } + return 0; +} + +static int lbtf_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct lbtf_private *priv = hw->priv; + struct sk_buff *beacon; + + switch (priv->vif->type) { + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_MESH_POINT: + beacon = ieee80211_beacon_get(hw, vif); + if (beacon) { + lbtf_beacon_set(priv, beacon); + kfree_skb(beacon); + lbtf_beacon_ctrl(priv, 1, hw->conf.beacon_int); + } + break; + default: + break; + } + + if (conf->bssid) { + u8 null_bssid[ETH_ALEN] = {0}; + bool activate = compare_ether_addr(conf->bssid, null_bssid); + lbtf_set_bssid(priv, activate, conf->bssid); + } + + return 0; +} + +#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) +static void lbtf_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct lbtf_private *priv = hw->priv; + int old_mac_control = priv->mac_control; + int i; + changed_flags &= SUPPORTED_FIF_FLAGS; + *new_flags &= SUPPORTED_FIF_FLAGS; + + if (!changed_flags) + return; + + if (*new_flags & (FIF_PROMISC_IN_BSS)) + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; + else + priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; + if (*new_flags & (FIF_ALLMULTI) || + mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; + } else if (mc_count) { + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; + priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; + priv->nr_of_multicastmacaddr = mc_count; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + memcpy(&priv->multicastlist[i], mclist->da_addr, + ETH_ALEN); + mclist = mclist->next; + } + lbtf_cmd_set_mac_multicast_addr(priv); + } else { + priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | + CMD_ACT_MAC_ALL_MULTICAST_ENABLE); + if (priv->nr_of_multicastmacaddr) { + priv->nr_of_multicastmacaddr = 0; + lbtf_cmd_set_mac_multicast_addr(priv); + } + } + + + if (priv->mac_control != old_mac_control) + lbtf_set_mac_control(priv); +} + +static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct lbtf_private *priv = hw->priv; + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + else + priv->preamble = CMD_TYPE_LONG_PREAMBLE; + lbtf_set_radio_control(priv); + } + + return; +} + +static const struct ieee80211_ops lbtf_ops = { + .tx = lbtf_op_tx, + .start = lbtf_op_start, + .stop = lbtf_op_stop, + .add_interface = lbtf_op_add_interface, + .remove_interface = lbtf_op_remove_interface, + .config = lbtf_op_config, + .config_interface = lbtf_op_config_interface, + .configure_filter = lbtf_op_configure_filter, + .bss_info_changed = lbtf_op_bss_info_changed, +}; + +int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) +{ + struct ieee80211_rx_status stats; + struct rxpd *prxpd; + bool is_qos, is_4addr, is_amsdu, need_padding; + unsigned int flags; + u16 fc, fc_le; + + prxpd = (struct rxpd *) skb->data; + + stats.flag = 0; + if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) + stats.flag |= RX_FLAG_FAILED_FCS_CRC; + stats.freq = priv->cur_freq; + stats.band = IEEE80211_BAND_2GHZ; + stats.signal = prxpd->snr; + stats.noise = prxpd->nf; + stats.qual = prxpd->snr - prxpd->nf; + /* Marvell rate index has a hole at value 4 */ + if (prxpd->rx_rate > 4) + --prxpd->rx_rate; + stats.rate_idx = prxpd->rx_rate; + skb_pull(skb, sizeof(struct rxpd)); + + fc_le = *((__le16 *) skb->data); + fc = le16_to_cpu(fc_le); + flags = le32_to_cpu(*(__le32 *)(skb->data + 4)); + + is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (fc & IEEE80211_STYPE_QOS_DATA); + is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); + is_amsdu = ((fc & 0x8C) == 0x88) && + (*(skb->data + ieee80211_hdrlen(fc_le) - QOS_CONTROL_LEN) + & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); + + need_padding = is_qos ^ is_4addr ^ is_amsdu; + if (need_padding) { + memmove(skb->data + 2, skb->data, skb->len); + skb_reserve(skb, 2); + } + + ieee80211_rx_irqsafe(priv->hw, skb, &stats); + return 0; +} +EXPORT_SYMBOL_GPL(lbtf_rx); + +/** + * lbtf_add_card: Add and initialize the card, no fw upload yet. + * + * @card A pointer to card + * + * Returns: pointer to struct lbtf_priv. + */ +struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) +{ + struct ieee80211_hw *hw; + struct lbtf_private *priv = NULL; + + hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops); + if (!hw) + goto done; + + priv = hw->priv; + if (lbtf_init_adapter(priv)) + goto err_init_adapter; + + priv->hw = hw; + priv->card = card; + priv->tx_skb = NULL; + + hw->queues = 1; + hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + hw->extra_tx_headroom = sizeof(struct txpd); + memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels)); + memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates)); + priv->band.n_bitrates = ARRAY_SIZE(lbtf_rates); + priv->band.bitrates = priv->rates; + priv->band.n_channels = ARRAY_SIZE(lbtf_channels); + priv->band.channels = priv->channels; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + skb_queue_head_init(&priv->bc_ps_buf); + + SET_IEEE80211_DEV(hw, dmdev); + + INIT_WORK(&priv->cmd_work, lbtf_cmd_work); + INIT_WORK(&priv->tx_work, lbtf_tx_work); + if (ieee80211_register_hw(hw)) + goto err_init_adapter; + + goto done; + +err_init_adapter: + lbtf_free_adapter(priv); + ieee80211_free_hw(hw); + priv = NULL; + +done: + return priv; +} +EXPORT_SYMBOL_GPL(lbtf_add_card); + + +int lbtf_remove_card(struct lbtf_private *priv) +{ + struct ieee80211_hw *hw = priv->hw; + + priv->surpriseremoved = 1; + del_timer(&priv->command_timer); + lbtf_free_adapter(priv); + priv->hw = NULL; + ieee80211_unregister_hw(hw); + ieee80211_free_hw(hw); + + return 0; +} +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)); + /* + * 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)); + ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb); + priv->tx_skb = NULL; + if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf)) + ieee80211_wake_queues(priv->hw); + else + queue_work(lbtf_wq, &priv->tx_work); +} +EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback); + +void lbtf_bcn_sent(struct lbtf_private *priv) +{ + struct sk_buff *skb = NULL; + + if (priv->vif->type != IEEE80211_IF_TYPE_AP) + return; + + if (skb_queue_empty(&priv->bc_ps_buf)) { + bool tx_buff_bc = 0; + + while ((skb = ieee80211_get_buffered_bc(priv->hw, priv->vif))) { + skb_queue_tail(&priv->bc_ps_buf, skb); + tx_buff_bc = 1; + } + if (tx_buff_bc) { + ieee80211_stop_queues(priv->hw); + queue_work(lbtf_wq, &priv->tx_work); + } + } + + skb = ieee80211_beacon_get(priv->hw, priv->vif); + + if (skb) { + lbtf_beacon_set(priv, skb); + kfree_skb(skb); + } +} +EXPORT_SYMBOL_GPL(lbtf_bcn_sent); + +static int __init lbtf_init_module(void) +{ + lbtf_wq = create_workqueue("libertastf"); + if (lbtf_wq == NULL) { + printk(KERN_ERR "libertastf: couldn't create workqueue\n"); + return -ENOMEM; + } + return 0; +} + +static void __exit lbtf_exit_module(void) +{ + destroy_workqueue(lbtf_wq); +} + +module_init(lbtf_init_module); +module_exit(lbtf_exit_module); + +MODULE_DESCRIPTION("Libertas WLAN Thinfirm Driver Library"); +MODULE_AUTHOR("Cozybit Inc."); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 691cdb49388b808bfbfacaea93afb5c2807db45e Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 14 Aug 2008 10:41:01 -0700 Subject: libertas_tf: command helper functions for libertas_tf Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/cmd.c | 669 +++++++++++++++++++++++++++++++++ 1 file changed, 669 insertions(+) create mode 100644 drivers/net/wireless/libertas_tf/cmd.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c new file mode 100644 index 00000000000..fdbcf8ba3e8 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -0,0 +1,669 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#include "libertas_tf.h" + +static const struct channel_range channel_ranges[] = { + { LBTF_REGDOMAIN_US, 1, 12 }, + { LBTF_REGDOMAIN_CA, 1, 12 }, + { LBTF_REGDOMAIN_EU, 1, 14 }, + { LBTF_REGDOMAIN_JP, 1, 14 }, + { LBTF_REGDOMAIN_SP, 1, 14 }, + { LBTF_REGDOMAIN_FR, 1, 14 }, +}; + +static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] = +{ + LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU, + LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP, +}; + +static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv); + + +/** + * lbtf_cmd_copyback - Simple callback that copies response back into command + * + * @priv A pointer to struct lbtf_private structure + * @extra A pointer to the original command structure for which + * 'resp' is a response + * @resp A pointer to the command response + * + * Returns: 0 on success, error on failure + */ +int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra, + struct cmd_header *resp) +{ + struct cmd_header *buf = (void *)extra; + uint16_t copy_len; + + copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size)); + memcpy(buf, resp, copy_len); + return 0; +} +EXPORT_SYMBOL_GPL(lbtf_cmd_copyback); + +#define CHAN_TO_IDX(chan) ((chan) - 1) + +static void lbtf_geo_init(struct lbtf_private *priv) +{ + const struct channel_range *range = channel_ranges; + u8 ch; + int i; + + for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) + if (channel_ranges[i].regdomain == priv->regioncode) { + range = &channel_ranges[i]; + break; + } + + for (ch = priv->range.start; ch < priv->range.end; ch++) + priv->channels[CHAN_TO_IDX(ch)].flags = 0; +} + +/** + * lbtf_update_hw_spec: Updates the hardware details. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success, error on failure + */ +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)); + memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN); + ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd); + if (ret) + goto out; + + priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo); + + /* The firmware release is in an interesting format: the patch + * level is in the most significant nibble ... so fix that: */ + priv->fwrelease = le32_to_cpu(cmd.fwrelease); + 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), + priv->fwrelease >> 24 & 0xff, + priv->fwrelease >> 16 & 0xff, + priv->fwrelease >> 8 & 0xff, + priv->fwrelease & 0xff, + priv->fwcapinfo); + + /* Clamp region code to 8-bit since FW spec indicates that it should + * only ever be 8-bit, even though the field size is 16-bit. Some + * firmware returns non-zero high 8 bits here. + */ + priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF; + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + /* use the region code to search for the index */ + if (priv->regioncode == lbtf_region_code_to_index[i]) + break; + } + + /* if it's unidentified region code, use the default (USA) */ + if (i >= MRVDRV_MAX_REGION_CODE) + priv->regioncode = 0x10; + + if (priv->current_addr[0] == 0xff) + memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN); + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr); + + lbtf_geo_init(priv); +out: + return ret; +} + +/** + * lbtf_set_channel: Set the radio channel + * + * @priv A pointer to struct lbtf_private structure + * @channel The desired channel, or 0 to clear a locked channel + * + * Returns: 0 on success, error on failure + */ +int lbtf_set_channel(struct lbtf_private *priv, u8 channel) +{ + struct cmd_ds_802_11_rf_channel cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET); + cmd.channel = cpu_to_le16(channel); + + return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd); +} + +int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon) +{ + struct cmd_ds_802_11_beacon_set cmd; + int size; + + if (beacon->len > MRVL_MAX_BCN_SIZE) + return -1; + size = sizeof(cmd) - sizeof(cmd.beacon) + beacon->len; + cmd.hdr.size = cpu_to_le16(size); + cmd.len = cpu_to_le16(beacon->len); + memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len); + + lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size); + return 0; +} + +int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable, + int beacon_int) { + struct cmd_ds_802_11_beacon_control cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.beacon_enable = cpu_to_le16(beacon_enable); + cmd.beacon_period = cpu_to_le16(beacon_int); + + lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd)); + return 0; +} + +static void lbtf_queue_cmd(struct lbtf_private *priv, + struct cmd_ctrl_node *cmdnode) +{ + unsigned long flags; + + if (!cmdnode) + return; + + if (!cmdnode->cmdbuf->size) + return; + + cmdnode->result = 0; + spin_lock_irqsave(&priv->driver_lock, flags); + list_add_tail(&cmdnode->list, &priv->cmdpendingq); + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +static void lbtf_submit_command(struct lbtf_private *priv, + struct cmd_ctrl_node *cmdnode) +{ + unsigned long flags; + struct cmd_header *cmd; + uint16_t cmdsize; + uint16_t command; + int timeo = 5 * HZ; + int ret; + + cmd = cmdnode->cmdbuf; + + spin_lock_irqsave(&priv->driver_lock, flags); + priv->cur_cmd = cmdnode; + cmdsize = le16_to_cpu(cmd->size); + command = le16_to_cpu(cmd->command); + ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (ret) + /* Let the timer kick in and retry, and potentially reset + the whole thing if the condition persists */ + timeo = HZ; + + /* Setup the timer after transmit command */ + mod_timer(&priv->command_timer, jiffies + timeo); +} + +/** + * This function inserts command node to cmdfreeq + * after cleans it. Requires priv->driver_lock held. + */ +static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv, + struct cmd_ctrl_node *cmdnode) +{ + if (!cmdnode) + return; + + cmdnode->callback = NULL; + cmdnode->callback_arg = 0; + + memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE); + + list_add_tail(&cmdnode->list, &priv->cmdfreeq); +} + +static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv, + struct cmd_ctrl_node *ptempcmd) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->driver_lock, flags); + __lbtf_cleanup_and_insert_cmd(priv, ptempcmd); + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd, + int result) +{ + cmd->result = result; + cmd->cmdwaitqwoken = 1; + wake_up_interruptible(&cmd->cmdwait_q); + + if (!cmd->callback) + __lbtf_cleanup_and_insert_cmd(priv, cmd); + priv->cur_cmd = NULL; +} + +int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv) +{ + struct cmd_ds_mac_multicast_addr cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr); + memcpy(cmd.maclist, priv->multicastlist, + priv->nr_of_multicastmacaddr * ETH_ALEN); + + lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd)); + return 0; +} + +void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode) +{ + struct cmd_ds_set_mode cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.mode = cpu_to_le16(mode); + lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd)); +} + +void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid) +{ + struct cmd_ds_set_bssid cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.activate = activate ? 1 : 0; + if (activate) + memcpy(cmd.bssid, bssid, ETH_ALEN); + + lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd)); +} + +int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr) +{ + struct cmd_ds_802_11_mac_address cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + memcpy(cmd.macadd, mac_addr, ETH_ALEN); + + lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd)); + return 0; +} + +int lbtf_set_radio_control(struct lbtf_private *priv) +{ + int ret = 0; + struct cmd_ds_802_11_radio_control cmd; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + switch (priv->preamble) { + case CMD_TYPE_SHORT_PREAMBLE: + cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); + break; + + case CMD_TYPE_LONG_PREAMBLE: + cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); + break; + + case CMD_TYPE_AUTO_PREAMBLE: + default: + cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); + break; + } + + if (priv->radioon) + cmd.control |= cpu_to_le16(TURN_ON_RF); + else + cmd.control &= cpu_to_le16(~TURN_ON_RF); + + ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); + return ret; +} + +void lbtf_set_mac_control(struct lbtf_private *priv) +{ + struct cmd_ds_mac_control cmd; + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(priv->mac_control); + cmd.reserved = 0; + + lbtf_cmd_async(priv, CMD_MAC_CONTROL, + &cmd.hdr, sizeof(cmd)); +} + +/** + * lbtf_allocate_cmd_buffer - Allocates cmd buffer, links it to free cmd queue + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success. + */ +int lbtf_allocate_cmd_buffer(struct lbtf_private *priv) +{ + u32 bufsize; + u32 i; + struct cmd_ctrl_node *cmdarray; + + /* Allocate and initialize the command array */ + bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS; + cmdarray = kzalloc(bufsize, GFP_KERNEL); + if (!cmdarray) + return -1; + priv->cmd_array = cmdarray; + + /* Allocate and initialize each command buffer in the command array */ + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL); + if (!cmdarray[i].cmdbuf) + return -1; + } + + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + init_waitqueue_head(&cmdarray[i].cmdwait_q); + lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]); + } + return 0; +} + +/** + * lbtf_free_cmd_buffer - Frees the cmd buffer. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 + */ +int lbtf_free_cmd_buffer(struct lbtf_private *priv) +{ + struct cmd_ctrl_node *cmdarray; + unsigned int i; + + /* need to check if cmd array is allocated or not */ + if (priv->cmd_array == NULL) + return 0; + + cmdarray = priv->cmd_array; + + /* Release shared memory buffers */ + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + kfree(cmdarray[i].cmdbuf); + cmdarray[i].cmdbuf = NULL; + } + + /* Release cmd_ctrl_node */ + kfree(priv->cmd_array); + priv->cmd_array = NULL; + + return 0; +} + +/** + * lbtf_get_cmd_ctrl_node - Gets free cmd node from free cmd queue. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: pointer to a struct cmd_ctrl_node or NULL if none available. + */ +static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv) +{ + struct cmd_ctrl_node *tempnode; + unsigned long flags; + + if (!priv) + return NULL; + + spin_lock_irqsave(&priv->driver_lock, flags); + + if (!list_empty(&priv->cmdfreeq)) { + tempnode = list_first_entry(&priv->cmdfreeq, + struct cmd_ctrl_node, list); + list_del(&tempnode->list); + } else + tempnode = NULL; + + spin_unlock_irqrestore(&priv->driver_lock, flags); + + return tempnode; +} + +/** + * lbtf_execute_next_command: execute next command in cmd pending queue. + * + * @priv A pointer to struct lbtf_private structure + * + * Returns: 0 on success. + */ +int lbtf_execute_next_command(struct lbtf_private *priv) +{ + struct cmd_ctrl_node *cmdnode = NULL; + struct cmd_header *cmd; + unsigned long flags; + + /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the + * only caller to us is lbtf_thread() and we get even when a + * data packet is received */ + + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->cur_cmd) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + return -1; + } + + if (!list_empty(&priv->cmdpendingq)) { + cmdnode = list_first_entry(&priv->cmdpendingq, + struct cmd_ctrl_node, list); + } + + if (cmdnode) { + cmd = cmdnode->cmdbuf; + + list_del(&cmdnode->list); + spin_unlock_irqrestore(&priv->driver_lock, flags); + lbtf_submit_command(priv, cmdnode); + } else + spin_unlock_irqrestore(&priv->driver_lock, flags); + return 0; +} + +static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv, + uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbtf_private *, unsigned long, + struct cmd_header *), + unsigned long callback_arg) +{ + struct cmd_ctrl_node *cmdnode; + + if (priv->surpriseremoved) + return ERR_PTR(-ENOENT); + + cmdnode = lbtf_get_cmd_ctrl_node(priv); + if (cmdnode == NULL) { + /* Wake up main thread to execute next command */ + queue_work(lbtf_wq, &priv->cmd_work); + return ERR_PTR(-ENOBUFS); + } + + cmdnode->callback = callback; + cmdnode->callback_arg = callback_arg; + + /* Copy the incoming command to the buffer */ + memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size); + + /* Set sequence number, clean result, move to buffer */ + priv->seqnum++; + cmdnode->cmdbuf->command = cpu_to_le16(command); + cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size); + cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum); + cmdnode->cmdbuf->result = 0; + cmdnode->cmdwaitqwoken = 0; + lbtf_queue_cmd(priv, cmdnode); + queue_work(lbtf_wq, &priv->cmd_work); + + return cmdnode; +} + +void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size) +{ + __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0); +} + +int __lbtf_cmd(struct lbtf_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbtf_private *, + unsigned long, struct cmd_header *), + unsigned long callback_arg) +{ + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + int ret = 0; + + cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, + callback, callback_arg); + if (IS_ERR(cmdnode)) + return PTR_ERR(cmdnode); + + might_sleep(); + ret = wait_event_interruptible(cmdnode->cmdwait_q, + cmdnode->cmdwaitqwoken); + if (ret) { + printk(KERN_DEBUG + "libertastf: command 0x%04x interrupted by signal", + command); + return ret; + } + + spin_lock_irqsave(&priv->driver_lock, flags); + ret = cmdnode->result; + if (ret) + printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n", + command, ret); + + __lbtf_cleanup_and_insert_cmd(priv, cmdnode); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(__lbtf_cmd); + +/* Call holding driver_lock */ +void lbtf_cmd_response_rx(struct lbtf_private *priv) +{ + priv->cmd_response_rxed = 1; + queue_work(lbtf_wq, &priv->cmd_work); +} +EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx); + +int lbtf_process_rx_command(struct lbtf_private *priv) +{ + uint16_t respcmd, curcmd; + struct cmd_header *resp; + int ret = 0; + unsigned long flags; + uint16_t result; + + mutex_lock(&priv->lock); + spin_lock_irqsave(&priv->driver_lock, flags); + + if (!priv->cur_cmd) { + ret = -1; + spin_unlock_irqrestore(&priv->driver_lock, flags); + goto done; + } + + resp = (void *)priv->cmd_resp_buff; + curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); + respcmd = le16_to_cpu(resp->command); + result = le16_to_cpu(resp->result); + + if (net_ratelimit()) + printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n", + respcmd, le16_to_cpu(resp->seqnum), + le16_to_cpu(resp->size)); + + if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + if (respcmd != CMD_RET(curcmd)) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + + if (resp->result == cpu_to_le16(0x0004)) { + /* 0x0004 means -EAGAIN. Drop the response, let it time out + and be resubmitted */ + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + + /* Now we got response from FW, cancel the command timer */ + del_timer(&priv->command_timer); + priv->cmd_timed_out = 0; + if (priv->nr_retries) + priv->nr_retries = 0; + + /* If the command is not successful, cleanup and return failure */ + if ((result != 0 || !(respcmd & 0x8000))) { + /* + * Handling errors here + */ + switch (respcmd) { + case CMD_RET(CMD_GET_HW_SPEC): + case CMD_RET(CMD_802_11_RESET): + printk(KERN_DEBUG "libertastf: reset failed\n"); + break; + + } + lbtf_complete_command(priv, priv->cur_cmd, result); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + ret = -1; + goto done; + } + + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (priv->cur_cmd && priv->cur_cmd->callback) { + ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, + resp); + } + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->cur_cmd) { + /* Clean up and Put current command back to cmdfreeq */ + lbtf_complete_command(priv, priv->cur_cmd, result); + } + spin_unlock_irqrestore(&priv->driver_lock, flags); + +done: + mutex_unlock(&priv->lock); + return ret; +} -- cgit v1.2.3 From c305a19a0d0a47ac59a58865a4a63be65b1bf7c8 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 14 Aug 2008 10:41:06 -0700 Subject: libertas_tf: usb specific functions The libertas thin firmware only supports usb devices, but the usb functions have been kept separate to ease future support for other devices. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/if_usb.c | 766 ++++++++++++++++++++++++++++++ drivers/net/wireless/libertas_tf/if_usb.h | 98 ++++ 2 files changed, 864 insertions(+) create mode 100644 drivers/net/wireless/libertas_tf/if_usb.c create mode 100644 drivers/net/wireless/libertas_tf/if_usb.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c new file mode 100644 index 00000000000..1cc03a8dd67 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#include +#include +#include +#include +#include + +#define DRV_NAME "lbtf_usb" + +#include "libertas_tf.h" +#include "if_usb.h" + +#define MESSAGE_HEADER_LEN 4 + +static char *lbtf_fw_name = "lbtf_usb.bin"; +module_param_named(fw_name, lbtf_fw_name, charp, 0644); + +static struct usb_device_id if_usb_table[] = { + /* Enter the device signature inside */ + { USB_DEVICE(0x1286, 0x2001) }, + { USB_DEVICE(0x05a3, 0x8388) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, if_usb_table); + +static void if_usb_receive(struct urb *urb); +static void if_usb_receive_fwload(struct urb *urb); +static int if_usb_prog_firmware(struct if_usb_card *cardp); +static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb); +static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, + uint16_t nb, u8 data); +static void if_usb_free(struct if_usb_card *cardp); +static int if_usb_submit_rx_urb(struct if_usb_card *cardp); +static int if_usb_reset_device(struct if_usb_card *cardp); + +/** + * if_usb_wrike_bulk_callback - call back to handle URB status + * + * @param urb pointer to urb structure + */ +static void if_usb_write_bulk_callback(struct urb *urb) +{ + if (urb->status != 0) + printk(KERN_INFO "libertastf: URB in failure status: %d\n", + urb->status); +} + +/** + * if_usb_free - free tx/rx urb, skb and rx buffer + * + * @param cardp pointer if_usb_card + */ +static void if_usb_free(struct if_usb_card *cardp) +{ + /* Unlink tx & rx urb */ + usb_kill_urb(cardp->tx_urb); + usb_kill_urb(cardp->rx_urb); + usb_kill_urb(cardp->cmd_urb); + + usb_free_urb(cardp->tx_urb); + cardp->tx_urb = NULL; + + usb_free_urb(cardp->rx_urb); + cardp->rx_urb = NULL; + + usb_free_urb(cardp->cmd_urb); + cardp->cmd_urb = NULL; + + kfree(cardp->ep_out_buf); + cardp->ep_out_buf = NULL; +} + +static void if_usb_setup_firmware(struct lbtf_private *priv) +{ + struct if_usb_card *cardp = priv->card; + struct cmd_ds_set_boot2_ver b2_cmd; + + if_usb_submit_rx_urb(cardp); + b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd)); + b2_cmd.action = 0; + b2_cmd.version = cardp->boot2_version; + + if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd)) + printk(KERN_INFO "libertastf: setting boot2 version failed\n"); +} + +static void if_usb_fw_timeo(unsigned long priv) +{ + struct if_usb_card *cardp = (void *)priv; + + if (!cardp->fwdnldover) + /* Download timed out */ + cardp->priv->surpriseremoved = 1; + wake_up(&cardp->fw_wq); +} + +/** + * if_usb_probe - sets the configuration values + * + * @ifnum interface number + * @id pointer to usb_device_id + * + * Returns: 0 on success, error code on failure + */ +static int if_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct lbtf_private *priv; + struct if_usb_card *cardp; + int i; + + udev = interface_to_usbdev(intf); + + cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); + if (!cardp) + goto error; + + setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp); + init_waitqueue_head(&cardp->fw_wq); + + cardp->udev = udev; + iface_desc = intf->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_bulk_in(endpoint)) { + cardp->ep_in_size = + le16_to_cpu(endpoint->wMaxPacketSize); + cardp->ep_in = usb_endpoint_num(endpoint); + } else if (usb_endpoint_is_bulk_out(endpoint)) { + cardp->ep_out_size = + le16_to_cpu(endpoint->wMaxPacketSize); + cardp->ep_out = usb_endpoint_num(endpoint); + } + } + if (!cardp->ep_out_size || !cardp->ep_in_size) + /* Endpoints not found */ + goto dealloc; + + cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!cardp->rx_urb) + goto dealloc; + + cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!cardp->tx_urb) + goto dealloc; + + cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!cardp->cmd_urb) + goto dealloc; + + cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, + GFP_KERNEL); + if (!cardp->ep_out_buf) + goto dealloc; + + priv = lbtf_add_card(cardp, &udev->dev); + if (!priv) + goto dealloc; + + cardp->priv = priv; + + priv->hw_host_to_card = if_usb_host_to_card; + priv->hw_prog_firmware = if_usb_prog_firmware; + priv->hw_reset_device = if_usb_reset_device; + cardp->boot2_version = udev->descriptor.bcdDevice; + + usb_get_dev(udev); + usb_set_intfdata(intf, cardp); + + return 0; + +dealloc: + if_usb_free(cardp); +error: + return -ENOMEM; +} + +/** + * if_usb_disconnect - free resource and cleanup + * + * @intf USB interface structure + */ +static void if_usb_disconnect(struct usb_interface *intf) +{ + struct if_usb_card *cardp = usb_get_intfdata(intf); + struct lbtf_private *priv = (struct lbtf_private *) cardp->priv; + + if_usb_reset_device(cardp); + + if (priv) + lbtf_remove_card(priv); + + /* Unlink and free urb */ + if_usb_free(cardp); + + usb_set_intfdata(intf, NULL); + usb_put_dev(interface_to_usbdev(intf)); +} + +/** + * if_usb_send_fw_pkt - This function downloads the FW + * + * @priv pointer to struct lbtf_private + * + * Returns: 0 + */ +static int if_usb_send_fw_pkt(struct if_usb_card *cardp) +{ + struct fwdata *fwdata = cardp->ep_out_buf; + u8 *firmware = (u8 *) cardp->fw->data; + + /* If we got a CRC failure on the last block, back + up and retry it */ + if (!cardp->CRC_OK) { + cardp->totalbytes = cardp->fwlastblksent; + cardp->fwseqnum--; + } + + /* struct fwdata (which we sent to the card) has an + extra __le32 field in between the header and the data, + which is not in the struct fwheader in the actual + firmware binary. Insert the seqnum in the middle... */ + memcpy(&fwdata->hdr, &firmware[cardp->totalbytes], + sizeof(struct fwheader)); + + cardp->fwlastblksent = cardp->totalbytes; + cardp->totalbytes += sizeof(struct fwheader); + + memcpy(fwdata->data, &firmware[cardp->totalbytes], + le32_to_cpu(fwdata->hdr.datalength)); + + fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum); + cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength); + + usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) + + le32_to_cpu(fwdata->hdr.datalength), 0); + + if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) + /* Host has finished FW downloading + * Donwloading FW JUMP BLOCK + */ + cardp->fwfinalblk = 1; + + return 0; +} + +static int if_usb_reset_device(struct if_usb_card *cardp) +{ + struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4; + int ret; + + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); + + cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET); + cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset)); + cmd->hdr.result = cpu_to_le16(0); + cmd->hdr.seqnum = cpu_to_le16(0x5a5a); + cmd->action = cpu_to_le16(CMD_ACT_HALT); + usb_tx_block(cardp, cardp->ep_out_buf, + 4 + sizeof(struct cmd_ds_802_11_reset), 0); + + msleep(100); + ret = usb_reset_device(cardp->udev); + msleep(100); + + return ret; +} +EXPORT_SYMBOL_GPL(if_usb_reset_device); + +/** + * usb_tx_block - transfer data to the device + * + * @priv pointer to struct lbtf_private + * @payload pointer to payload data + * @nb data length + * @data non-zero for data, zero for commands + * + * Returns: 0 on success, nonzero otherwise. + */ +static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, + uint16_t nb, u8 data) +{ + struct urb *urb; + + /* check if device is removed */ + if (cardp->priv->surpriseremoved) + return -1; + + if (data) + urb = cardp->tx_urb; + else + urb = cardp->cmd_urb; + + usb_fill_bulk_urb(urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, + cardp->ep_out), + payload, nb, if_usb_write_bulk_callback, cardp); + + urb->transfer_flags |= URB_ZERO_PACKET; + + if (usb_submit_urb(urb, GFP_ATOMIC)) + return -1; + return 0; +} + +static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, + void (*callbackfn)(struct urb *urb)) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + if (!skb) + return -1; + + cardp->rx_skb = skb; + + /* Fill the receive configuration URB and initialise the Rx call back */ + usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, + usb_rcvbulkpipe(cardp->udev, cardp->ep_in), + (void *) (skb->tail), + MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); + + cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; + + if (usb_submit_urb(cardp->rx_urb, GFP_ATOMIC)) { + kfree_skb(skb); + cardp->rx_skb = NULL; + return -1; + } else + return 0; +} + +static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp) +{ + return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); +} + +static int if_usb_submit_rx_urb(struct if_usb_card *cardp) +{ + return __if_usb_submit_rx_urb(cardp, &if_usb_receive); +} + +static void if_usb_receive_fwload(struct urb *urb) +{ + struct if_usb_card *cardp = urb->context; + struct sk_buff *skb = cardp->rx_skb; + struct fwsyncheader *syncfwheader; + struct bootcmdresp bcmdresp; + + if (urb->status) { + kfree_skb(skb); + return; + } + + if (cardp->fwdnldover) { + __le32 *tmp = (__le32 *)(skb->data); + + if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && + tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) + /* Firmware ready event received */ + wake_up(&cardp->fw_wq); + else + if_usb_submit_rx_urb_fwload(cardp); + kfree_skb(skb); + return; + } + if (cardp->bootcmdresp <= 0) { + memcpy(&bcmdresp, skb->data, sizeof(bcmdresp)); + + if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { + kfree_skb(skb); + if_usb_submit_rx_urb_fwload(cardp); + cardp->bootcmdresp = 1; + /* Received valid boot command response */ + return; + } + if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { + if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) || + bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || + bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) + cardp->bootcmdresp = -1; + } else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB && + bcmdresp.result == BOOT_CMD_RESP_OK) + cardp->bootcmdresp = 1; + + kfree_skb(skb); + if_usb_submit_rx_urb_fwload(cardp); + return; + } + + syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); + if (!syncfwheader) { + kfree_skb(skb); + return; + } + + memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader)); + + if (!syncfwheader->cmd) + cardp->CRC_OK = 1; + else + cardp->CRC_OK = 0; + kfree_skb(skb); + + /* reschedule timer for 200ms hence */ + mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); + + if (cardp->fwfinalblk) { + cardp->fwdnldover = 1; + goto exit; + } + + if_usb_send_fw_pkt(cardp); + + exit: + if_usb_submit_rx_urb_fwload(cardp); + + kfree(syncfwheader); + + return; +} + +#define MRVDRV_MIN_PKT_LEN 30 + +static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, + struct if_usb_card *cardp, + struct lbtf_private *priv) +{ + if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN + || recvlength < MRVDRV_MIN_PKT_LEN) { + kfree_skb(skb); + return; + } + + skb_put(skb, recvlength); + skb_pull(skb, MESSAGE_HEADER_LEN); + lbtf_rx(priv, skb); +} + +static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, + struct sk_buff *skb, + struct if_usb_card *cardp, + struct lbtf_private *priv) +{ + if (recvlength > LBS_CMD_BUFFER_SIZE) { + kfree_skb(skb); + return; + } + + if (!in_interrupt()) + BUG(); + + spin_lock(&priv->driver_lock); + memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, + recvlength - MESSAGE_HEADER_LEN); + kfree_skb(skb); + lbtf_cmd_response_rx(priv); + spin_unlock(&priv->driver_lock); +} + +/** + * if_usb_receive - read data received from the device. + * + * @urb pointer to struct urb + */ +static void if_usb_receive(struct urb *urb) +{ + struct if_usb_card *cardp = urb->context; + struct sk_buff *skb = cardp->rx_skb; + struct lbtf_private *priv = cardp->priv; + int recvlength = urb->actual_length; + uint8_t *recvbuff = NULL; + uint32_t recvtype = 0; + __le32 *pkt = (__le32 *) skb->data; + + if (recvlength) { + if (urb->status) { + kfree_skb(skb); + goto setup_for_next; + } + + recvbuff = skb->data; + recvtype = le32_to_cpu(pkt[0]); + } else if (urb->status) { + kfree_skb(skb); + return; + } + + switch (recvtype) { + case CMD_TYPE_DATA: + process_cmdtypedata(recvlength, skb, cardp, priv); + break; + + case CMD_TYPE_REQUEST: + process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); + break; + + case CMD_TYPE_INDICATION: + { + /* Event cause handling */ + u32 event_cause = le32_to_cpu(pkt[1]); + + /* Icky undocumented magic special case */ + if (event_cause & 0xffff0000) { + u16 tmp; + u8 retrycnt; + u8 failure; + + tmp = event_cause >> 16; + retrycnt = tmp & 0x00ff; + failure = (tmp & 0xff00) >> 8; + lbtf_send_tx_feedback(priv, retrycnt, failure); + } else if (event_cause == LBTF_EVENT_BCN_SENT) + lbtf_bcn_sent(priv); + else + printk(KERN_DEBUG + "Unsupported notification %d received\n", + event_cause); + kfree_skb(skb); + break; + } + default: + printk(KERN_DEBUG "libertastf: unknown command type 0x%X\n", + recvtype); + kfree_skb(skb); + break; + } + +setup_for_next: + if_usb_submit_rx_urb(cardp); +} + +/** + * if_usb_host_to_card - Download data to the device + * + * @priv pointer to struct lbtf_private structure + * @type type of data + * @buf pointer to data buffer + * @len number of bytes + * + * Returns: 0 on success, nonzero otherwise + */ +static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb) +{ + struct if_usb_card *cardp = priv->card; + u8 data = 0; + + if (type == MVMS_CMD) { + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); + } else { + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA); + data = 1; + } + + memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb); + + return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN, + data); +} + +/** + * if_usb_issue_boot_command - Issue boot command to Boot2. + * + * @ivalue 1 boots from FW by USB-Download, 2 boots from FW in EEPROM. + * + * Returns: 0 + */ +static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) +{ + struct bootcmd *bootcmd = cardp->ep_out_buf; + + /* Prepare command */ + bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); + bootcmd->cmd = ivalue; + memset(bootcmd->pad, 0, sizeof(bootcmd->pad)); + + /* Issue command */ + usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd), 0); + + return 0; +} + + +/** + * check_fwfile_format - Check the validity of Boot2/FW image. + * + * @data pointer to image + * @totlen image length + * + * Returns: 0 if the image is valid, nonzero otherwise. + */ +static int check_fwfile_format(const u8 *data, u32 totlen) +{ + u32 bincmd, exit; + u32 blksize, offset, len; + int ret; + + ret = 1; + exit = len = 0; + + do { + struct fwheader *fwh = (void *) data; + + bincmd = le32_to_cpu(fwh->dnldcmd); + blksize = le32_to_cpu(fwh->datalength); + switch (bincmd) { + case FW_HAS_DATA_TO_RECV: + offset = sizeof(struct fwheader) + blksize; + data += offset; + len += offset; + if (len >= totlen) + exit = 1; + break; + case FW_HAS_LAST_BLOCK: + exit = 1; + ret = 0; + break; + default: + exit = 1; + break; + } + } while (!exit); + + if (ret) + printk(KERN_INFO + "libertastf: firmware file format check failed\n"); + return ret; +} + + +static int if_usb_prog_firmware(struct if_usb_card *cardp) +{ + int i = 0; + static int reset_count = 10; + int ret = 0; + + ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev); + if (ret < 0) { + printk(KERN_INFO "libertastf: firmware %s not found\n", + lbtf_fw_name); + goto done; + } + + if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) + goto release_fw; + +restart: + if (if_usb_submit_rx_urb_fwload(cardp) < 0) { + ret = -1; + goto release_fw; + } + + cardp->bootcmdresp = 0; + do { + int j = 0; + i++; + /* Issue Boot command = 1, Boot from Download-FW */ + if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); + /* wait for command response */ + do { + j++; + msleep_interruptible(100); + } while (cardp->bootcmdresp == 0 && j < 10); + } while (cardp->bootcmdresp == 0 && i < 5); + + if (cardp->bootcmdresp <= 0) { + if (--reset_count >= 0) { + if_usb_reset_device(cardp); + goto restart; + } + return -1; + } + + i = 0; + + cardp->totalbytes = 0; + cardp->fwlastblksent = 0; + cardp->CRC_OK = 1; + cardp->fwdnldover = 0; + cardp->fwseqnum = -1; + cardp->totalbytes = 0; + cardp->fwfinalblk = 0; + + /* Send the first firmware packet... */ + if_usb_send_fw_pkt(cardp); + + /* ... and wait for the process to complete */ + wait_event_interruptible(cardp->fw_wq, cardp->priv->surpriseremoved || + cardp->fwdnldover); + + del_timer_sync(&cardp->fw_timeout); + usb_kill_urb(cardp->rx_urb); + + if (!cardp->fwdnldover) { + printk(KERN_INFO "libertastf: failed to load fw," + " resetting device!\n"); + if (--reset_count >= 0) { + if_usb_reset_device(cardp); + goto restart; + } + + printk(KERN_INFO "libertastf: fw download failure\n"); + ret = -1; + goto release_fw; + } + + cardp->priv->fw_ready = 1; + + release_fw: + release_firmware(cardp->fw); + cardp->fw = NULL; + + if_usb_setup_firmware(cardp->priv); + + done: + return ret; +} +EXPORT_SYMBOL_GPL(if_usb_prog_firmware); + + +#define if_usb_suspend NULL +#define if_usb_resume NULL + +static struct usb_driver if_usb_driver = { + .name = DRV_NAME, + .probe = if_usb_probe, + .disconnect = if_usb_disconnect, + .id_table = if_usb_table, + .suspend = if_usb_suspend, + .resume = if_usb_resume, +}; + +static int __init if_usb_init_module(void) +{ + int ret = 0; + + ret = usb_register(&if_usb_driver); + return ret; +} + +static void __exit if_usb_exit_module(void) +{ + usb_deregister(&if_usb_driver); +} + +module_init(if_usb_init_module); +module_exit(if_usb_exit_module); + +MODULE_DESCRIPTION("8388 USB WLAN Thinfirm Driver"); +MODULE_AUTHOR("Cozybit Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/libertas_tf/if_usb.h b/drivers/net/wireless/libertas_tf/if_usb.h new file mode 100644 index 00000000000..6fa5b3f59ef --- /dev/null +++ b/drivers/net/wireless/libertas_tf/if_usb.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008, cozybit Inc. + * Copyright (C) 2003-2006, Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#include +#include + +struct lbtf_private; + +/** + * This file contains definition for USB interface. + */ +#define CMD_TYPE_REQUEST 0xF00DFACE +#define CMD_TYPE_DATA 0xBEADC0DE +#define CMD_TYPE_INDICATION 0xBEEFFACE + +#define BOOT_CMD_FW_BY_USB 0x01 +#define BOOT_CMD_FW_IN_EEPROM 0x02 +#define BOOT_CMD_UPDATE_BOOT2 0x03 +#define BOOT_CMD_UPDATE_FW 0x04 +#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* LVRM */ + +struct bootcmd { + __le32 magic; + uint8_t cmd; + uint8_t pad[11]; +}; + +#define BOOT_CMD_RESP_OK 0x0001 +#define BOOT_CMD_RESP_FAIL 0x0000 + +struct bootcmdresp { + __le32 magic; + uint8_t cmd; + uint8_t result; + uint8_t pad[2]; +}; + +/** USB card description structure*/ +struct if_usb_card { + struct usb_device *udev; + struct urb *rx_urb, *tx_urb, *cmd_urb; + struct lbtf_private *priv; + + struct sk_buff *rx_skb; + + uint8_t ep_in; + uint8_t ep_out; + + int8_t bootcmdresp; + + int ep_in_size; + + void *ep_out_buf; + int ep_out_size; + + const struct firmware *fw; + struct timer_list fw_timeout; + wait_queue_head_t fw_wq; + uint32_t fwseqnum; + uint32_t totalbytes; + uint32_t fwlastblksent; + uint8_t CRC_OK; + uint8_t fwdnldover; + uint8_t fwfinalblk; + + __le16 boot2_version; +}; + +/** fwheader */ +struct fwheader { + __le32 dnldcmd; + __le32 baseaddr; + __le32 datalength; + __le32 CRC; +}; + +#define FW_MAX_DATA_BLK_SIZE 600 +/** FWData */ +struct fwdata { + struct fwheader hdr; + __le32 seqnum; + uint8_t data[0]; +}; + +/** fwsyncheader */ +struct fwsyncheader { + __le32 cmd; + __le32 seqnum; +}; + +#define FW_HAS_DATA_TO_RECV 0x00000001 +#define FW_HAS_LAST_BLOCK 0x00000004 -- cgit v1.2.3 From d9c6350431d0c8cac000c6a230d9a20dad52e26d Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 14 Aug 2008 10:41:10 -0700 Subject: libertas_tf: config and makefile Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 13 +++++++++++++ drivers/net/wireless/Makefile | 2 ++ drivers/net/wireless/libertas_tf/Makefile | 6 ++++++ 3 files changed, 21 insertions(+) create mode 100644 drivers/net/wireless/libertas_tf/Makefile (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9931b5ab59c..1ac46ad48c3 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -300,6 +300,19 @@ config LIBERTAS_DEBUG ---help--- Debugging support. +config LIBERTAS_THINFIRM + tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" + depends on WLAN_80211 && MAC80211 + select FW_LOADER + ---help--- + A library for Marvell Libertas 8xxx devices using thinfirm. + +config LIBERTAS_THINFIRM_USB + tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware" + depends on LIBERTAS_THINFIRM && USB + ---help--- + A driver for Marvell Libertas 8388 USB devices using thinfirm. + config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 59aa89ec6e8..c05fd7627f3 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -48,6 +48,8 @@ obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o obj-$(CONFIG_USB_ZD1201) += zd1201.o 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 diff --git a/drivers/net/wireless/libertas_tf/Makefile b/drivers/net/wireless/libertas_tf/Makefile new file mode 100644 index 00000000000..ff5544d6ac9 --- /dev/null +++ b/drivers/net/wireless/libertas_tf/Makefile @@ -0,0 +1,6 @@ +libertas_tf-objs := main.o cmd.o + +libertas_tf_usb-objs += if_usb.o + +obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf.o +obj-$(CONFIG_LIBERTAS_THINFIRM_USB) += libertas_tf_usb.o -- cgit v1.2.3 From c94c93da90a9e46a73a5733ff8454fb4b14733fb Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 28 Jul 2008 23:01:34 -0700 Subject: wireless: replace __FUNCTION__ with __func__ __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 16 ++++++++-------- drivers/net/wireless/hermes.c | 2 +- drivers/net/wireless/ipw2100.c | 2 +- drivers/net/wireless/ipw2200.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-3945-debug.h | 4 ++-- drivers/net/wireless/libertas/if_cs.c | 2 +- drivers/net/wireless/prism54/isl_ioctl.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2x00.h | 4 ++-- drivers/net/wireless/wl3501_cs.c | 8 ++++---- 9 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index b5cd850a4a5..ae58a12befd 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1915,7 +1915,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct airo_info *ai = dev->priv; if (!skb) { - airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!",__func__); return 0; } npacks = skb_queue_len (&ai->txq); @@ -1964,7 +1964,7 @@ static int mpi_send_packet (struct net_device *dev) if ((skb = skb_dequeue(&ai->txq)) == NULL) { airo_print_err(dev->name, "%s: Dequeue'd zero in send_packet()", - __FUNCTION__); + __func__); return 0; } @@ -2115,7 +2115,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { u32 *fids = priv->fids; if ( skb == NULL ) { - airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!", __func__); return 0; } @@ -2186,7 +2186,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { } if ( skb == NULL ) { - airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!", __func__); return 0; } @@ -4127,7 +4127,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) airo_print_err(ai->dev->name, "%s: MAC should be disabled (rid=%04x)", - __FUNCTION__, rid); + __func__, rid); memset(&cmd, 0, sizeof(cmd)); memset(&rsp, 0, sizeof(rsp)); @@ -4142,7 +4142,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, &ai->config_desc.rid_desc, sizeof(Rid)); if (len < 4 || len > 2047) { - airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len); + airo_print_err(ai->dev->name, "%s: len=%d", __func__, len); rc = -1; } else { memcpy((char *)ai->config_desc.virtual_host_addr, @@ -4151,9 +4151,9 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, rc = issuecommand(ai, &cmd, &rsp); if ((rc & 0xff00) != 0) { airo_print_err(ai->dev->name, "%s: Write rid Error %d", - __FUNCTION__, rc); + __func__, rc); airo_print_err(ai->dev->name, "%s: Cmd=%04x", - __FUNCTION__, cmd.cmd); + __func__, cmd.cmd); } if ((rsp.status & 0x7f00)) diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 29d39105f5b..2cd86af1390 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -463,7 +463,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, if (rtype != rid) printk(KERN_WARNING "hermes @ %p: %s(): " "rid (0x%04x) does not match type (0x%04x)\n", - hw->iobase, __FUNCTION__, rid, rtype); + hw->iobase, __func__, rid, rtype); if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize) printk(KERN_WARNING "hermes @ %p: " "Truncating LTV record from %d to %d bytes. " diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 19a401c4a0d..bca74811bc7 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -211,7 +211,7 @@ static u32 ipw2100_debug_level = IPW_DL_NONE; do { \ if (ipw2100_debug_level & (level)) { \ printk(KERN_DEBUG "ipw2100: %c %s ", \ - in_interrupt() ? 'I' : 'U', __FUNCTION__); \ + in_interrupt() ? 'I' : 'U', __func__); \ printk(message); \ } \ } while (0) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index d4ab28b73b3..0bad1ec3e7e 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1394,13 +1394,13 @@ BIT_ARG16(x) #define IPW_DEBUG(level, fmt, args...) \ do { if (ipw_debug_level & (level)) \ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #ifdef CONFIG_IPW2200_DEBUG #define IPW_LL_DEBUG(level, fmt, args...) \ do { if (ipw_debug_level & (level)) \ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #else #define IPW_LL_DEBUG(level, fmt, args...) do {} while (0) #endif /* CONFIG_IPW2200_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index f1d002f7b79..33016fb5e9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -34,12 +34,12 @@ extern u32 iwl3945_debug_level; #define IWL_DEBUG(level, fmt, args...) \ do { if (iwl3945_debug_level & (level)) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) static inline void iwl3945_print_hex_dump(int level, void *p, u32 len) { diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 04d7a251e3f..92837a2dd6d 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -720,7 +720,7 @@ static int if_cs_host_to_card(struct lbs_private *priv, ret = if_cs_send_cmd(priv, buf, nb); break; default: - lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type); + lbs_pr_err("%s: unsupported type %d\n", __func__, type); } lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 3d75a7137d3..16e68f4b654 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -71,7 +71,7 @@ prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { printk(KERN_DEBUG "%s(): Sorry, Repeater mode and Secondary mode " - "are not yet supported by this driver.\n", __FUNCTION__); + "are not yet supported by this driver.\n", __func__); return -EINVAL; } @@ -333,7 +333,7 @@ prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { printk(KERN_DEBUG "%s: %s() You passed a non-valid init_mode.\n", - priv->ndev->name, __FUNCTION__); + priv->ndev->name, __func__); return -EINVAL; } @@ -1234,7 +1234,7 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, /* don't know how to disable radio */ printk(KERN_DEBUG "%s: %s() disabling radio is not yet supported.\n", - priv->ndev->name, __FUNCTION__); + priv->ndev->name, __func__); return -ENOTSUPP; } else if (vwrq->fixed) /* currently only fixed value is supported */ @@ -1242,7 +1242,7 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, else { printk(KERN_DEBUG "%s: %s() auto power will be implemented later.\n", - priv->ndev->name, __FUNCTION__); + priv->ndev->name, __func__); return -ENOTSUPP; } } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8b10ea41b20..82c28dcc471 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -53,11 +53,11 @@ */ #define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \ printk(__kernlvl "%s -> %s: %s - " __msg, \ - wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args) + wiphy_name((__dev)->hw->wiphy), __func__, __lvl, ##__args) #define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \ printk(__kernlvl "%s -> %s: %s - " __msg, \ - KBUILD_MODNAME, __FUNCTION__, __lvl, ##__args) + KBUILD_MODNAME, __func__, __lvl, ##__args) #ifdef CONFIG_RT2X00_DEBUG #define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 377141995e3..b6d4e04b8ab 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -79,7 +79,7 @@ static int pc_debug = PCMCIA_DEBUG; module_param(pc_debug, int, 0); #define dprintk(n, format, args...) \ { if (pc_debug > (n)) \ - printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##args); } + printk(KERN_INFO "%s: " format "\n", __func__ , ##args); } #else #define dprintk(n, format, args...) #endif @@ -470,7 +470,7 @@ static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) spin_unlock_irqrestore(&this->lock, flags); rc = wait_event_interruptible(this->wait, this->sig_pwr_mgmt_confirm.status != 255); - printk(KERN_INFO "%s: %s status=%d\n", __FUNCTION__, + printk(KERN_INFO "%s: %s status=%d\n", __func__, suspend ? "suspend" : "resume", this->sig_pwr_mgmt_confirm.status); goto out; @@ -1199,7 +1199,7 @@ static int wl3501_reset_board(struct wl3501_card *this) } WL3501_NOPLOOP(10); } - printk(KERN_WARNING "%s: failed to reset the board!\n", __FUNCTION__); + printk(KERN_WARNING "%s: failed to reset the board!\n", __func__); rc = -ENODEV; out: return rc; @@ -1250,7 +1250,7 @@ static int wl3501_init_firmware(struct wl3501_card *this) out: return rc; fail: - printk(KERN_WARNING "%s: failed!\n", __FUNCTION__); + printk(KERN_WARNING "%s: failed!\n", __func__); goto out; } -- cgit v1.2.3 From 2bb057d07a0bc17475a7bf897fc41667ab08b73f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:37:44 +0200 Subject: rt2x00: Implement HW encryption Various rt2x00 devices support hardware encryption. Most of them require the IV/EIV to be generated by mac80211, but require it to be provided seperately instead of within the frame itself. This means that rt2x00lib should extract the data from the frame and place it in the frame descriptor. During RX the IV/EIV is provided in the descriptor by the hardware which means that it should be inserted into the frame by rt2x00lib. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 4 + drivers/net/wireless/rt2x00/Makefile | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 39 +++++- drivers/net/wireless/rt2x00/rt2x00crypto.c | 215 +++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00debug.c | 97 +++++++++++++ drivers/net/wireless/rt2x00/rt2x00dev.c | 30 +++- drivers/net/wireless/rt2x00/rt2x00lib.h | 47 +++++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 110 +++++++++++++-- drivers/net/wireless/rt2x00/rt2x00queue.c | 81 +++++++++-- drivers/net/wireless/rt2x00/rt2x00queue.h | 73 +++++++++- drivers/net/wireless/rt2x00/rt2x00reg.h | 19 ++- 11 files changed, 686 insertions(+), 30 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2x00crypto.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index d485a86bba7..2f60e175f03 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -33,6 +33,10 @@ config RT2X00_LIB_FIRMWARE depends on RT2X00_LIB select FW_LOADER +config RT2X00_LIB_CRYPTO + boolean + depends on RT2X00_LIB + config RT2X00_LIB_RFKILL boolean depends on RT2X00_LIB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 1087dbcf1a0..917cb4f3b03 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -3,6 +3,7 @@ rt2x00lib-y += rt2x00mac.o rt2x00lib-y += rt2x00config.o rt2x00lib-y += rt2x00queue.o rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o +rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 82c28dcc471..0ffd972bb85 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -451,6 +451,23 @@ struct rt2x00lib_erp { int ack_consume_time; }; +/* + * Configuration structure for hardware encryption. + */ +struct rt2x00lib_crypto { + enum cipher cipher; + + enum set_key_cmd cmd; + const u8 *address; + + u32 bssidx; + u32 aid; + + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +}; + /* * Configuration structure wrapper around the * rt2x00 interface configuration handler. @@ -547,6 +564,12 @@ struct rt2x00lib_ops { /* * Configuration handlers. */ + int (*config_shared_key) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); + int (*config_pairwise_key) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); void (*config_filter) (struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags); void (*config_intf) (struct rt2x00_dev *rt2x00dev, @@ -609,7 +632,7 @@ enum rt2x00_flags { DEVICE_DIRTY_CONFIG, /* - * Driver features + * Driver requirements */ DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, @@ -618,9 +641,14 @@ enum rt2x00_flags { DRIVER_REQUIRE_DMA, /* - * Driver configuration + * Driver features */ CONFIG_SUPPORT_HW_BUTTON, + CONFIG_SUPPORT_HW_CRYPTO, + + /* + * Driver configuration + */ CONFIG_FRAME_TYPE, CONFIG_RF_SEQUENCE, CONFIG_EXTERNAL_LNA_A, @@ -966,6 +994,13 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); +#ifdef CONFIG_RT2X00_LIB_CRYPTO +int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key); +#else +#define rt2x00mac_set_key NULL +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c new file mode 100644 index 00000000000..e1448cfa944 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -0,0 +1,215 @@ +/* + Copyright (C) 2004 - 2008 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 crypto specific routines. + */ + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) +{ + switch (key->alg) { + case ALG_WEP: + if (key->keylen == LEN_WEP40) + return CIPHER_WEP64; + else + return CIPHER_WEP128; + case ALG_TKIP: + return CIPHER_TKIP; + case ALG_CCMP: + return CIPHER_AES; + default: + return CIPHER_NONE; + } +} + +unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_key_conf *key = tx_info->control.hw_key; + unsigned int overhead = 0; + + /* + * Extend frame length to include IV/EIV/ICV/MMIC, + * note that these lengths should only be added when + * mac80211 does not generate it. + */ + overhead += tx_info->control.icv_len; + + if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + overhead += tx_info->control.iv_len; + + if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { + if (key->alg == ALG_TKIP) + overhead += 8; + } + + return overhead; +} + +void rt2x00crypto_tx_remove_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 */ + 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); + + /* Move ieee80211 header */ + memmove(skb->data + iv_len, skb->data, header_length); + + /* Pull buffer to correct size */ + skb_pull(skb, iv_len); + + /* IV/EIV data has officially be stripped */ + skbdesc->flags |= FRAME_DESC_IV_STRIPPED; +} + +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); + + if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) + return; + + skb_push(skb, iv_len); + + /* Move ieee80211 header */ + 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); + + /* IV/EIV data has returned into the frame */ + skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; +} + +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, + unsigned int header_length, + struct rxdone_entry_desc *rxdesc) +{ + unsigned int payload_len = rxdesc->size - header_length; + unsigned int iv_len; + unsigned int icv_len; + unsigned int transfer = 0; + + /* + * WEP64/WEP128: Provides IV & ICV + * TKIP: Provides IV/EIV & ICV + * AES: Provies IV/EIV & ICV + */ + switch (rxdesc->cipher) { + case CIPHER_WEP64: + case CIPHER_WEP128: + iv_len = 4; + icv_len = 4; + break; + case CIPHER_TKIP: + iv_len = 8; + icv_len = 4; + break; + case CIPHER_AES: + iv_len = 8; + icv_len = 8; + break; + default: + /* Unsupport type */ + return; + } + + /* + * Make room for new data, note that we increase both + * headsize and tailsize when required. The tailsize is + * only needed when ICV data needs to be inserted and + * the padding is smaller then the ICV data. + * When alignment requirements is greater then the + * ICV data we must trim the skb to the correct size + * because we need to remove the extra bytes. + */ + skb_push(skb, iv_len + align); + if (align < icv_len) + skb_put(skb, icv_len - align); + else if (align > icv_len) + skb_trim(skb, rxdesc->size + iv_len + icv_len); + + /* Move ieee80211 header */ + memmove(skb->data + transfer, + skb->data + transfer + iv_len + 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; + } + + /* Move payload */ + if (align) { + memmove(skb->data + transfer, + skb->data + transfer + align, + payload_len); + } + + /* + * NOTE: Always count the payload as transfered, + * even when alignment was set to zero. This is required + * for determining the correct offset for the ICV data. + */ + 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; + } + + /* IV/EIV/ICV has been inserted into frame */ + rxdesc->size = transfer; + rxdesc->flags &= ~RX_FLAG_IV_STRIPPED; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 6bee1d611bb..5cf4c859e39 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -35,6 +35,13 @@ #define MAX_LINE_LENGTH 64 +struct rt2x00debug_crypto { + unsigned long success; + unsigned long icv_error; + unsigned long mic_error; + unsigned long key_error; +}; + struct rt2x00debug_intf { /* * Pointer to driver structure where @@ -63,6 +70,7 @@ struct rt2x00debug_intf { * - queue folder * - frame dump file * - queue stats file + * - crypto stats file */ struct dentry *driver_folder; struct dentry *driver_entry; @@ -80,6 +88,7 @@ struct rt2x00debug_intf { struct dentry *queue_folder; struct dentry *queue_frame_dump_entry; struct dentry *queue_stats_entry; + struct dentry *crypto_stats_entry; /* * The frame dump file only allows a single reader, @@ -97,6 +106,12 @@ struct rt2x00debug_intf { struct sk_buff_head frame_dump_skbqueue; wait_queue_head_t frame_dump_waitqueue; + /* + * HW crypto statistics. + * All statistics are stored seperately per cipher type. + */ + struct rt2x00debug_crypto crypto_stats[CIPHER_MAX]; + /* * Driver and chipset files will use a data buffer * that has been created in advance. This will simplify @@ -114,6 +129,25 @@ struct rt2x00debug_intf { unsigned int offset_rf; }; +void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, + enum cipher cipher, enum rx_crypto status) +{ + struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; + + if (cipher == CIPHER_TKIP_NO_MIC) + cipher = CIPHER_TKIP; + if (cipher == CIPHER_NONE || cipher > CIPHER_MAX) + return; + + /* Remove CIPHER_NONE index */ + cipher--; + + intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS); + intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV); + intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC); + intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY); +} + void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, enum rt2x00_dump_type type, struct sk_buff *skb) { @@ -327,6 +361,59 @@ static const struct file_operations rt2x00debug_fop_queue_stats = { .release = rt2x00debug_file_release, }; +#ifdef CONFIG_RT2X00_LIB_CRYPTO +static ssize_t rt2x00debug_read_crypto_stats(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + char *name[] = { "WEP64", "WEP128", "TKIP", "AES" }; + char *data; + char *temp; + size_t size; + unsigned int i; + + if (*offset) + return 0; + + data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL); + if (!data) + return -ENOMEM; + + temp = data; + temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n"); + + for (i = 0; i < CIPHER_MAX; i++) { + temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i], + intf->crypto_stats[i].success, + intf->crypto_stats[i].icv_error, + intf->crypto_stats[i].mic_error, + intf->crypto_stats[i].key_error); + } + + size = strlen(data); + size = min(size, length); + + if (copy_to_user(buf, data, size)) { + kfree(data); + return -EFAULT; + } + + kfree(data); + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_crypto_stats = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_crypto_stats, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, +}; +#endif + #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ static ssize_t rt2x00debug_read_##__name(struct file *file, \ char __user *buf, \ @@ -569,6 +656,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) debugfs_create_file("queue", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_stats); +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + intf->crypto_stats_entry = + debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, + intf, &rt2x00debug_fop_crypto_stats); +#endif + return; exit: @@ -587,6 +681,9 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) skb_queue_purge(&intf->frame_dump_skbqueue); +#ifdef CONFIG_RT2X00_LIB_CRYPTO + debugfs_remove(intf->crypto_stats_entry); +#endif debugfs_remove(intf->queue_stats_entry); debugfs_remove(intf->queue_frame_dump_entry); debugfs_remove(intf->queue_folder); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f42283ad7b0..182952249a1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -507,6 +507,15 @@ void rt2x00lib_txdone(struct queue_entry *entry, */ rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + /* + * If the IV/EIV data was stripped from the frame before it was + * passed to the hardware, we should now reinsert it again because + * mac80211 will expect the the same data to be present it the + * frame as it was passed to us. + */ + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + rt2x00crypto_tx_insert_iv(entry->skb); + /* * Send frame to debugfs immediately, after this call is completed * we are going to overwrite the skb->cb array. @@ -585,7 +594,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; const struct rt2x00_rate *rate; - unsigned int header_size; + unsigned int header_length; unsigned int align; unsigned int i; int idx = -1; @@ -613,10 +622,19 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ - header_size = ieee80211_get_hdrlen_from_skb(entry->skb); - align = ((unsigned long)(entry->skb->data + header_size)) & 3; + header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + align = ((unsigned long)(entry->skb->data + header_length)) & 3; - if (align) { + /* + * Hardware might have stripped the IV/EIV/ICV data, + * in that case it is possible that the data was + * provided seperately (through hardware descriptor) + * in which case we should reinsert the data into the frame. + */ + if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) { + rt2x00crypto_rx_insert_iv(entry->skb, align, + header_length, &rxdesc); + } else if (align) { skb_push(entry->skb, align); /* Move entire frame in 1 command */ memmove(entry->skb->data, entry->skb->data + align, @@ -657,6 +675,10 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, (rxdesc.dev_flags & RXDONE_MY_BSS)) rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi); + rt2x00debug_update_crypto(rt2x00dev, + rxdesc.cipher, + rxdesc.cipher_status); + rt2x00dev->link.qual.rx_success++; rx_status->mactime = rxdesc.timestamp; diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index c5fb3a72cf3..7bbc16b1b6c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -181,6 +181,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, enum rt2x00_dump_type type, struct sk_buff *skb); +void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, + enum cipher cipher, enum rx_crypto status); #else static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { @@ -195,8 +197,53 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { } + +static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, + enum cipher cipher, + enum rx_crypto status) +{ +} #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +/* + * Crypto handlers. + */ +#ifdef CONFIG_RT2X00_LIB_CRYPTO +enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); +unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); +void rt2x00crypto_tx_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, + unsigned int header_length, + struct rxdone_entry_desc *rxdesc); +#else +static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) +{ + return CIPHER_NONE; +} + +static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) +{ + return 0; +} + +static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, + unsigned int iv_len) +{ +} + +static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +{ +} + +static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, + unsigned int align, + unsigned int header_length, + struct rxdone_entry_desc *rxdesc) +{ +} +#endif + /* * RFkill handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4b9fde903cd..3af42733941 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -36,22 +36,22 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); struct ieee80211_tx_info *rts_info; struct sk_buff *skb; - int size; + unsigned int data_length; int retval = 0; if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) - size = sizeof(struct ieee80211_cts); + data_length = sizeof(struct ieee80211_cts); else - size = sizeof(struct ieee80211_rts); + data_length = sizeof(struct ieee80211_rts); - skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); + skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom); if (unlikely(!skb)) { WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); return -ENOMEM; } skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); - skb_put(skb, size); + skb_put(skb, data_length); /* * Copy TX information over from original frame to @@ -64,7 +64,6 @@ 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->control.hw_key = NULL; rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; @@ -74,13 +73,24 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + skb->do_not_encrypt = 1; + + /* + * 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) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, - frag_skb->data, size, tx_info, + frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); else ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, - frag_skb->data, size, tx_info, + frag_skb->data, data_length, tx_info, (struct ieee80211_rts *)(skb->data)); retval = rt2x00queue_write_tx_frame(queue, skb); @@ -464,6 +474,90 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); +#ifdef CONFIG_RT2X00_LIB_CRYPTO +int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + 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)) + return -EOPNOTSUPP; + else if (key->keylen > 32) + return -ENOSPC; + + memset(&crypto, 0, sizeof(crypto)); + + /* + * When in STA mode, bssidx is always 0 otherwise local_address[5] + * contains the bss number, see BSS_ID_MASK comments for details. + */ + if (rt2x00dev->intf_sta_count) + crypto.bssidx = 0; + else + crypto.bssidx = + local_address[5] & (rt2x00dev->ops->max_ap_intf - 1); + + crypto.cipher = rt2x00crypto_key_to_cipher(key); + if (crypto.cipher == CIPHER_NONE) + return -EOPNOTSUPP; + + crypto.cmd = cmd; + crypto.address = address; + + if (crypto.cipher == CIPHER_TKIP) { + if (key->keylen > NL80211_TKIP_DATA_OFFSET_ENCR_KEY) + memcpy(&crypto.key, + &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY], + sizeof(crypto.key)); + + if (key->keylen > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(&crypto.tx_mic, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + sizeof(crypto.tx_mic)); + + if (key->keylen > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY) + memcpy(&crypto.rx_mic, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + sizeof(crypto.rx_mic)); + } else + memcpy(&crypto.key, &key->key[0], key->keylen); + + /* + * Each BSS has a maximum of 4 shared keys. + * Shared key index values: + * 0) BSS0 key0 + * 1) BSS0 key1 + * ... + * 4) BSS1 key0 + * ... + * 8) BSS2 key0 + * ... + * Both pairwise as shared key indeces are determined by + * driver. This is required because the hardware requires + * keys to be assigned in correct order (When key 1 is + * provided but key 0 is not, then the key is not found + * by the hardware during RX). + */ + key->hw_key_idx = 0; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + set_key = rt2x00dev->ops->lib->config_pairwise_key; + else + set_key = rt2x00dev->ops->lib->config_shared_key; + + if (!set_key) + return -EOPNOTSUPP; + + return set_key(rt2x00dev, &crypto, key); +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_key); +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ + int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 898cdd7f57d..c0f97c53e5c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,10 +33,11 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { - unsigned int frame_size; - unsigned int reserved_size; struct sk_buff *skb; struct skb_frame_desc *skbdesc; + unsigned int frame_size; + unsigned int head_size = 0; + unsigned int tail_size = 0; /* * The frame size includes descriptor size, because the @@ -49,16 +50,32 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, * this means we need at least 3 bytes for moving the frame * into the correct offset. */ - reserved_size = 4; + head_size = 4; + + /* + * 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. + */ +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + head_size += 8; + tail_size += 4; + } +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Allocate skbuffer. */ - skb = dev_alloc_skb(frame_size + reserved_size); + skb = dev_alloc_skb(frame_size + head_size + tail_size); if (!skb) return NULL; - skb_reserve(skb, reserved_size); + /* + * Make sure we not have a frame with the requested bytes + * available in the head and tail. + */ + skb_reserve(skb, head_size); skb_put(skb, frame_size); /* @@ -140,7 +157,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 should be extended with 4 bytes for CRC */ + /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */ data_length = entry->skb->len + 4; /* @@ -149,6 +166,35 @@ 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); + + /* + * 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 */ @@ -305,6 +351,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; + unsigned int iv_len = IEEE80211_SKB_CB(skb)->control.iv_len; if (unlikely(rt2x00queue_full(queue))) return -EINVAL; @@ -326,15 +373,33 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) rt2x00queue_create_tx_descriptor(entry, &txdesc); /* - * skb->cb array is now ours and we are free to use it. + * All information is retreived from the skb->cb array, + * now we should claim ownership of the driver part of that + * array. */ skbdesc = get_skb_frame_desc(entry->skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; + /* + * When hardware encryption is supported, and this frame + * is to be encrypted, we should strip the IV/EIV data from + * the frame so we can provide it to the driver seperately. + */ + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) + rt2x00crypto_tx_remove_iv(skb, iv_len); + + /* + * 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. + */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - return -EIO; + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; + return 0; } if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index ff78e52ce43..37f3f98d58a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -87,10 +87,13 @@ enum data_queue_qid { * * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX + * @FRAME_DESC_IV_STRIPPED: Frame contained a IV/EIV provided by + * mac80211 but was stripped for processing by the driver. */ enum skb_frame_desc_flags { - SKBDESC_DMA_MAPPED_RX = (1 << 0), - SKBDESC_DMA_MAPPED_TX = (1 << 1), + SKBDESC_DMA_MAPPED_RX = 1 << 0, + SKBDESC_DMA_MAPPED_TX = 1 << 1, + FRAME_DESC_IV_STRIPPED = 1 << 2, }; /** @@ -104,6 +107,8 @@ enum skb_frame_desc_flags { * @desc: Pointer to descriptor part of the frame. * Note that this pointer could point to something outside * of the scope of the skb->data pointer. + * @iv: IV data used during encryption/decryption. + * @eiv: EIV data used during encryption/decryption. * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. * @entry: The entry to which this sk buffer belongs. */ @@ -113,6 +118,9 @@ struct skb_frame_desc { unsigned int desc_len; void *desc; + __le32 iv; + __le32 eiv; + dma_addr_t skb_dma; struct queue_entry *entry; @@ -152,7 +160,11 @@ enum rxdone_entry_desc_flags { * @size: Data size of the received frame. * @flags: MAC80211 receive flags (See &enum mac80211_rx_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. + * @icv: ICV data used during decryption. */ struct rxdone_entry_desc { u64 timestamp; @@ -161,6 +173,12 @@ struct rxdone_entry_desc { int size; int flags; int dev_flags; + u8 cipher; + u8 cipher_status; + + __le32 iv; + __le32 eiv; + __le32 icv; }; /** @@ -206,6 +224,10 @@ struct txdone_entry_desc { * @ENTRY_TXD_BURST: This frame belongs to the same burst event. * @ENTRY_TXD_ACK: An ACK is required for this frame. * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used. + * @ENTRY_TXD_ENCRYPT: This frame should be encrypted. + * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared). + * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware. + * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, @@ -218,6 +240,10 @@ enum txentry_desc_flags { ENTRY_TXD_BURST, ENTRY_TXD_ACK, ENTRY_TXD_RETRY_MODE, + ENTRY_TXD_ENCRYPT, + ENTRY_TXD_ENCRYPT_PAIRWISE, + ENTRY_TXD_ENCRYPT_IV, + ENTRY_TXD_ENCRYPT_MMIC, }; /** @@ -236,6 +262,9 @@ enum txentry_desc_flags { * @ifs: IFS value. * @cw_min: cwmin value. * @cw_max: cwmax value. + * @cipher: Cipher type used for encryption. + * @key_idx: Key index used for encryption. + * @iv_offset: Position where IV should be inserted by hardware. */ struct txentry_desc { unsigned long flags; @@ -252,6 +281,10 @@ struct txentry_desc { short ifs; short cw_min; short cw_max; + + enum cipher cipher; + u16 key_idx; + u16 iv_offset; }; /** @@ -484,25 +517,51 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) } /** - * rt2x00_desc_read - Read a word from the hardware descriptor. + * _rt2x00_desc_read - Read a word from the hardware descriptor. + * @desc: Base descriptor address + * @word: Word index from where the descriptor should be read. + * @value: Address where the descriptor value should be written into. + */ +static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) +{ + *value = desc[word]; +} + +/** + * rt2x00_desc_read - Read a word from the hardware descriptor, this + * function will take care of the byte ordering. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. * @value: Address where the descriptor value should be written into. */ static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) { - *value = le32_to_cpu(desc[word]); + __le32 tmp; + _rt2x00_desc_read(desc, word, &tmp); + *value = le32_to_cpu(tmp); +} + +/** + * rt2x00_desc_write - write a word to the hardware descriptor, this + * function will take care of the byte ordering. + * @desc: Base descriptor address + * @word: Word index from where the descriptor should be written. + * @value: Value that should be written into the descriptor. + */ +static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value) +{ + desc[word] = value; } /** - * rt2x00_desc_write - wrote a word to the hardware descriptor. + * rt2x00_desc_write - write a word to the hardware descriptor. * @desc: Base descriptor address * @word: Word index from where the descriptor should be written. * @value: Value that should be written into the descriptor. */ static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value) { - desc[word] = cpu_to_le32(value); + _rt2x00_desc_write(desc, word, cpu_to_le32(value)); } #endif /* RT2X00QUEUE_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 7e88ce5651b..6d5acf99a1c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -26,6 +26,16 @@ #ifndef RT2X00REG_H #define RT2X00REG_H +/* + * RX crypto status + */ +enum rx_crypto { + RX_CRYPTO_SUCCESS = 0, + RX_CRYPTO_FAIL_ICV = 1, + RX_CRYPTO_FAIL_MIC = 2, + RX_CRYPTO_FAIL_KEY = 3, +}; + /* * Antenna values */ @@ -104,7 +114,14 @@ enum cipher { */ CIPHER_CKIP64 = 5, CIPHER_CKIP128 = 6, - CIPHER_TKIP_NO_MIC = 7, + CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */ + +/* + * Max cipher type. + * Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128 + * are excluded due to limitations in mac80211. + */ + CIPHER_MAX = 4, }; /* -- cgit v1.2.3 From 61e754f44b57060464b1fcf261a8428ecfa23bed Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:38:02 +0200 Subject: rt2x00: Implement HW encryption (rt61pci) rt61pci supports hardware encryption. rt61pci supports up to 4 shared keys and up to 64 pairwise keys. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 1 + drivers/net/wireless/rt2x00/rt61pci.c | 256 +++++++++++++++++++++++++++++++++- drivers/net/wireless/rt2x00/rt61pci.h | 21 ++- 3 files changed, 270 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 2f60e175f03..f333f6100d0 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -107,6 +107,7 @@ config RT61PCI depends on PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO select CRC_ITU_T select EEPROM_93CX6 ---help--- diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 087e90b328c..86e7a50374b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -346,6 +346,204 @@ static void rt61pci_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ +static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for shared keys. We have 1 register + * with key valid bits. The goal is simple, read + * the register, if that is full we have no slots + * left. + * Note that each BSS is allowed to have up to 4 + * shared keys, so put a mask over the allowed + * entries. + */ + mask = (0xf << crypto->bssidx); + + rt2x00pci_register_read(rt2x00dev, SEC_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = SHARED_KEY_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, reg, + &key_entry, sizeof(key_entry)); + + /* + * The cipher types are stored over 2 registers. + * bssidx 0 and 1 keys are stored in SEC_CSR1 and + * bssidx 1 and 2 keys are stored in SEC_CSR5. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + if (key->hw_key_idx < 8) { + field.bit_offset = (3 * key->hw_key_idx); + field.bit_mask = 0x7 << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt2x00pci_register_write(rt2x00dev, SEC_CSR1, reg); + } else { + field.bit_offset = (3 * (key->hw_key_idx - 8)); + field.bit_mask = 0x7 << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt2x00pci_register_write(rt2x00dev, SEC_CSR5, reg); + } + + /* + * 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; + } + + /* + * SEC_CSR0 contains only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + mask = 1 << key->hw_key_idx; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR0, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt2x00pci_register_write(rt2x00dev, SEC_CSR0, reg); + + return 0; +} + +static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_pairwise_ta_entry addr_entry; + struct hw_key_entry key_entry; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for pairwise keys. We have 2 registers + * with key valid bits. The goal is simple, read + * the first register, if that is full move to + * the next register. + * When both registers are full, we drop the key, + * otherwise we use the first invalid entry. + */ + rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); + if (reg && reg == ~0) { + key->hw_key_idx = 32; + rt2x00pci_register_read(rt2x00dev, SEC_CSR3, ®); + if (reg && reg == ~0) + return -ENOSPC; + } + + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + memset(&addr_entry, 0, sizeof(addr_entry)); + memcpy(&addr_entry, crypto->address, ETH_ALEN); + addr_entry.cipher = crypto->cipher; + + reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, reg, + &key_entry, sizeof(key_entry)); + + reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, reg, + &addr_entry, sizeof(addr_entry)); + + /* + * Enable pairwise lookup table for given BSS idx, + * without this received frames will not be decrypted + * by the hardware. + */ + rt2x00pci_register_read(rt2x00dev, SEC_CSR4, ®); + reg |= (1 << crypto->bssidx); + rt2x00pci_register_write(rt2x00dev, SEC_CSR4, reg); + + /* + * 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; + } + + /* + * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + if (key->hw_key_idx < 32) { + mask = 1 << key->hw_key_idx; + + rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt2x00pci_register_write(rt2x00dev, SEC_CSR2, reg); + } else { + mask = 1 << (key->hw_key_idx - 32); + + rt2x00pci_register_read(rt2x00dev, SEC_CSR3, ®); + if (crypto->cmd == SET_KEY) + reg |= mask; + else if (crypto->cmd == DISABLE_KEY) + reg &= ~mask; + rt2x00pci_register_write(rt2x00dev, SEC_CSR3, reg); + } + + return 0; +} + static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -1533,8 +1731,8 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct txentry_desc *txdesc) + struct sk_buff *skb, + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1548,7 +1746,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); - 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_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); @@ -1561,6 +1759,11 @@ static void rt61pci_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); + _rt2x00_desc_write(txd, 4, skbdesc->eiv); + } + rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, @@ -1595,11 +1798,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, + test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, + test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); } @@ -1718,6 +1925,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 rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; u32 word0; u32 word1; @@ -1728,6 +1936,38 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); + rxdesc->cipher_status = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); + } + + 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, 4, &rxdesc->icv); + + /* + * 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; + + /* + * FIXME: Legacy driver indicates that the frame does + * contain the Michael Mic. Unfortunately, in rt2x00 + * the MIC seems to be missing completely... + */ + 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, @@ -1735,7 +1975,7 @@ static void rt61pci_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 = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) @@ -2355,6 +2595,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. @@ -2404,6 +2645,7 @@ static const struct ieee80211_ops rt61pci_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, .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, @@ -2432,6 +2674,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .write_beacon = rt61pci_write_beacon, .kick_tx_queue = rt61pci_kick_tx_queue, .fill_rxdone = rt61pci_fill_rxdone, + .config_shared_key = rt61pci_config_shared_key, + .config_pairwise_key = rt61pci_config_pairwise_key, .config_filter = rt61pci_config_filter, .config_intf = rt61pci_config_intf, .config_erp = rt61pci_config_erp, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 1004d5b899e..6d591cef3e5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -134,6 +134,16 @@ #define PAIRWISE_KEY_TABLE_BASE 0x1200 #define PAIRWISE_TA_TABLE_BASE 0x1a00 +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_TA_ENTRY(__idx) \ + ( PAIRWISE_TA_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_pairwise_ta_entry)) ) + struct hw_key_entry { u8 key[16]; u8 tx_mic[8]; @@ -142,7 +152,8 @@ struct hw_key_entry { struct hw_pairwise_ta_entry { u8 address[6]; - u8 reserved[2]; + u8 cipher; + u8 reserved; } __attribute__ ((packed)); /* @@ -662,6 +673,10 @@ struct hw_pairwise_ta_entry { * SEC_CSR4: Pairwise key table lookup control. */ #define SEC_CSR4 0x30b0 +#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001) +#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002) +#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004) +#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008) /* * SEC_CSR5: shared key table security mode register. @@ -1428,8 +1443,10 @@ struct hw_pairwise_ta_entry { /* * Word4 + * ICV: Received ICV of originally encrypted. + * NOTE: This is a guess, the official definition is "reserved" */ -#define RXD_W4_RESERVED FIELD32(0xffffffff) +#define RXD_W4_ICV FIELD32(0xffffffff) /* * the above 20-byte is called RXINFO and will be DMAed to MAC RX block -- cgit v1.2.3 From 906c110fcc24bdd5bf0fa22d89ac75d99c747e53 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:38:24 +0200 Subject: rt2x00: Implement HW encryption (rt73usb) rt73usb supports hardware encryption. rt73usb supports up to 4 shared keys and up to 64 pairwise keys. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 1 + drivers/net/wireless/rt2x00/rt73usb.c | 271 +++++++++++++++++++++++++++++++++- drivers/net/wireless/rt2x00/rt73usb.h | 21 ++- 3 files changed, 285 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f333f6100d0..11f590d63af 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -156,6 +156,7 @@ config RT73USB depends on USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO select CRC_ITU_T ---help--- This adds support for rt2501 wireless chipset family. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 9761eaaa08b..ddba747fed9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -357,6 +357,219 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ +static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + int timeout; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for shared keys. We have 1 register + * with key valid bits. The goal is simple, read + * the register, if that is full we have no slots + * left. + * Note that each BSS is allowed to have up to 4 + * shared keys, so put a mask over the allowed + * entries. + */ + mask = (0xf << crypto->bssidx); + + rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = SHARED_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + &key_entry, + sizeof(key_entry), + timeout); + + /* + * The cipher types are stored over 2 registers. + * bssidx 0 and 1 keys are stored in SEC_CSR1 and + * bssidx 1 and 2 keys are stored in SEC_CSR5. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + if (key->hw_key_idx < 8) { + field.bit_offset = (3 * key->hw_key_idx); + field.bit_mask = 0x7 << field.bit_offset; + + rt73usb_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt73usb_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, ®); + rt2x00_set_field32(®, field, crypto->cipher); + rt73usb_register_write(rt2x00dev, SEC_CSR5, reg); + } + + /* + * 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; + } + + /* + * SEC_CSR0 contains only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + mask = 1 << key->hw_key_idx; + + rt73usb_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); + + return 0; +} + +static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_pairwise_ta_entry addr_entry; + struct hw_key_entry key_entry; + int timeout; + u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { + /* + * rt2x00lib can't determine the correct free + * key_idx for pairwise keys. We have 2 registers + * with key valid bits. The goal is simple, read + * the first register, if that is full move to + * the next register. + * When both registers are full, we drop the key, + * otherwise we use the first invalid entry. + */ + rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + if (reg && reg == ~0) { + key->hw_key_idx = 32; + rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + if (reg && reg == ~0) + return -ENOSPC; + } + + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + + /* + * Upload key to hardware + */ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + &key_entry, + sizeof(key_entry), + timeout); + + /* + * 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. + */ + 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, + &addr_entry, sizeof(addr_entry)); + + /* + * Enable pairwise lookup table for given BSS idx, + * without this received frames will not be decrypted + * by the hardware. + */ + rt73usb_register_read(rt2x00dev, SEC_CSR4, ®); + reg |= (1 << crypto->bssidx); + rt73usb_register_write(rt2x00dev, SEC_CSR4, reg); + + /* + * 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; + } + + /* + * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate + * a particular key is valid. Because using the FIELD32() + * defines directly will cause a lot of overhead we use + * a calculation to determine the correct bit directly. + */ + if (key->hw_key_idx < 32) { + mask = 1 << key->hw_key_idx; + + rt73usb_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); + } else { + mask = 1 << (key->hw_key_idx - 32); + + rt73usb_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); + } + + return 0; +} + static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -1265,8 +1478,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, - struct txentry_desc *txdesc) + struct sk_buff *skb, + struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; @@ -1280,7 +1493,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); - 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_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_desc_write(txd, 1, word); @@ -1292,6 +1505,11 @@ static void rt73usb_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); + _rt2x00_desc_write(txd, 4, skbdesc->eiv); + } + rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(rt2x00dev->tx_power)); @@ -1313,12 +1531,16 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, + test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, + test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len - skbdesc->desc_len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); } @@ -1468,6 +1690,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 rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; u32 word0; @@ -1489,6 +1712,38 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG); + rxdesc->cipher_status = + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(rxd, 2, &rxdesc->iv); + _rt2x00_desc_read(rxd, 3, &rxdesc->eiv); + _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + + /* + * 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; + + /* + * FIXME: Legacy driver indicates that the frame does + * contain the Michael Mic. Unfortunately, in rt2x00 + * the MIC seems to be missing completely... + */ + 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, @@ -1496,7 +1751,7 @@ static void rt73usb_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 = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); + rxdesc->rssi = rt73usb_agc_to_rssi(rt2x00dev, word1); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) @@ -1938,6 +2193,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1997,6 +2253,7 @@ static const struct ieee80211_ops rt73usb_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, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, @@ -2024,6 +2281,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, + .config_shared_key = rt73usb_config_shared_key, + .config_pairwise_key = rt73usb_config_pairwise_key, .config_filter = rt73usb_config_filter, .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 14849350101..91e04d319d7 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -92,6 +92,16 @@ #define PAIRWISE_KEY_TABLE_BASE 0x1200 #define PAIRWISE_TA_TABLE_BASE 0x1a00 +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_key_entry)) ) +#define PAIRWISE_TA_ENTRY(__idx) \ + ( PAIRWISE_TA_TABLE_BASE + \ + ((__idx) * sizeof(struct hw_pairwise_ta_entry)) ) + struct hw_key_entry { u8 key[16]; u8 tx_mic[8]; @@ -100,7 +110,8 @@ struct hw_key_entry { struct hw_pairwise_ta_entry { u8 address[6]; - u8 reserved[2]; + u8 cipher; + u8 reserved; } __attribute__ ((packed)); /* @@ -563,6 +574,10 @@ struct hw_pairwise_ta_entry { * SEC_CSR4: Pairwise key table lookup control. */ #define SEC_CSR4 0x30b0 +#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001) +#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002) +#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004) +#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008) /* * SEC_CSR5: shared key table security mode register. @@ -1010,8 +1025,10 @@ struct hw_pairwise_ta_entry { /* * Word4 + * ICV: Received ICV of originally encrypted. + * NOTE: This is a guess, the official definition is "reserved" */ -#define RXD_W4_RESERVED FIELD32(0xffffffff) +#define RXD_W4_ICV FIELD32(0xffffffff) /* * the above 20-byte is called RXINFO and will be DMAed to MAC RX block -- cgit v1.2.3 From 8c5e7a5f59f9d11597bd47de28334da318ea0e80 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:38:47 +0200 Subject: rt2x00: Gather channel information in structure Channel information which is read from EEPROM should be read into an array containing per-channel information. This removes the requirement of multiple arrays and makes the channel handling a bit cleaner and easier to expand. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 40 ++++++++++++++++----------- drivers/net/wireless/rt2x00/rt2400pci.h | 22 ++++++--------- drivers/net/wireless/rt2x00/rt2500pci.c | 39 ++++++++++++++++++--------- drivers/net/wireless/rt2x00/rt2500pci.h | 17 ++++-------- drivers/net/wireless/rt2x00/rt2500usb.c | 39 ++++++++++++++++++--------- drivers/net/wireless/rt2x00/rt2500usb.h | 17 ++++-------- drivers/net/wireless/rt2x00/rt2x00.h | 23 ++++++++++------ drivers/net/wireless/rt2x00/rt2x00config.c | 4 +++ drivers/net/wireless/rt2x00/rt2x00dev.c | 18 +++---------- drivers/net/wireless/rt2x00/rt61pci.c | 42 +++++++++++++++++------------ drivers/net/wireless/rt2x00/rt61pci.h | 17 ++++-------- drivers/net/wireless/rt2x00/rt73usb.c | 43 +++++++++++++++++------------- drivers/net/wireless/rt2x00/rt73usb.h | 17 ++++-------- 13 files changed, 176 insertions(+), 162 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4c0538d6099..0107cec18b2 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1404,7 +1404,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * RF value list for RF2420 & RF2421 * Supports: 2.4 GHz */ -static const struct rf_channel rf_vals_bg[] = { +static const struct rf_channel rf_vals_b[] = { { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 }, { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 }, { 3, 0x00022058, 0x000c2002, 0x00000101, 0 }, @@ -1421,10 +1421,11 @@ static const struct rf_channel rf_vals_bg[] = { { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 }, }; -static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1439,24 +1440,29 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); - /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; - spec->num_channels = ARRAY_SIZE(rf_vals_bg); - spec->channels = rf_vals_bg; + spec->num_channels = ARRAY_SIZE(rf_vals_b); + spec->channels = rf_vals_b; + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + return 0; } static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1477,7 +1483,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt2400pci_probe_hw_mode(rt2x00dev); + retval = rt2400pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires the atim queue and DMA-mapped skbs. diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index bc556425822..bbff381ce39 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -938,19 +938,13 @@ #define MAX_TXPOWER 62 #define DEFAULT_TXPOWER 39 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ - ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ - (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - (__txpower) += MIN_TXPOWER; \ - ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \ - (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \ -}) +#define __CLAMP_TX(__txpower) \ + clamp_t(char, (__txpower), MIN_TXPOWER, MAX_TXPOWER) + +#define TXPOWER_FROM_DEV(__txpower) \ + ((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER) + +#define TXPOWER_TO_DEV(__txpower) \ + MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER) #endif /* RT2400PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 181a146b476..e0ff76ff490 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1721,10 +1721,11 @@ static const struct rf_channel rf_vals_5222[] = { { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, }; -static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1740,21 +1741,11 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); - /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); @@ -1776,6 +1767,26 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = DEFAULT_TXPOWER; + } + + return 0; } static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1796,7 +1807,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt2500pci_probe_hw_mode(rt2x00dev); + retval = rt2500pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires the atim queue and DMA-mapped skbs. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 42f376929ea..8c26bef6cf4 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1223,17 +1223,10 @@ #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT2500PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index cd5af656932..3b90ed62214 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1665,10 +1665,11 @@ static const struct rf_channel rf_vals_5222[] = { { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, }; -static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -1686,21 +1687,11 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); - /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); @@ -1722,6 +1713,26 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->num_channels = ARRAY_SIZE(rf_vals_5222); spec->channels = rf_vals_5222; } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = DEFAULT_TXPOWER; + } + + return 0; } static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -1742,7 +1753,9 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt2500usb_probe_hw_mode(rt2x00dev); + retval = rt2500usb_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires the atim queue diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 4769ffeb4cc..89e5ed24e4f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -825,17 +825,10 @@ #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT2500USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 0ffd972bb85..323bd54eb80 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -143,6 +143,17 @@ struct rf_channel { u32 rf4; }; +/* + * Channel information structure + */ +struct channel_info { + unsigned int flags; +#define GEOGRAPHY_ALLOWED 0x00000001 + + short tx_power1; + short tx_power2; +}; + /* * Antenna setup values. */ @@ -394,10 +405,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) * @num_channels: Number of supported channels. This is used as array size * for @tx_power_a, @tx_power_bg and @channels. * @channels: Device/chipset specific channel values (See &struct rf_channel). - * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL). - * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL). - * @tx_power_default: Default TX power value to use when either - * @tx_power_a or @tx_power_bg is missing. + * @channels_info: Additional information for channels (See &struct channel_info). */ struct hw_mode_spec { unsigned int supported_bands; @@ -410,10 +418,7 @@ struct hw_mode_spec { unsigned int num_channels; const struct rf_channel *channels; - - const u8 *tx_power_a; - const u8 *tx_power_bg; - u8 tx_power_default; + const struct channel_info *channels_info; }; /* @@ -425,7 +430,9 @@ struct hw_mode_spec { */ struct rt2x00lib_conf { struct ieee80211_conf *conf; + struct rf_channel rf; + struct channel_info channel; struct antenna_setup ant; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index d134c3be539..ea37c796204 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -245,6 +245,10 @@ config: memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); + + memcpy(&libconf.channel, + &rt2x00dev->spec.channels_info[conf->channel->hw_value], + sizeof(libconf.channel)); } if (flags & CONFIG_UPDATE_ANTENNA) { diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 182952249a1..328ff8bc4c1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -818,7 +818,6 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, struct ieee80211_rate *rates; unsigned int num_rates; unsigned int i; - unsigned char tx_power; num_rates = 0; if (spec->supported_rates & SUPPORT_RATE_CCK) @@ -844,20 +843,9 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, * Initialize Channel list. */ for (i = 0; i < spec->num_channels; i++) { - if (spec->channels[i].channel <= 14) { - if (spec->tx_power_bg) - tx_power = spec->tx_power_bg[i]; - else - tx_power = spec->tx_power_default; - } else { - if (spec->tx_power_a) - tx_power = spec->tx_power_a[i]; - else - tx_power = spec->tx_power_default; - } - rt2x00lib_channel(&channels[i], - spec->channels[i].channel, tx_power, i); + spec->channels[i].channel, + spec->channels_info[i].tx_power1, i); } /* @@ -909,6 +897,8 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; } + + kfree(rt2x00dev->spec.channels_info); } static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 86e7a50374b..87012f88461 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2514,10 +2514,11 @@ static const struct rf_channel rf_vals_seq[] = { { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 }, }; -static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -2533,21 +2534,11 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); - /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { spec->num_channels = 14; @@ -2561,13 +2552,28 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_rf(&rt2x00dev->chip, RF5325)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals_seq); + } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); - spec->tx_power_a = txpower; + if (spec->num_channels > 14) { + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); } + + return 0; } static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -2588,7 +2594,9 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt61pci_probe_hw_mode(rt2x00dev); + retval = rt61pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires firmware and DMA mapped skbs. diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 6d591cef3e5..8ec1451308c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -1482,17 +1482,10 @@ struct hw_pairwise_ta_entry { #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT61PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ddba747fed9..1bd6b3ffca0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2107,10 +2107,11 @@ static const struct rf_channel rf_vals_5225_2527[] = { }; -static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; - u8 *txpower; + struct channel_info *info; + char *tx_power; unsigned int i; /* @@ -2126,21 +2127,11 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0)); - /* - * Convert tx_power array in eeprom. - */ - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); - /* * Initialize hw_mode information. */ spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - spec->tx_power_a = NULL; - spec->tx_power_bg = txpower; - spec->tx_power_default = DEFAULT_TXPOWER; if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); @@ -2158,14 +2149,26 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels = rf_vals_5225_2527; } - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF5226)) { - txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 0; i < 14; i++) - txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; - spec->tx_power_a = txpower; + spec->channels_info = info; + + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + + if (spec->num_channels > 14) { + tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 14; i < spec->num_channels; i++) + info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); } + + return 0; } static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) @@ -2186,7 +2189,9 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - rt73usb_probe_hw_mode(rt2x00dev); + retval = rt73usb_probe_hw_mode(rt2x00dev); + if (retval) + return retval; /* * This device requires firmware. diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 91e04d319d7..868386c457f 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -1050,17 +1050,10 @@ struct hw_pairwise_ta_entry { #define MAX_TXPOWER 31 #define DEFAULT_TXPOWER 24 -#define TXPOWER_FROM_DEV(__txpower) \ -({ \ - ((__txpower) > MAX_TXPOWER) ? \ - DEFAULT_TXPOWER : (__txpower); \ -}) - -#define TXPOWER_TO_DEV(__txpower) \ -({ \ - ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ - (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ - (__txpower)); \ -}) +#define TXPOWER_FROM_DEV(__txpower) \ + (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER) #endif /* RT73USB_H */ -- cgit v1.2.3 From edcc25b22f7c328f56e8c129afa1e10c8bacb2ef Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 4 Aug 2008 16:39:05 +0200 Subject: rt2x00: Release rt2x00 2.2.0 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 323bd54eb80..ced0a525176 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.1.8" +#define DRV_VERSION "2.2.0" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.2.3 From 06303352d3de02a371ccaec1366a92db5e1d7c30 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 5 Aug 2008 19:32:23 +0200 Subject: ath5k: set short preamble flag for rx set the short preamble flag in ieee80211_rx_status for frames received with a short preamble. drivers/net/wireless/ath5k/base.c: Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c1de1ef09e5..cd598c0d8d6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1763,12 +1763,10 @@ accept: rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); -#if 0 /* add rxs.flag SHORTPRE once it is in mac80211 */ - if (rs.rs_rate >= ATH5K_RATE_CODE_2M && - rs.rs_rate <= ATH5K_RATE_CODE_11M && - rs.rs_rate & AR5K_SET_SHORT_PREAMBLE) + if (rxs.rate_idx >= 0 && rs.rs_rate == + sc->curband->bitrates[rxs.rate_idx].hw_value_short) rxs.flag |= RX_FLAG_SHORTPRE; -#endif + ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ -- cgit v1.2.3 From ba2ab47129eee76f6f0ef52b4beae30a12cee7f6 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 6 Aug 2008 16:22:17 +0200 Subject: rt2x00: Move lna_gain calculation to config() callback We can optimize lna calculation in IRQ context by calculating most of the value during the config() callback when most of the value is actually influenced. This will be required later by rt2800pci and rt2800usb as well, since they need the lna_gain value during config(). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 5 ++++ drivers/net/wireless/rt2x00/rt61pci.c | 48 ++++++++++++++++++++++------------- drivers/net/wireless/rt2x00/rt73usb.c | 41 ++++++++++++++++++++---------- 3 files changed, 63 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ced0a525176..3fa3d5b006a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -803,6 +803,11 @@ struct rt2x00_dev { */ u32 *rf; + /* + * LNA gain + */ + short lna_gain; + /* * USB Max frame size (for rt2500usb & rt73usb). */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 87012f88461..0fcc4563683 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -638,6 +638,30 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, 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) { @@ -956,6 +980,9 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { + /* 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) @@ -1883,40 +1910,27 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, */ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) { - u16 eeprom; - u8 offset; + u8 offset = rt2x00dev->lna_gain; u8 lna; lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); switch (lna) { case 3: - offset = 90; + offset += 90; break; case 2: - offset = 74; + offset += 74; break; case 1: - offset = 64; + offset += 64; break; default: return 0; } if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - offset += 14; - if (lna == 3 || lna == 2) offset += 10; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - offset += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 1bd6b3ffca0..4f2eb90aaf0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -664,6 +664,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, 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) { @@ -918,6 +938,9 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { + /* 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) @@ -1644,20 +1667,19 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, */ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) { - u16 eeprom; - u8 offset; + u8 offset = rt2x00dev->lna_gain; u8 lna; lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); switch (lna) { case 3: - offset = 90; + offset += 90; break; case 2: - offset = 74; + offset += 74; break; case 1: - offset = 64; + offset += 64; break; default: return 0; @@ -1673,15 +1695,6 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) else if (lna == 2) offset += 8; } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - offset += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; -- cgit v1.2.3 From 008c44825db74c6cdcea13dfb1598896e74fe908 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 6 Aug 2008 17:27:31 +0200 Subject: rt2x00: Add module parameter to disable HW crypto Add a module parameter to rt61 and rt73 to disable HW crypto. The option should only be checked when determining if the SUPPORT_HW_CRYPTO flag should be set or not. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 10 +++++++++- drivers/net/wireless/rt2x00/rt73usb.c | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 0fcc4563683..23cf93dfda0 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -37,6 +37,13 @@ #include "rt2x00pci.h" #include "rt61pci.h" +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 0; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + /* * Register access. * BBP and RF register require indirect register access, @@ -2617,7 +2624,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4f2eb90aaf0..f58fd059c9a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -36,6 +36,13 @@ #include "rt2x00usb.h" #include "rt73usb.h" +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 0; +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 @@ -2211,7 +2218,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); /* * Set the rssi offset. -- cgit v1.2.3 From 32ddf0718590f410d5f18cb4fcda419f4aeefc57 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 8 Aug 2008 21:17:37 +0200 Subject: p54: rename prism54xyz -> p54xyz It's been a long time, but fullmac prism54 driver is still around... I think we should rename every prism54* in order to avoid some confusion about "what is actually what" in the future ;-). Thanks-to: Maxi Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 6 +++--- drivers/net/wireless/p54/p54common.h | 6 +++--- drivers/net/wireless/p54/p54pci.c | 34 +++++++++++++++++----------------- drivers/net/wireless/p54/p54pci.h | 10 +++++----- drivers/net/wireless/p54/p54usb.c | 32 ++++++++++++++++---------------- drivers/net/wireless/p54/p54usb.h | 6 +++--- 6 files changed, 47 insertions(+), 47 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 4801a363507..10df07de9e5 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -1,5 +1,5 @@ -#ifndef PRISM54_H -#define PRISM54_H +#ifndef P54_H +#define P54_H /* * Shared defines for all mac80211 Prism54 code @@ -76,4 +76,4 @@ void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); struct ieee80211_hw *p54_init_common(size_t priv_data_len); void p54_free_common(struct ieee80211_hw *dev); -#endif /* PRISM54_H */ +#endif /* P54_H */ diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 8db6c0e8e54..9bc2a1cf4b5 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -1,5 +1,5 @@ -#ifndef PRISM54COMMON_H -#define PRISM54COMMON_H +#ifndef P54COMMON_H +#define P54COMMON_H /* * Common code specific definitions for mac80211 Prism54 drivers @@ -250,4 +250,4 @@ struct p54_tx_control_vdcf { __le16 frameburst; } __attribute__ ((packed)); -#endif /* PRISM54COMMON_H */ +#endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 7dd4add4bf4..ea2dc3d93c4 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -75,7 +75,7 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); if (err) { - printk(KERN_ERR "%s (prism54pci): cannot find firmware " + printk(KERN_ERR "%s (p54pci): cannot find firmware " "(isl3886)\n", pci_name(priv->pdev)); return err; } @@ -150,16 +150,16 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) init_completion(&priv->boot_comp); err = request_irq(priv->pdev->irq, &p54p_simple_interrupt, - IRQF_SHARED, "prism54pci", priv); + IRQF_SHARED, "p54pci", priv); if (err) { - printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n", + printk(KERN_ERR "%s (p54pci): failed to register IRQ handler\n", pci_name(priv->pdev)); return err; } eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL); if (!eeprom) { - printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n", + printk(KERN_ERR "%s (p54pci): no memory for eeprom!\n", pci_name(priv->pdev)); err = -ENOMEM; goto out; @@ -177,7 +177,7 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { - printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n", + printk(KERN_ERR "%s (p54pci): Cannot boot firmware!\n", pci_name(priv->pdev)); err = -EINVAL; goto out; @@ -219,7 +219,7 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) alen = le16_to_cpu(ring_control->rx_mgmt[0].len); if (le32_to_cpu(ring_control->device_idx[2]) != 1 || alen < 0x10) { - printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n", + printk(KERN_ERR "%s (p54pci): Cannot read eeprom!\n", pci_name(priv->pdev)); err = -EINVAL; goto out; @@ -412,7 +412,7 @@ static int p54p_open(struct ieee80211_hw *dev) init_completion(&priv->boot_comp); err = request_irq(priv->pdev->irq, &p54p_interrupt, - IRQF_SHARED, "prism54pci", dev); + IRQF_SHARED, "p54pci", dev); if (err) { printk(KERN_ERR "%s: failed to register IRQ handler\n", wiphy_name(dev->wiphy)); @@ -506,7 +506,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n", + printk(KERN_ERR "%s (p54pci): Cannot enable new PCI device\n", pci_name(pdev)); return err; } @@ -514,22 +514,22 @@ static int __devinit p54p_probe(struct pci_dev *pdev, mem_addr = pci_resource_start(pdev, 0); mem_len = pci_resource_len(pdev, 0); if (mem_len < sizeof(struct p54p_csr)) { - printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n", + printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", pci_name(pdev)); pci_disable_device(pdev); return err; } - err = pci_request_regions(pdev, "prism54pci"); + err = pci_request_regions(pdev, "p54pci"); if (err) { - printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n", + printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", pci_name(pdev)); return err; } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n", + printk(KERN_ERR "%s (p54pci): No suitable DMA available\n", pci_name(pdev)); goto err_free_reg; } @@ -542,7 +542,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, dev = p54_init_common(sizeof(*priv)); if (!dev) { - printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n", + printk(KERN_ERR "%s (p54pci): ieee80211 alloc failed\n", pci_name(pdev)); err = -ENOMEM; goto err_free_reg; @@ -556,7 +556,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->map = ioremap(mem_addr, mem_len); if (!priv->map) { - printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n", + printk(KERN_ERR "%s (p54pci): Cannot map device memory\n", pci_name(pdev)); err = -EINVAL; // TODO: use a better error code? goto err_free_dev; @@ -565,7 +565,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), &priv->ring_control_dma); if (!priv->ring_control) { - printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n", + printk(KERN_ERR "%s (p54pci): Cannot allocate rings\n", pci_name(pdev)); err = -ENOMEM; goto err_iounmap; @@ -588,7 +588,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n", + printk(KERN_ERR "%s (p54pci): Cannot register netdevice\n", pci_name(pdev)); goto err_free_common; } @@ -673,7 +673,7 @@ static int p54p_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ static struct pci_driver p54p_driver = { - .name = "prism54pci", + .name = "p54pci", .id_table = p54p_table, .probe = p54p_probe, .remove = __devexit_p(p54p_remove), diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 5bedd7af385..07678ef5ddc 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -1,5 +1,5 @@ -#ifndef PRISM54PCI_H -#define PRISM54PCI_H +#ifndef P54PCI_H +#define P54PCI_H /* * Defines for PCI based mac80211 Prism54 driver @@ -68,7 +68,7 @@ struct p54p_csr { } __attribute__ ((packed)); /* usb backend only needs the register defines above */ -#ifndef PRISM54USB_H +#ifndef P54USB_H struct p54p_desc { __le32 host_addr; __le32 device_addr; @@ -102,5 +102,5 @@ struct p54p_priv { struct completion boot_comp; }; -#endif /* PRISM54USB_H */ -#endif /* PRISM54PCI_H */ +#endif /* P54USB_H */ +#endif /* P54PCI_H */ diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index cbaca23a945..8a420df605a 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -322,7 +322,7 @@ static int p54u_read_eeprom(struct ieee80211_hw *dev) buf = kmalloc(0x2020, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "prism54usb: cannot allocate memory for " + printk(KERN_ERR "p54usb: cannot allocate memory for " "eeprom readback!\n"); return -ENOMEM; } @@ -331,7 +331,7 @@ static int p54u_read_eeprom(struct ieee80211_hw *dev) *((u32 *) buf) = priv->common.rx_start; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "prism54usb: addr send failed\n"); + printk(KERN_ERR "p54usb: addr send failed\n"); goto fail; } } else { @@ -341,7 +341,7 @@ static int p54u_read_eeprom(struct ieee80211_hw *dev) reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg)); if (err) { - printk(KERN_ERR "prism54usb: dev_int send failed\n"); + printk(KERN_ERR "p54usb: dev_int send failed\n"); goto fail; } } @@ -359,7 +359,7 @@ static int p54u_read_eeprom(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, EEPROM_READBACK_LEN + priv->common.tx_hdr_len); if (err) { - printk(KERN_ERR "prism54usb: eeprom req send failed\n"); + printk(KERN_ERR "p54usb: eeprom req send failed\n"); goto fail; } @@ -369,7 +369,7 @@ static int p54u_read_eeprom(struct ieee80211_hw *dev) if (!err && alen > offset) { p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset); } else { - printk(KERN_ERR "prism54usb: eeprom read failed!\n"); + printk(KERN_ERR "p54usb: eeprom read failed!\n"); err = -EINVAL; goto fail; } @@ -458,7 +458,7 @@ 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 "prism54usb: firmware upload failed!\n"); + printk(KERN_ERR "p54usb: firmware upload failed!\n"); goto err_upload_failed; } @@ -469,7 +469,7 @@ 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 "prism54usb: firmware upload failed!\n"); + printk(KERN_ERR "p54usb: firmware upload failed!\n"); goto err_upload_failed; } @@ -480,13 +480,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "prism54usb: firmware upload failed!\n"); + printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "prism54usb: firmware boot timed out!\n"); + printk(KERN_ERR "p54usb: firmware boot timed out!\n"); err = -ETIMEDOUT; break; } @@ -498,7 +498,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "prism54usb: firmware boot failed!\n"); + printk(KERN_ERR "p54usb: firmware boot failed!\n"); goto err_upload_failed; } @@ -660,7 +660,7 @@ 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 "prism54usb: firmware block upload " + printk(KERN_ERR "p54usb: firmware block upload " "failed\n"); goto fail; } @@ -694,7 +694,7 @@ 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 "prism54usb: firmware DMA transfer " + printk(KERN_ERR "p54usb: firmware DMA transfer " "failed\n"); goto fail; } @@ -802,7 +802,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, dev = p54_init_common(sizeof(*priv)); if (!dev) { - printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n"); + printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); return -ENOMEM; } @@ -858,7 +858,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { u8 perm_addr[ETH_ALEN]; - printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); + printk(KERN_WARNING "p54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); random_ether_addr(perm_addr); SET_IEEE80211_PERM_ADDR(dev, perm_addr); } @@ -867,7 +867,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "prism54usb: Cannot register netdevice\n"); + printk(KERN_ERR "p54usb: Cannot register netdevice\n"); goto err_free_dev; } @@ -902,7 +902,7 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) } static struct usb_driver p54u_driver = { - .name = "prism54usb", + .name = "p54usb", .id_table = p54u_table, .probe = p54u_probe, .disconnect = p54u_disconnect, diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index d1896b396c1..1baaff058c5 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -1,5 +1,5 @@ -#ifndef PRISM54USB_H -#define PRISM54USB_H +#ifndef P54USB_H +#define P54USB_H /* * Defines for USB based mac80211 Prism54 driver @@ -130,4 +130,4 @@ struct p54u_priv { struct sk_buff_head rx_queue; }; -#endif /* PRISM54USB_H */ +#endif /* P54USB_H */ -- cgit v1.2.3 From b54bf94bf91e4ca2a489eb02bca0424ddb55242a Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Aug 2008 14:28:43 +0200 Subject: pcmcia: use pcmcia_loop_config in net pcmcia drivers Use the config loop helper in (some) net pcmcia drivers. CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/wireless/airo_cs.c | 230 +++++++++++++++++--------------- drivers/net/wireless/atmel_cs.c | 123 ++++++++--------- drivers/net/wireless/hostap/hostap_cs.c | 227 +++++++++++++++---------------- drivers/net/wireless/orinoco_cs.c | 176 ++++++++++++------------ drivers/net/wireless/spectrum_cs.c | 175 ++++++++++++------------ 5 files changed, 452 insertions(+), 479 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index f12355398fe..4fbe811bebf 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -206,126 +206,131 @@ static void airo_detach(struct pcmcia_device *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) +struct airo_cs_config_data { + cistpl_cftable_entry_t dflt; + win_req_t req; +}; + +static int airo_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + void *priv_data) +{ + struct airo_cs_config_data *cfg_mem = priv_data; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + cfg_mem->dflt = *cfg; + + if (cfg->index == 0) + return -ENODEV; + + p_dev->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vpp1.present & (1<conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (cfg_mem->dflt.vpp1.present & (1<conf.Vpp = cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + return -ENODEV; + + /* + Now set up a common memory window, if needed. There is room + in the struct pcmcia_device structure for one memory window handle, + but if the base addresses need to be saved, or if multiple + windows are needed, the info should go in the private data + structure for this device. + + Note that the memory window base is a physical address, and + needs to be mapped to virtual space with ioremap() before it + is used. + */ + if ((cfg->mem.nwin > 0) || (cfg_mem->dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &cfg_mem->dflt.mem; + memreq_t map; + cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + cfg_mem->req.Base = mem->win[0].host_addr; + cfg_mem->req.Size = mem->win[0].len; + cfg_mem->req.AccessSpeed = 0; + if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0) + return -ENODEV; + map.Page = 0; + map.CardOffset = mem->win[0].card_addr; + if (pcmcia_map_mem_page(p_dev->win, &map) != 0) + return -ENODEV; + } + /* If we got this far, we're cool! */ + return 0; +} + + static int airo_config(struct pcmcia_device *link) { - tuple_t tuple; - cisparse_t parse; local_info_t *dev; + struct airo_cs_config_data *cfg_mem; int last_fn, last_ret; - u_char buf[64]; - win_req_t req; - memreq_t map; dev = link->priv; DEBUG(0, "airo_config(0x%p)\n", link); + cfg_mem = kzalloc(sizeof(struct airo_cs_config_data), GFP_KERNEL); + if (!cfg_mem) + return -ENOMEM; + /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. + * In this loop, we scan the CIS for configuration table + * entries, each of which describes a valid card + * configuration, including voltage, IO window, memory window, + * and interrupt settings. + * + * We make no assumptions about the card to be configured: we + * use just the information available in the CIS. In an ideal + * world, this would work for any PCMCIA card, but it requires + * a complete and accurate CIS. In practice, a driver usually + * "knows" most of these things without consulting the CIS, + * and most client drivers will only use the CIS to fill in + * implementation-defined details. + */ + last_ret = pcmcia_loop_config(link, airo_cs_config_check, cfg_mem); + if (last_ret) + goto failed; + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. */ - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t dflt = { 0 }; - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - if (cfg->index == 0) goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vpp1.present & (1<conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt.vpp1.present & (1<conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - - /* - Now set up a common memory window, if needed. There is room - in the struct pcmcia_device structure for one memory window handle, - but if the base addresses need to be saved, or if multiple - windows are needed, the info should go in the private data - structure for this device. - - Note that the memory window base is a physical address, and - needs to be mapped to virtual space with ioremap() before it - is used. - */ - if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { - cistpl_mem_t *mem = - (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; - req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; - req.Base = mem->win[0].host_addr; - req.Size = mem->win[0].len; - req.AccessSpeed = 0; - if (pcmcia_request_window(&link, &req, &link->win) != 0) - goto next_entry; - map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(link->win, &map) != 0) - goto next_entry; - } - /* If we got this far, we're cool! */ - break; - - next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); - } - - /* - Allocate an interrupt line. Note that this does not assign a - handler to the interrupt, unless the 'Handler' member of the - irq structure is initialized. - */ if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); @@ -362,14 +367,17 @@ static int airo_config(struct pcmcia_device *link) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); if (link->win) - printk(", mem 0x%06lx-0x%06lx", req.Base, - req.Base+req.Size-1); + printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base, + cfg_mem->req.Base+cfg_mem->req.Size-1); printk("\n"); + kfree(cfg_mem); return 0; cs_failed: cs_error(link, last_fn, last_ret); + failed: airo_release(link); + kfree(cfg_mem); return -ENODEV; } /* airo_config */ diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 12617cd0b78..263c36f7ee2 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -224,25 +224,69 @@ static int card_present(void *arg) return 0; } +static int atmel_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + void *priv_data) +{ + cistpl_cftable_entry_t *dflt = priv_data; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + *dflt = *cfg; + if (cfg->index == 0) + return -ENODEV; + p_dev->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vpp1.present & (1<conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt->vpp1.present & (1<conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int atmel_config(struct pcmcia_device *link) { - tuple_t tuple; - cisparse_t parse; local_info_t *dev; int last_fn, last_ret; - u_char buf[64]; struct pcmcia_device_id *did; + cistpl_cftable_entry_t dflt = { 0 }; dev = link->priv; did = handle_to_dev(link).driver_data; DEBUG(0, "atmel_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - /* In this loop, we scan the CIS for configuration table entries, each of which describes a valid card configuration, including @@ -255,66 +299,8 @@ static int atmel_config(struct pcmcia_device *link) these things without consulting the CIS, and most client drivers will only use the CIS to fill in implementation-defined details. */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t dflt = { 0 }; - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - if (cfg->index == 0) goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vpp1.present & (1<conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (dflt.vpp1.present & (1<conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - - /* If we got this far, we're cool! */ - break; - - next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); - } + if (pcmcia_loop_config(link, atmel_config_check, &dflt)) + goto failed; /* Allocate an interrupt line. Note that this does not assign a @@ -360,6 +346,7 @@ static int atmel_config(struct pcmcia_device *link) cs_failed: cs_error(link, last_fn, last_ret); + failed: atmel_release(link); return -ENODEV; } diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 3b4e55cf33c..3d914dde5de 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -532,145 +532,134 @@ static void prism2_detach(struct pcmcia_device *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -#define CFG_CHECK2(fn, retf) \ -do { int _ret = (retf); \ -if (_ret != 0) { \ - PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \ - cs_error(link, fn, _ret); \ - goto next_entry; \ -} \ -} while (0) - /* run after a CARD_INSERTION event is received to configure the PCMCIA * socket and make the device available to the system */ + +struct prism2_config_data { + cistpl_cftable_entry_t dflt; + config_info_t conf; +}; + +static int prism2_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + void *priv_data) +{ + struct prism2_config_data *cfg_mem = priv_data; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + cfg_mem->dflt = *cfg; + if (cfg->index == 0) + return -ENODEV; + + p_dev->conf.ConfigIndex = cfg->index; + PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " + "(default 0x%02X)\n", cfg->index, cfg_mem->dflt.index); + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / + 10000 && !ignore_cis_vcc) { + PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" + " this entry\n"); + return -ENODEV; + } + } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / + 10000 && !ignore_cis_vcc) { + PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " + "- skipping this entry\n"); + return -ENODEV; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) { + /* At least Compaq WL200 does not have IRQInfo1 set, + * but it does not work without interrupts.. */ + printk(KERN_WARNING "Config has no IRQ info, but trying to " + "enable IRQ anyway..\n"); + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " + "cfg_mem->dflt.io.nwin=%d\n", + cfg->io.nwin, cfg_mem->dflt.io.nwin); + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " + "io.base=0x%04x, len=%d\n", io->flags, + io->win[0].base, io->win[0].len); + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & + CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int prism2_config(struct pcmcia_device *link) { struct net_device *dev; struct hostap_interface *iface; + struct prism2_config_data *cfg_mem; local_info_t *local; int ret = 1; - tuple_t tuple; - cisparse_t *parse; int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - cistpl_cftable_entry_t dflt = { 0 }; struct hostap_cs_priv *hw_priv; PDEBUG(DEBUG_FLOW, "prism2_config()\n"); - parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); + cfg_mem = kzalloc(sizeof(struct prism2_config_data), GFP_KERNEL); + if (!cfg_mem) + return -ENOMEM; + hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); - if (parse == NULL || hw_priv == NULL) { + if (hw_priv == NULL) { ret = -ENOMEM; goto failed; } - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &conf)); + pcmcia_get_configuration_info(link, &cfg_mem->conf)); /* Look for an appropriate configuration table entry in the CIS */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - for (;;) { - cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); - CFG_CHECK2(GetTupleData, - pcmcia_get_tuple_data(link, &tuple)); - CFG_CHECK2(ParseTuple, - pcmcia_parse_tuple(link, &tuple, parse)); - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " - "(default 0x%02X)\n", cfg->index, dflt.index); - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / - 10000 && !ignore_cis_vcc) { - PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" - " this entry\n"); - goto next_entry; - } - } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / - 10000 && !ignore_cis_vcc) { - PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " - "- skipping this entry\n"); - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) { - /* At least Compaq WL200 does not have IRQInfo1 set, - * but it does not work without interrupts.. */ - printk("Config has no IRQ info, but trying to enable " - "IRQ anyway..\n"); - link->conf.Attributes |= CONF_ENABLE_IRQ; - } - - /* IO window settings */ - PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " - "dflt.io.nwin=%d\n", - cfg->io.nwin, dflt.io.nwin); - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " - "io.base=0x%04x, len=%d\n", io->flags, - io->win[0].base, io->win[0].len); - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & - CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - CFG_CHECK2(RequestIO, - pcmcia_request_io(link, &link->io)); - - /* This configuration table entry is OK */ - break; - - next_entry: - CS_CHECK(GetNextTuple, - pcmcia_get_next_tuple(link, &tuple)); + last_ret = pcmcia_loop_config(link, prism2_config_check, cfg_mem); + if (last_ret) { + if (!ignore_cis_vcc) + printk(KERN_ERR "GetNextTuple(): No matching " + "CIS configuration. Maybe you need the " + "ignore_cis_vcc=1 parameter.\n"); + cs_error(link, RequestIO, last_ret); + goto failed; } /* Need to allocate net_device before requesting IRQ handler */ @@ -738,15 +727,15 @@ static int prism2_config(struct pcmcia_device *link) if (ret == 0 && local->ddev) strcpy(hw_priv->node.dev_name, local->ddev->name); } - kfree(parse); + kfree(cfg_mem); return ret; cs_failed: cs_error(link, last_fn, last_ret); failed: - kfree(parse); kfree(hw_priv); + kfree(cfg_mem); prism2_release((u_long)link); return ret; } diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1c216e015f6..473370c9e0d 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -164,23 +164,96 @@ static void orinoco_cs_detach(struct pcmcia_device *link) last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ } while (0) +struct orinoco_cs_config_data { + cistpl_cftable_entry_t dflt; + config_info_t conf; +}; + +static int orinoco_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + void *priv_data) +{ + struct orinoco_cs_config_data *cfg_mem = priv_data; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + cfg_mem->dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + p_dev->conf.ConfigIndex = cfg->index; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + goto next_entry; + } + return 0; + +next_entry: + pcmcia_disable_device(p_dev); + return -ENODEV; +}; + static int orinoco_cs_config(struct pcmcia_device *link) { + struct orinoco_cs_config_data *cfg_mem; struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - tuple_t tuple; - cisparse_t parse; void __iomem *mem; + cfg_mem = kzalloc(sizeof(struct orinoco_cs_config_data), GFP_KERNEL); + if (!cfg_mem) + return -ENOMEM; + /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &conf)); + pcmcia_get_configuration_info(link, &cfg_mem->conf)); /* * In this loop, we scan the CIS for configuration table @@ -196,94 +269,14 @@ orinoco_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_cftable_entry_t dflt = { .index = 0 }; - - if ( (pcmcia_get_tuple_data(link, &tuple) != 0) - || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n", conf.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 (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - if(!ignore_cis_vcc) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - pcmcia_disable_device(link); - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret == CS_NO_MORE_ITEMS) { + last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, cfg_mem); + if (last_ret) { + if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - goto cs_failed; - } + cs_error(link, RequestIO, last_ret); + goto failed; } /* @@ -334,7 +327,7 @@ orinoco_cs_config(struct pcmcia_device *link) "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); - + kfree(cfg_mem); return 0; cs_failed: @@ -342,6 +335,7 @@ orinoco_cs_config(struct pcmcia_device *link) failed: orinoco_cs_release(link); + kfree(cfg_mem); return -ENODEV; } /* orinoco_cs_config */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 98df9bc7836..8e1951cfc15 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -633,23 +633,96 @@ static void spectrum_cs_detach(struct pcmcia_device *link) * device available to the system. */ +struct spectrum_cs_config_data { + cistpl_cftable_entry_t dflt; + config_info_t conf; +}; + +static int spectrum_cs_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + void *priv_data) +{ + struct spectrum_cs_config_data *cfg_mem = priv_data; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + cfg_mem->dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + p_dev->conf.ConfigIndex = cfg->index; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + if (!ignore_cis_vcc) + goto next_entry; + } + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* Do we need to allocate an interrupt? */ + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + goto next_entry; + } + return 0; + +next_entry: + pcmcia_disable_device(p_dev); + return -ENODEV; +}; + static int spectrum_cs_config(struct pcmcia_device *link) { + struct spectrum_cs_config_data *cfg_mem; struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; int last_fn, last_ret; - u_char buf[64]; - config_info_t conf; - tuple_t tuple; - cisparse_t parse; void __iomem *mem; + cfg_mem = kzalloc(sizeof(struct spectrum_cs_config_data), GFP_KERNEL); + if (!cfg_mem) + return -ENOMEM; + /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &conf)); + pcmcia_get_configuration_info(link, &cfg_mem->conf)); /* * In this loop, we scan the CIS for configuration table @@ -665,94 +738,14 @@ spectrum_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_cftable_entry_t dflt = { .index = 0 }; - - if ( (pcmcia_get_tuple_data(link, &tuple) != 0) - || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Use power settings for Vcc and Vpp if present */ - /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.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 (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); - if(!ignore_cis_vcc) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - /* Do we need to allocate an interrupt? */ - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = - (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = - IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = - io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = - link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - - /* If we got this far, we're cool! */ - - break; - - next_entry: - pcmcia_disable_device(link); - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret == CS_NO_MORE_ITEMS) { + last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, cfg_mem); + if (last_ret) { + if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - goto cs_failed; - } + cs_error(link, RequestIO, last_ret); + goto failed; } /* @@ -809,6 +802,7 @@ spectrum_cs_config(struct pcmcia_device *link) link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); + kfree(cfg_mem); return 0; cs_failed: @@ -816,6 +810,7 @@ spectrum_cs_config(struct pcmcia_device *link) failed: spectrum_cs_release(link); + kfree(cfg_mem); return -ENODEV; } /* spectrum_cs_config */ -- cgit v1.2.3 From 498ac1899b62626bf6879a251d75c22ec564c559 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Aug 2008 14:59:13 +0200 Subject: pcmcia: pcmcia_config_loop() ConfigIndex unification Almost all drivers set p_dev->conf.ConfigIndex to cfg->index in the pcmcia_config_loop() callback function. Therefore, factor it out. Signed-off-by: Dominik Brodowski --- drivers/net/wireless/airo_cs.c | 2 -- drivers/net/wireless/atmel_cs.c | 2 -- drivers/net/wireless/hostap/hostap_cs.c | 1 - drivers/net/wireless/orinoco_cs.c | 1 - drivers/net/wireless/spectrum_cs.c | 1 - 5 files changed, 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 4fbe811bebf..d7216730f18 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -223,8 +223,6 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev, if (cfg->index == 0) return -ENODEV; - p_dev->conf.ConfigIndex = cfg->index; - /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { p_dev->conf.Attributes |= CONF_ENABLE_SPKR; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 263c36f7ee2..12efd44d64a 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -234,8 +234,6 @@ static int atmel_config_check(struct pcmcia_device *p_dev, *dflt = *cfg; if (cfg->index == 0) return -ENODEV; - p_dev->conf.ConfigIndex = cfg->index; - /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { p_dev->conf.Attributes |= CONF_ENABLE_SPKR; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 3d914dde5de..2abaa90b799 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -552,7 +552,6 @@ static int prism2_config_check(struct pcmcia_device *p_dev, if (cfg->index == 0) return -ENODEV; - p_dev->conf.ConfigIndex = cfg->index; PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " "(default 0x%02X)\n", cfg->index, cfg_mem->dflt.index); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 473370c9e0d..67a172dfb2d 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -179,7 +179,6 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev, cfg_mem->dflt = *cfg; if (cfg->index == 0) goto next_entry; - p_dev->conf.ConfigIndex = cfg->index; /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 8e1951cfc15..7536aa91dad 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -648,7 +648,6 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev, cfg_mem->dflt = *cfg; if (cfg->index == 0) goto next_entry; - p_dev->conf.ConfigIndex = cfg->index; /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ -- cgit v1.2.3 From 8e2fc39ddea7fe8c6798837da282db88a09af793 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Aug 2008 15:30:31 +0200 Subject: pcmcia: pcmcia_config_loop() default CIS entry handling Many drivers use the default CIS entry within their pcmcia_config_loop() callback function. Therefore, factor the default CIS entry handling out. Signed-off-by: Dominik Brodowski --- drivers/net/wireless/airo_cs.c | 51 ++++++++++++++------------------- drivers/net/wireless/atmel_cs.c | 9 ++---- drivers/net/wireless/hostap/hostap_cs.c | 24 +++++++--------- drivers/net/wireless/orinoco_cs.c | 18 ++++++------ drivers/net/wireless/spectrum_cs.c | 18 ++++++------ 5 files changed, 52 insertions(+), 68 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index d7216730f18..657adf85ab7 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -206,19 +206,12 @@ static void airo_detach(struct pcmcia_device *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -struct airo_cs_config_data { - cistpl_cftable_entry_t dflt; - win_req_t req; -}; - static int airo_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, void *priv_data) { - struct airo_cs_config_data *cfg_mem = priv_data; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - cfg_mem->dflt = *cfg; + win_req_t *req = priv_data; if (cfg->index == 0) return -ENODEV; @@ -233,17 +226,17 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vpp1.present & (1<conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; - else if (cfg_mem->dflt.vpp1.present & (1<conf.Vpp = cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt->vpp1.present & (1<conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1) + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) p_dev->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; @@ -273,14 +266,14 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev, needs to be mapped to virtual space with ioremap() before it is used. */ - if ((cfg->mem.nwin > 0) || (cfg_mem->dflt.mem.nwin > 0)) { - cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &cfg_mem->dflt.mem; + if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { + cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; memreq_t map; - cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; - cfg_mem->req.Base = mem->win[0].host_addr; - cfg_mem->req.Size = mem->win[0].len; - cfg_mem->req.AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0) + req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req->Base = mem->win[0].host_addr; + req->Size = mem->win[0].len; + req->AccessSpeed = 0; + if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0) return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; @@ -295,15 +288,15 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev, static int airo_config(struct pcmcia_device *link) { local_info_t *dev; - struct airo_cs_config_data *cfg_mem; + win_req_t *req; int last_fn, last_ret; dev = link->priv; DEBUG(0, "airo_config(0x%p)\n", link); - cfg_mem = kzalloc(sizeof(struct airo_cs_config_data), GFP_KERNEL); - if (!cfg_mem) + req = kzalloc(sizeof(win_req_t), GFP_KERNEL); + if (!req) return -ENOMEM; /* @@ -320,7 +313,7 @@ static int airo_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - last_ret = pcmcia_loop_config(link, airo_cs_config_check, cfg_mem); + last_ret = pcmcia_loop_config(link, airo_cs_config_check, req); if (last_ret) goto failed; @@ -365,17 +358,17 @@ static int airo_config(struct pcmcia_device *link) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); if (link->win) - printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base, - cfg_mem->req.Base+cfg_mem->req.Size-1); + printk(", mem 0x%06lx-0x%06lx", req->Base, + req->Base+req->Size-1); printk("\n"); - kfree(cfg_mem); + kfree(req); return 0; cs_failed: cs_error(link, last_fn, last_ret); failed: airo_release(link); - kfree(cfg_mem); + kfree(req); return -ENODEV; } /* airo_config */ diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 12efd44d64a..c71aae992ec 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -226,14 +226,12 @@ static int card_present(void *arg) static int atmel_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, void *priv_data) { - cistpl_cftable_entry_t *dflt = priv_data; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - *dflt = *cfg; if (cfg->index == 0) return -ENODEV; + /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { p_dev->conf.Attributes |= CONF_ENABLE_SPKR; @@ -278,7 +276,6 @@ static int atmel_config(struct pcmcia_device *link) local_info_t *dev; int last_fn, last_ret; struct pcmcia_device_id *did; - cistpl_cftable_entry_t dflt = { 0 }; dev = link->priv; did = handle_to_dev(link).driver_data; @@ -297,7 +294,7 @@ static int atmel_config(struct pcmcia_device *link) these things without consulting the CIS, and most client drivers will only use the CIS to fill in implementation-defined details. */ - if (pcmcia_loop_config(link, atmel_config_check, &dflt)) + if (pcmcia_loop_config(link, atmel_config_check, NULL)) goto failed; /* diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 2abaa90b799..f9595ca71a0 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -537,23 +537,21 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) * socket and make the device available to the system */ struct prism2_config_data { - cistpl_cftable_entry_t dflt; config_info_t conf; }; static int prism2_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, void *priv_data) { struct prism2_config_data *cfg_mem = priv_data; - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - cfg_mem->dflt = *cfg; if (cfg->index == 0) return -ENODEV; PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X " - "(default 0x%02X)\n", cfg->index, cfg_mem->dflt.index); + "(default 0x%02X)\n", cfg->index, dflt->index); /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { @@ -570,8 +568,8 @@ static int prism2_config_check(struct pcmcia_device *p_dev, " this entry\n"); return -ENODEV; } - } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000 && !ignore_cis_vcc) { PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " "- skipping this entry\n"); @@ -581,11 +579,11 @@ static int prism2_config_check(struct pcmcia_device *p_dev, if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - p_dev->conf.Vpp = cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || cfg_mem->dflt.irq.IRQInfo1) + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) p_dev->conf.Attributes |= CONF_ENABLE_IRQ; else if (!(p_dev->conf.Attributes & CONF_ENABLE_IRQ)) { /* At least Compaq WL200 does not have IRQInfo1 set, @@ -597,11 +595,11 @@ static int prism2_config_check(struct pcmcia_device *p_dev, /* IO window settings */ PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d " - "cfg_mem->dflt.io.nwin=%d\n", - cfg->io.nwin, cfg_mem->dflt.io.nwin); + "dflt->io.nwin=%d\n", + cfg->io.nwin, dflt->io.nwin); p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, " "io.base=0x%04x, len=%d\n", io->flags, diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 67a172dfb2d..8a367f96db3 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -165,18 +165,16 @@ static void orinoco_cs_detach(struct pcmcia_device *link) } while (0) struct orinoco_cs_config_data { - cistpl_cftable_entry_t dflt; config_info_t conf; }; static int orinoco_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, void *priv_data) { struct orinoco_cs_config_data *cfg_mem = priv_data; - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - cfg_mem->dflt = *cfg; if (cfg->index == 0) goto next_entry; @@ -188,9 +186,9 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev, if (!ignore_cis_vcc) goto next_entry; } - } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -199,17 +197,17 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev, if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) p_dev->conf.Vpp = - cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ p_dev->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 7536aa91dad..e28878dfaba 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -634,18 +634,16 @@ static void spectrum_cs_detach(struct pcmcia_device *link) */ struct spectrum_cs_config_data { - cistpl_cftable_entry_t dflt; config_info_t conf; }; static int spectrum_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, void *priv_data) { struct spectrum_cs_config_data *cfg_mem = priv_data; - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - cfg_mem->dflt = *cfg; if (cfg->index == 0) goto next_entry; @@ -657,9 +655,9 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev, if (!ignore_cis_vcc) goto next_entry; } - } else if (cfg_mem->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg_mem->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (cfg_mem->conf.Vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -668,17 +666,17 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev, if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (cfg_mem->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) p_dev->conf.Vpp = - cfg_mem->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ p_dev->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (cfg_mem->dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &cfg_mem->dflt.io; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; -- cgit v1.2.3 From ad913c11928f51abb6174f165db8d8d205b22e21 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 2 Aug 2008 16:12:00 +0200 Subject: pcmcia: pcmcia_config_loop() improvement by passing vcc By passing the current Vcc setting to the pcmcia_config_loop callback function, we can remove pcmcia_get_configuration_info() calls from many drivers. Signed-off-by: Dominik Brodowski --- drivers/net/wireless/airo_cs.c | 1 + drivers/net/wireless/atmel_cs.c | 1 + drivers/net/wireless/hostap/hostap_cs.c | 23 ++++------------------- drivers/net/wireless/orinoco_cs.c | 28 ++++++---------------------- drivers/net/wireless/spectrum_cs.c | 28 ++++++---------------------- 5 files changed, 18 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 657adf85ab7..fac1526e49a 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -209,6 +209,7 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int airo_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, + unsigned int vcc, void *priv_data) { win_req_t *req = priv_data; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index c71aae992ec..4830d51900a 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -227,6 +227,7 @@ static int card_present(void *arg) static int atmel_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, + unsigned int vcc, void *priv_data) { if (cfg->index == 0) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index f9595ca71a0..c768d42d517 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -536,17 +536,12 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) /* run after a CARD_INSERTION event is received to configure the PCMCIA * socket and make the device available to the system */ -struct prism2_config_data { - config_info_t conf; -}; - static int prism2_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, + unsigned int vcc, void *priv_data) { - struct prism2_config_data *cfg_mem = priv_data; - if (cfg->index == 0) return -ENODEV; @@ -562,14 +557,14 @@ static int prism2_config_check(struct pcmcia_device *p_dev, /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000 && !ignore_cis_vcc) { PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping" " this entry\n"); return -ENODEV; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000 && !ignore_cis_vcc) { PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch " "- skipping this entry\n"); @@ -627,7 +622,6 @@ static int prism2_config(struct pcmcia_device *link) { struct net_device *dev; struct hostap_interface *iface; - struct prism2_config_data *cfg_mem; local_info_t *local; int ret = 1; int last_fn, last_ret; @@ -635,21 +629,14 @@ static int prism2_config(struct pcmcia_device *link) PDEBUG(DEBUG_FLOW, "prism2_config()\n"); - cfg_mem = kzalloc(sizeof(struct prism2_config_data), GFP_KERNEL); - if (!cfg_mem) - return -ENOMEM; - hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); if (hw_priv == NULL) { ret = -ENOMEM; goto failed; } - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &cfg_mem->conf)); - /* Look for an appropriate configuration table entry in the CIS */ - last_ret = pcmcia_loop_config(link, prism2_config_check, cfg_mem); + last_ret = pcmcia_loop_config(link, prism2_config_check, NULL); if (last_ret) { if (!ignore_cis_vcc) printk(KERN_ERR "GetNextTuple(): No matching " @@ -724,7 +711,6 @@ static int prism2_config(struct pcmcia_device *link) if (ret == 0 && local->ddev) strcpy(hw_priv->node.dev_name, local->ddev->name); } - kfree(cfg_mem); return ret; cs_failed: @@ -732,7 +718,6 @@ static int prism2_config(struct pcmcia_device *link) failed: kfree(hw_priv); - kfree(cfg_mem); prism2_release((u_long)link); return ret; } diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 8a367f96db3..c7b57d9d499 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -164,31 +164,26 @@ static void orinoco_cs_detach(struct pcmcia_device *link) last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ } while (0) -struct orinoco_cs_config_data { - config_info_t conf; -}; - static int orinoco_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, + unsigned int vcc, void *priv_data) { - struct orinoco_cs_config_data *cfg_mem = priv_data; - if (cfg->index == 0) goto next_entry; /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -236,7 +231,6 @@ next_entry: static int orinoco_cs_config(struct pcmcia_device *link) { - struct orinoco_cs_config_data *cfg_mem; struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; @@ -244,14 +238,6 @@ orinoco_cs_config(struct pcmcia_device *link) int last_fn, last_ret; void __iomem *mem; - cfg_mem = kzalloc(sizeof(struct orinoco_cs_config_data), GFP_KERNEL); - if (!cfg_mem) - return -ENOMEM; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &cfg_mem->conf)); - /* * In this loop, we scan the CIS for configuration table * entries, each of which describes a valid card @@ -266,7 +252,7 @@ orinoco_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, cfg_mem); + last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); if (last_ret) { if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " @@ -324,7 +310,6 @@ orinoco_cs_config(struct pcmcia_device *link) "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); - kfree(cfg_mem); return 0; cs_failed: @@ -332,7 +317,6 @@ orinoco_cs_config(struct pcmcia_device *link) failed: orinoco_cs_release(link); - kfree(cfg_mem); return -ENODEV; } /* orinoco_cs_config */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index e28878dfaba..d7e9d9c3042 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -633,31 +633,26 @@ static void spectrum_cs_detach(struct pcmcia_device *link) * device available to the system. */ -struct spectrum_cs_config_data { - config_info_t conf; -}; - static int spectrum_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, + unsigned int vcc, void *priv_data) { - struct spectrum_cs_config_data *cfg_mem = priv_data; - if (cfg->index == 0) goto next_entry; /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (cfg_mem->conf.Vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (cfg_mem->conf.Vcc = %d, CIS = %d)\n", cfg_mem->conf.Vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { + DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -705,7 +700,6 @@ next_entry: static int spectrum_cs_config(struct pcmcia_device *link) { - struct spectrum_cs_config_data *cfg_mem; struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; @@ -713,14 +707,6 @@ spectrum_cs_config(struct pcmcia_device *link) int last_fn, last_ret; void __iomem *mem; - cfg_mem = kzalloc(sizeof(struct spectrum_cs_config_data), GFP_KERNEL); - if (!cfg_mem) - return -ENOMEM; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link, &cfg_mem->conf)); - /* * In this loop, we scan the CIS for configuration table * entries, each of which describes a valid card @@ -735,7 +721,7 @@ spectrum_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, cfg_mem); + last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); if (last_ret) { if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " @@ -799,7 +785,6 @@ spectrum_cs_config(struct pcmcia_device *link) link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); - kfree(cfg_mem); return 0; cs_failed: @@ -807,7 +792,6 @@ spectrum_cs_config(struct pcmcia_device *link) failed: spectrum_cs_release(link); - kfree(cfg_mem); return -ENODEV; } /* spectrum_cs_config */ -- cgit v1.2.3 From 0753bba2d45762f83b9f4db94d15a3047f592964 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:46 +0100 Subject: orinoco: Add ESSID specific scanning for Agere fw Pass the ESSID to the card. This allows 'iwlist eth1 scan essid ' to work, and will help with routers setup not to broadcast the ESSID. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 1ebcafe7ca5..a60b459a9a9 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2982,6 +2982,11 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, range->min_r_time = 0; range->max_r_time = 65535 * 1000; /* ??? */ + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) + range->scan_capa = IW_SCAN_CAPA_ESSID; + else + range->scan_capa = IW_SCAN_CAPA_NONE; + /* Event capability (kernel) */ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); /* Event capability (driver) */ @@ -3951,6 +3956,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; + struct iw_scan_req *si = (struct iw_scan_req *) extra; int err = 0; unsigned long flags; @@ -4012,7 +4018,19 @@ static int orinoco_ioctl_setscan(struct net_device *dev, } break; case FIRMWARE_TYPE_AGERE: - err = hermes_write_wordrec(hw, USER_BAP, + if (priv->scan_mode & IW_SCAN_THIS_ESSID) { + struct hermes_idstring idbuf; + size_t len = min(sizeof(idbuf.val), + (size_t) si->essid_len); + idbuf.len = cpu_to_le16(len); + memcpy(idbuf.val, si->essid, len); + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + HERMES_BYTES_TO_RECLEN(len + 2), + &idbuf); + } else + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSCANSSID_AGERE, 0); /* Any ESSID */ if (err) -- cgit v1.2.3 From 17a1a887041ea39a19c5d469f1e31df940b00622 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:47 +0100 Subject: orinoco: Update scan translation Report channel, beacon interval and capabilities. Use WEXT defines instead of magic numbers. State quality stats in dB. Also a few changes to keep line length less than 80. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 71 +++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index a60b459a9a9..00b1d595fa3 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -3948,7 +3948,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Trigger a scan (look for other cells in the vicinity */ +/* Trigger a scan (look for other cells in the vicinity) */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, struct iw_param *srq, @@ -3988,7 +3988,6 @@ static int orinoco_ioctl_setscan(struct net_device *dev, * we access scan variables in priv is critical. * o scan_inprogress : not touched by irq handler * o scan_mode : not touched by irq handler - * o scan_len : synchronised with scan_result * Before modifying anything on those variables, please think hard ! * Jean II */ @@ -4054,8 +4053,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, #define MAX_CUSTOM_LEN 64 /* Translate scan data returned from the card to a card independant - * format that the Wireless Tools will understand - Jean II - * Return message length or -errno for fatal errors */ + * format that the Wireless Tools will understand - Jean II */ static inline char *orinoco_translate_scan(struct net_device *dev, struct iw_request_info *info, char *current_ev, @@ -4067,9 +4065,10 @@ static inline char *orinoco_translate_scan(struct net_device *dev, u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ - char *p; char custom[MAX_CUSTOM_LEN]; + memset(&iwe, 0, sizeof(iwe)); + /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; @@ -4091,8 +4090,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, /* Add mode */ iwe.cmd = SIOCGIWMODE; capabilities = le16_to_cpu(bss->a.capabilities); - if (capabilities & 0x3) { - if (capabilities & 0x1) + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (capabilities & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; @@ -4102,17 +4101,22 @@ static inline char *orinoco_translate_scan(struct net_device *dev, channel = bss->s.channel; if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add frequency */ + /* Add channel and frequency */ iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + iwe.u.freq.m = channel_frequency[channel-1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } - /* Add quality statistics */ + /* Add quality statistics. level and noise in dB. No link quality */ iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = 0x10; /* no link quality */ + iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; /* Wireless tools prior to 27.pre22 will show link quality @@ -4126,25 +4130,13 @@ static inline char *orinoco_translate_scan(struct net_device *dev, /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; - if (capabilities & 0x10) + if (capabilities & WLAN_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->a.essid); - - /* 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 - last_scanned)); - iwe.u.data.length = p - custom; - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); + &iwe, NULL); /* Bit rate is not available in Lucent/Agere firmwares */ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { @@ -4166,7 +4158,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev, if (bss->p.rates[i] == 0x0) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000); + iwe.u.bitrate.value = + ((bss->p.rates[i] & 0x7f) * 500000); current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, @@ -4177,6 +4170,34 @@ static inline char *orinoco_translate_scan(struct net_device *dev, current_ev = current_val; } + /* Beacon interval */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "bcn_int=%d", + le16_to_cpu(bss->a.beacon_interv)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Capabilites */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "capab=0x%04x", + capabilities); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + return current_ev; } -- cgit v1.2.3 From a1d81f1523de0c588f1d7798a49d66559f538e4f Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:48 +0100 Subject: orinoco: Specify all three parameters to every Hermes command. hermes_issue_cmd now takes two more parameters. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 2cd86af1390..3a6ce5a9647 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -87,7 +87,8 @@ MODULE_LICENSE("Dual MPL/GPL"); Callable from any context. */ -static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) +static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0, + u16 param1, u16 param2) { int k = CMD_BUSY_TIMEOUT; u16 reg; @@ -103,8 +104,8 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) return -EBUSY; } - hermes_write_regn(hw, PARAM2, 0); - hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM2, param2); + hermes_write_regn(hw, PARAM1, param1); hermes_write_regn(hw, PARAM0, param0); hermes_write_regn(hw, CMD, cmd); @@ -162,7 +163,7 @@ int hermes_init(hermes_t *hw) /* We don't use hermes_docmd_wait here, because the reset wipes the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); + err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0, 0, 0); if (err) return err; @@ -216,7 +217,7 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, u16 reg; u16 status; - err = hermes_issue_cmd(hw, cmd, parm0); + err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); if (err) { if (! hermes_present(hw)) { if (net_ratelimit()) @@ -497,7 +498,7 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, hermes_write_bytes(hw, dreg, value, count << 1); - err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, rid, NULL); return err; -- cgit v1.2.3 From 82a06ee518f570eb8fbb6588e75a4a5d838ac901 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:49 +0100 Subject: orinoco: Move EXPORT_SYMBOL declarations next to exported function Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 3a6ce5a9647..240118f3358 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -122,6 +122,7 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) hw->reg_spacing = reg_spacing; hw->inten = 0x0; } +EXPORT_SYMBOL(hermes_struct_init); int hermes_init(hermes_t *hw) { @@ -202,6 +203,7 @@ int hermes_init(hermes_t *hw) out: return err; } +EXPORT_SYMBOL(hermes_init); /* Issue a command to the chip, and (busy!) wait for it to * complete. @@ -272,6 +274,7 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, out: return err; } +EXPORT_SYMBOL(hermes_docmd_wait); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) { @@ -314,7 +317,7 @@ int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) return 0; } - +EXPORT_SYMBOL(hermes_allocate); /* Set up a BAP to read a particular chunk of data from card's internal buffer. * @@ -398,6 +401,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, out: return err; } +EXPORT_SYMBOL(hermes_bap_pread); /* Write a block of data to the chip's buffer, via the * BAP. Synchronization/serialization is the caller's problem. @@ -423,6 +427,7 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, out: return err; } +EXPORT_SYMBOL(hermes_bap_pwrite); /* Read a Length-Type-Value record from the card. * @@ -476,6 +481,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, return 0; } +EXPORT_SYMBOL(hermes_read_ltv); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, u16 length, const void *value) @@ -503,15 +509,6 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, return err; } - -EXPORT_SYMBOL(hermes_struct_init); -EXPORT_SYMBOL(hermes_init); -EXPORT_SYMBOL(hermes_docmd_wait); -EXPORT_SYMBOL(hermes_allocate); - -EXPORT_SYMBOL(hermes_bap_pread); -EXPORT_SYMBOL(hermes_bap_pwrite); -EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_write_ltv); static int __init init_hermes(void) -- cgit v1.2.3 From fc5a62d8b7052ea588e4f7750cd78b0c4c47015a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:50 +0100 Subject: orinoco: Add function to execute Hermes initialisation commands synchronously The current synchronous execution function doesn't work for certain Hermes commands which clear the MAGIC number from SWSUPPORT0. These commands seem to be related to initialisation or programming, for example HERMES_CMD_INIT. Replicate hermes_docmd_wait for commands which clear the MAGIC number from SWSUPPORT0. This version accepts two extra arguments which are passed straight to the firmware. Functionality copied out of hermes_init. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes.c | 94 ++++++++++++++++++++++++++----------------- drivers/net/wireless/hermes.h | 3 ++ 2 files changed, 60 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index 240118f3358..bfa375369df 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c @@ -116,6 +116,61 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0, * Function definitions */ +/* For doing cmds that wipe the magic constant in SWSUPPORT0 */ +int hermes_doicmd_wait(hermes_t *hw, u16 cmd, + u16 parm0, u16 parm1, u16 parm2, + struct hermes_response *resp) +{ + int err = 0; + int k; + u16 status, reg; + + err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ((!(reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (!hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (!(reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ %p: " + "Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + if (resp) { + resp->status = status; + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + } + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + if (status & HERMES_STATUS_RESULT) + err = -EIO; +out: + return err; +} +EXPORT_SYMBOL(hermes_doicmd_wait); + void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) { hw->iobase = address; @@ -126,7 +181,7 @@ EXPORT_SYMBOL(hermes_struct_init); int hermes_init(hermes_t *hw) { - u16 status, reg; + u16 reg; int err = 0; int k; @@ -164,43 +219,8 @@ int hermes_init(hermes_t *hw) /* We don't use hermes_docmd_wait here, because the reset wipes the magic constant in SWSUPPORT0 away, and it gets confused */ - err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0, 0, 0); - if (err) - return err; - - reg = hermes_read_regn(hw, EVSTAT); - k = CMD_INIT_TIMEOUT; - while ( (! (reg & HERMES_EV_CMD)) && k) { - k--; - udelay(10); - reg = hermes_read_regn(hw, EVSTAT); - } - - hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); - - if (! hermes_present(hw)) { - DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", - hw->iobase); - err = -ENODEV; - goto out; - } - - if (! (reg & HERMES_EV_CMD)) { - printk(KERN_ERR "hermes @ %p: " - "Timeout waiting for card to reset (reg=0x%04x)!\n", - hw->iobase, reg); - err = -ETIMEDOUT; - goto out; - } - - status = hermes_read_regn(hw, STATUS); - - hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL); - if (status & HERMES_STATUS_RESULT) - err = -EIO; - - out: return err; } EXPORT_SYMBOL(hermes_init); diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 8e3f0e3edb5..287f5363fda 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -353,6 +353,9 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing); int hermes_init(hermes_t *hw); int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, struct hermes_response *resp); +int hermes_doicmd_wait(hermes_t *hw, u16 cmd, + u16 parm0, u16 parm1, u16 parm2, + struct hermes_response *resp); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, -- cgit v1.2.3 From f482eb797a391a098046a934f55af8bd785a4494 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:51 +0100 Subject: orinoco: Move firmware download functionality into new module Move the functionality from spectrum_cs to hermes_dld in preparation for making it more generic and usable by other orinoco drivers. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/Makefile | 2 +- drivers/net/wireless/hermes_dld.c | 338 +++++++++++++++++++++++++++++++++++++ drivers/net/wireless/hermes_dld.h | 45 +++++ drivers/net/wireless/spectrum_cs.c | 274 +----------------------------- 4 files changed, 385 insertions(+), 274 deletions(-) create mode 100644 drivers/net/wireless/hermes_dld.c create mode 100644 drivers/net/wireless/hermes_dld.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index c05fd7627f3..59d2d805f60 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o -obj-$(CONFIG_HERMES) += orinoco.o hermes.o +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 diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c new file mode 100644 index 00000000000..9a8ef3040d5 --- /dev/null +++ b/drivers/net/wireless/hermes_dld.c @@ -0,0 +1,338 @@ +/* + * Hermes download helper driver. + * + * This could be entirely merged into hermes.c. + * + * I'm keeping it separate to minimise the amount of merging between + * kernel upgrades. It also means the memory overhead for drivers that + * don't need firmware download low. + * + * This driver: + * - is capable of writing to the volatile area of the hermes device + * - is currently not capable of writing to non-volatile areas + * - provide helpers to identify and update plugin data + * - is not capable of interpreting a fw image directly. That is up to + * the main card driver. + * - deals with Hermes I devices. It can probably be modified to deal + * with Hermes II devices + * + * Copyright (C) 2007, David Kilroy + * + * Plug data code slightly modified from spectrum_cs driver + * Copyright (C) 2002-2005 Pavel Roskin + * Portions based on information in wl_lkm_718 Agere driver + * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include +#include +#include "hermes.h" +#include "hermes_dld.h" + +MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset"); +MODULE_AUTHOR("David Kilroy "); +MODULE_LICENSE("Dual MPL/GPL"); + +#define PFX "hermes_dld: " + +/* + * AUX port access. To unlock the AUX port write the access keys to the + * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL + * register. Then read it and make sure it's HERMES_AUX_ENABLED. + */ +#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ +#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ +#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ + +#define HERMES_AUX_PW0 0xFE01 +#define HERMES_AUX_PW1 0xDC23 +#define HERMES_AUX_PW2 0xBA45 + +/* End markers */ +#define PDI_END 0x00000000 /* End of PDA */ +#define BLOCK_END 0xFFFFFFFF /* Last image block */ + +/* + * The following structures have little-endian fields denoted by + * the leading underscore. Don't access them directly - use inline + * functions defined below. + */ + +/* + * The binary image to be downloaded consists of series of data blocks. + * Each block has the following structure. + */ +struct dblock { + __le32 addr; /* adapter address where to write the block */ + __le16 len; /* length of the data only, in bytes */ + char data[0]; /* data to be written */ +} __attribute__ ((packed)); + +/* + * Plug Data References are located in in the image after the last data + * block. They refer to areas in the adapter memory where the plug data + * items with matching ID should be written. + */ +struct pdr { + __le32 id; /* record ID */ + __le32 addr; /* adapter address where to write the data */ + __le32 len; /* expected length of the data, in bytes */ + char next[0]; /* next PDR starts here */ +} __attribute__ ((packed)); + +/* + * Plug Data Items are located in the EEPROM read from the adapter by + * primary firmware. They refer to the device-specific data that should + * be plugged into the secondary firmware. + */ +struct pdi { + __le16 len; /* length of ID and data, in words */ + __le16 id; /* record ID */ + char data[0]; /* plug data */ +} __attribute__ ((packed)); + +/* Functions for access to little-endian data */ +static inline u32 +dblock_addr(const struct dblock *blk) +{ + return le32_to_cpu(blk->addr); +} + +static inline u32 +dblock_len(const struct dblock *blk) +{ + return le16_to_cpu(blk->len); +} + +static inline u32 +pdr_id(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->id); +} + +static inline u32 +pdr_addr(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->addr); +} + +static inline u32 +pdr_len(const struct pdr *pdr) +{ + return le32_to_cpu(pdr->len); +} + +static inline u32 +pdi_id(const struct pdi *pdi) +{ + return le16_to_cpu(pdi->id); +} + +/* Return length of the data only, in bytes */ +static inline u32 +pdi_len(const struct pdi *pdi) +{ + return 2 * (le16_to_cpu(pdi->len) - 1); +} + +/* Set address of the auxiliary port */ +static inline void +spectrum_aux_setaddr(hermes_t *hw, u32 addr) +{ + hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); + hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); +} + +/* Open access to the auxiliary port */ +static int +spectrum_aux_open(hermes_t *hw) +{ + int i; + + /* Already open? */ + if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED) + return 0; + + hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); + hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); + hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); + hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE); + + for (i = 0; i < 20; i++) { + udelay(10); + if (hermes_read_reg(hw, HERMES_CONTROL) == + HERMES_AUX_ENABLED) + return 0; + } + + return -EBUSY; +} + +/* + * Scan PDR for the record with the specified RECORD_ID. + * If it's not found, return NULL. + */ +static struct pdr * +spectrum_find_pdr(struct pdr *first_pdr, u32 record_id) +{ + struct pdr *pdr = first_pdr; + + while (pdr_id(pdr) != PDI_END) { + /* + * PDR area is currently not terminated by PDI_END. + * It's followed by CRC records, which have the type + * field where PDR has length. The type can be 0 or 1. + */ + if (pdr_len(pdr) < 2) + return NULL; + + /* If the record ID matches, we are done */ + if (pdr_id(pdr) == record_id) + return pdr; + + pdr = (struct pdr *) pdr->next; + } + return NULL; +} + +/* Process one Plug Data Item - find corresponding PDR and plug it */ +static int +spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) +{ + struct pdr *pdr; + + /* Find the PDI corresponding to this PDR */ + pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi)); + + /* No match is found, safe to ignore */ + if (!pdr) + return 0; + + /* Lengths of the data in PDI and PDR must match */ + if (pdi_len(pdi) != pdr_len(pdr)) + return -EINVAL; + + /* do the actual plugging */ + spectrum_aux_setaddr(hw, pdr_addr(pdr)); + hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); + + return 0; +} + +/* Read PDA from the adapter */ +int +spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) +{ + int ret; + int pda_size; + + /* Issue command to read EEPROM */ + ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); + if (ret) + return ret; + + /* Open auxiliary port */ + ret = spectrum_aux_open(hw); + if (ret) + return ret; + + /* read PDA from EEPROM */ + spectrum_aux_setaddr(hw, PDA_ADDR); + hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2); + + /* Check PDA length */ + pda_size = le16_to_cpu(pda[0]); + if (pda_size > pda_len) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(spectrum_read_pda); + +/* Parse PDA and write the records into the adapter */ +int +spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, + __le16 *pda) +{ + int ret; + struct pdi *pdi; + struct pdr *first_pdr; + const struct dblock *blk = first_block; + + /* Skip all blocks to locate Plug Data References */ + while (dblock_addr(blk) != BLOCK_END) + blk = (struct dblock *) &blk->data[dblock_len(blk)]; + + first_pdr = (struct pdr *) blk; + + /* Go through every PDI and plug them into the adapter */ + pdi = (struct pdi *) (pda + 2); + while (pdi_id(pdi) != PDI_END) { + ret = spectrum_plug_pdi(hw, first_pdr, pdi); + if (ret) + return ret; + + /* Increment to the next PDI */ + pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; + } + return 0; +} +EXPORT_SYMBOL(spectrum_apply_pda); + +/* Load firmware blocks into the adapter */ +int +spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block) +{ + const struct dblock *blk; + u32 blkaddr; + u32 blklen; + + blk = first_block; + blkaddr = dblock_addr(blk); + blklen = dblock_len(blk); + + while (dblock_addr(blk) != BLOCK_END) { + spectrum_aux_setaddr(hw, blkaddr); + hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, + blklen); + + blk = (struct dblock *) &blk->data[blklen]; + blkaddr = dblock_addr(blk); + blklen = dblock_len(blk); + } + return 0; +} +EXPORT_SYMBOL(spectrum_load_blocks); + +static int __init init_hermes_dld(void) +{ + return 0; +} + +static void __exit exit_hermes_dld(void) +{ +} + +module_init(init_hermes_dld); +module_exit(exit_hermes_dld); diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h new file mode 100644 index 00000000000..2c8892ac635 --- /dev/null +++ b/drivers/net/wireless/hermes_dld.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007, David Kilroy + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ +#ifndef _HERMES_DLD_H +#define _HERMES_DLD_H + +#include "hermes.h" + +/* Position of PDA in the adapter memory */ +#define EEPROM_ADDR 0x3000 +#define EEPROM_LEN 0x200 +#define PDA_OFFSET 0x100 + +#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET) +#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2) + +struct dblock; + +int spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len); +int spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, + __le16 *pda); +int spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block); + +#endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 98df9bc7836..579873d0e8c 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -33,6 +33,7 @@ #include #include "orinoco.h" +#include "hermes_dld.h" static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; @@ -88,144 +89,9 @@ static void spectrum_cs_release(struct pcmcia_device *link); #define HCR_IDLE 0x0E /* don't run firmware after reset */ #define HCR_MEM16 0x10 /* memory width bit, should be preserved */ -/* - * AUX port access. To unlock the AUX port write the access keys to the - * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL - * register. Then read it and make sure it's HERMES_AUX_ENABLED. - */ -#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ -#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ -#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ - -#define HERMES_AUX_PW0 0xFE01 -#define HERMES_AUX_PW1 0xDC23 -#define HERMES_AUX_PW2 0xBA45 - /* End markers */ -#define PDI_END 0x00000000 /* End of PDA */ -#define BLOCK_END 0xFFFFFFFF /* Last image block */ #define TEXT_END 0x1A /* End of text header */ -/* - * The following structures have little-endian fields denoted by - * the leading underscore. Don't access them directly - use inline - * functions defined below. - */ - -/* - * The binary image to be downloaded consists of series of data blocks. - * Each block has the following structure. - */ -struct dblock { - __le32 addr; /* adapter address where to write the block */ - __le16 len; /* length of the data only, in bytes */ - char data[0]; /* data to be written */ -} __attribute__ ((packed)); - -/* - * Plug Data References are located in in the image after the last data - * block. They refer to areas in the adapter memory where the plug data - * items with matching ID should be written. - */ -struct pdr { - __le32 id; /* record ID */ - __le32 addr; /* adapter address where to write the data */ - __le32 len; /* expected length of the data, in bytes */ - char next[0]; /* next PDR starts here */ -} __attribute__ ((packed)); - - -/* - * Plug Data Items are located in the EEPROM read from the adapter by - * primary firmware. They refer to the device-specific data that should - * be plugged into the secondary firmware. - */ -struct pdi { - __le16 len; /* length of ID and data, in words */ - __le16 id; /* record ID */ - char data[0]; /* plug data */ -} __attribute__ ((packed)); - - -/* Functions for access to little-endian data */ -static inline u32 -dblock_addr(const struct dblock *blk) -{ - return le32_to_cpu(blk->addr); -} - -static inline u32 -dblock_len(const struct dblock *blk) -{ - return le16_to_cpu(blk->len); -} - -static inline u32 -pdr_id(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->id); -} - -static inline u32 -pdr_addr(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->addr); -} - -static inline u32 -pdr_len(const struct pdr *pdr) -{ - return le32_to_cpu(pdr->len); -} - -static inline u32 -pdi_id(const struct pdi *pdi) -{ - return le16_to_cpu(pdi->id); -} - -/* Return length of the data only, in bytes */ -static inline u32 -pdi_len(const struct pdi *pdi) -{ - return 2 * (le16_to_cpu(pdi->len) - 1); -} - - -/* Set address of the auxiliary port */ -static inline void -spectrum_aux_setaddr(hermes_t *hw, u32 addr) -{ - hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); - hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); -} - - -/* Open access to the auxiliary port */ -static int -spectrum_aux_open(hermes_t *hw) -{ - int i; - - /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED) - return 0; - - hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); - hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); - hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE); - - for (i = 0; i < 20; i++) { - udelay(10); - if (hermes_read_reg(hw, HERMES_CONTROL) == - HERMES_AUX_ENABLED) - return 0; - } - - return -EBUSY; -} - #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) @@ -293,144 +159,6 @@ spectrum_reset(struct pcmcia_device *link, int idle) } -/* - * Scan PDR for the record with the specified RECORD_ID. - * If it's not found, return NULL. - */ -static struct pdr * -spectrum_find_pdr(struct pdr *first_pdr, u32 record_id) -{ - struct pdr *pdr = first_pdr; - - while (pdr_id(pdr) != PDI_END) { - /* - * PDR area is currently not terminated by PDI_END. - * It's followed by CRC records, which have the type - * field where PDR has length. The type can be 0 or 1. - */ - if (pdr_len(pdr) < 2) - return NULL; - - /* If the record ID matches, we are done */ - if (pdr_id(pdr) == record_id) - return pdr; - - pdr = (struct pdr *) pdr->next; - } - return NULL; -} - - -/* Process one Plug Data Item - find corresponding PDR and plug it */ -static int -spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) -{ - struct pdr *pdr; - - /* Find the PDI corresponding to this PDR */ - pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi)); - - /* No match is found, safe to ignore */ - if (!pdr) - return 0; - - /* Lengths of the data in PDI and PDR must match */ - if (pdi_len(pdi) != pdr_len(pdr)) - return -EINVAL; - - /* do the actual plugging */ - spectrum_aux_setaddr(hw, pdr_addr(pdr)); - hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); - - return 0; -} - - -/* Read PDA from the adapter */ -static int -spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) -{ - int ret; - int pda_size; - - /* Issue command to read EEPROM */ - ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; - - /* Open auxiliary port */ - ret = spectrum_aux_open(hw); - if (ret) - return ret; - - /* read PDA from EEPROM */ - spectrum_aux_setaddr(hw, PDA_ADDR); - hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2); - - /* Check PDA length */ - pda_size = le16_to_cpu(pda[0]); - if (pda_size > pda_len) - return -EINVAL; - - return 0; -} - - -/* Parse PDA and write the records into the adapter */ -static int -spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - __le16 *pda) -{ - int ret; - struct pdi *pdi; - struct pdr *first_pdr; - const struct dblock *blk = first_block; - - /* Skip all blocks to locate Plug Data References */ - while (dblock_addr(blk) != BLOCK_END) - blk = (struct dblock *) &blk->data[dblock_len(blk)]; - - first_pdr = (struct pdr *) blk; - - /* Go through every PDI and plug them into the adapter */ - pdi = (struct pdi *) (pda + 2); - while (pdi_id(pdi) != PDI_END) { - ret = spectrum_plug_pdi(hw, first_pdr, pdi); - if (ret) - return ret; - - /* Increment to the next PDI */ - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; - } - return 0; -} - - -/* Load firmware blocks into the adapter */ -static int -spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block) -{ - const struct dblock *blk; - u32 blkaddr; - u32 blklen; - - blk = first_block; - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - - while (dblock_addr(blk) != BLOCK_END) { - spectrum_aux_setaddr(hw, blkaddr); - hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, - blklen); - - blk = (struct dblock *) &blk->data[blklen]; - blkaddr = dblock_addr(blk); - blklen = dblock_len(blk); - } - return 0; -} - - /* * Process a firmware image - stop the card, load the firmware, reset * the card and make sure it responds. For the secondary firmware take -- cgit v1.2.3 From e23341809b7b60981d14a368155cd1f0724fb8d5 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:52 +0100 Subject: orinoco: Make firmware download logic more generic Ensure PDA read is terminated. Prevent invalid programming blocks from causing reads outside the firmware image Turn off aux stuff when finished. Option to program in limited block sizes (controlled by macro). Option to read PDA from EEPROM. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes_dld.c | 209 ++++++++++++++++++++++++++++--------- drivers/net/wireless/hermes_dld.h | 22 ++-- drivers/net/wireless/spectrum_cs.c | 23 ++-- 3 files changed, 182 insertions(+), 72 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c index 9a8ef3040d5..22ae79dae41 100644 --- a/drivers/net/wireless/hermes_dld.c +++ b/drivers/net/wireless/hermes_dld.c @@ -64,14 +64,34 @@ MODULE_LICENSE("Dual MPL/GPL"); #define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ #define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ #define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ +#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ #define HERMES_AUX_PW0 0xFE01 #define HERMES_AUX_PW1 0xDC23 #define HERMES_AUX_PW2 0xBA45 -/* End markers */ +/* End markers used in dblocks */ #define PDI_END 0x00000000 /* End of PDA */ #define BLOCK_END 0xFFFFFFFF /* Last image block */ +#define TEXT_END 0x1A /* End of text header */ + +/* + * PDA == Production Data Area + * + * In principle, the max. size of the PDA is is 4096 words. Currently, + * however, only about 500 bytes of this area are used. + * + * Some USB implementations can't handle sizes in excess of 1016. Note + * that PDA is not actually used in those USB environments, but may be + * retrieved by common code. + */ +#define MAX_PDA_SIZE 1000 + +/* Limit the amout we try to download in a single shot. + * Size is in bytes. + */ +#define MAX_DL_SIZE 1024 +#define LIMIT_PROGRAM_SIZE 0 /* * The following structures have little-endian fields denoted by @@ -112,7 +132,8 @@ struct pdi { char data[0]; /* plug data */ } __attribute__ ((packed)); -/* Functions for access to little-endian data */ +/*** FW data block access functions ***/ + static inline u32 dblock_addr(const struct dblock *blk) { @@ -125,6 +146,8 @@ dblock_len(const struct dblock *blk) return le16_to_cpu(blk->len); } +/*** PDR Access functions ***/ + static inline u32 pdr_id(const struct pdr *pdr) { @@ -143,6 +166,8 @@ pdr_len(const struct pdr *pdr) return le32_to_cpu(pdr->len); } +/*** PDI Access functions ***/ + static inline u32 pdi_id(const struct pdi *pdi) { @@ -156,49 +181,55 @@ pdi_len(const struct pdi *pdi) return 2 * (le16_to_cpu(pdi->len) - 1); } -/* Set address of the auxiliary port */ +/*** Hermes AUX control ***/ + static inline void -spectrum_aux_setaddr(hermes_t *hw, u32 addr) +hermes_aux_setaddr(hermes_t *hw, u32 addr) { hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); } -/* Open access to the auxiliary port */ -static int -spectrum_aux_open(hermes_t *hw) +static inline int +hermes_aux_control(hermes_t *hw, int enabled) { + int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; + int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; int i; /* Already open? */ - if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED) + if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) return 0; hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); - hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE); + hermes_write_reg(hw, HERMES_CONTROL, action); for (i = 0; i < 20; i++) { udelay(10); if (hermes_read_reg(hw, HERMES_CONTROL) == - HERMES_AUX_ENABLED) + desired_state) return 0; } return -EBUSY; } +/*** Plug Data Functions ***/ + /* * Scan PDR for the record with the specified RECORD_ID. * If it's not found, return NULL. */ static struct pdr * -spectrum_find_pdr(struct pdr *first_pdr, u32 record_id) +hermes_find_pdr(struct pdr *first_pdr, u32 record_id) { struct pdr *pdr = first_pdr; + void *end = (void *)first_pdr + MAX_PDA_SIZE; - while (pdr_id(pdr) != PDI_END) { + while (((void *)pdr < end) && + (pdr_id(pdr) != PDI_END)) { /* * PDR area is currently not terminated by PDI_END. * It's followed by CRC records, which have the type @@ -218,12 +249,12 @@ spectrum_find_pdr(struct pdr *first_pdr, u32 record_id) /* Process one Plug Data Item - find corresponding PDR and plug it */ static int -spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) +hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) { struct pdr *pdr; - /* Find the PDI corresponding to this PDR */ - pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi)); + /* Find the PDR corresponding to this PDI */ + pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); /* No match is found, safe to ignore */ if (!pdr) @@ -234,96 +265,172 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi) return -EINVAL; /* do the actual plugging */ - spectrum_aux_setaddr(hw, pdr_addr(pdr)); + hermes_aux_setaddr(hw, pdr_addr(pdr)); hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); return 0; } /* Read PDA from the adapter */ -int -spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len) +int hermes_read_pda(hermes_t *hw, + __le16 *pda, + u32 pda_addr, + u16 pda_len, + int use_eeprom) /* can we get this into hw? */ { int ret; - int pda_size; + u16 pda_size; + u16 data_len = pda_len; + __le16 *data = pda; - /* Issue command to read EEPROM */ - ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); - if (ret) - return ret; + if (use_eeprom) { + /* PDA of spectrum symbol is in eeprom */ + + /* Issue command to read EEPROM */ + ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); + if (ret) + return ret; + } /* Open auxiliary port */ - ret = spectrum_aux_open(hw); + ret = hermes_aux_control(hw, 1); + printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret); if (ret) return ret; /* read PDA from EEPROM */ - spectrum_aux_setaddr(hw, PDA_ADDR); - hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2); + hermes_aux_setaddr(hw, pda_addr); + hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); + + /* Close aux port */ + ret = hermes_aux_control(hw, 0); + printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret); /* Check PDA length */ pda_size = le16_to_cpu(pda[0]); + printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n", + pda_size, pda_len); if (pda_size > pda_len) return -EINVAL; return 0; } -EXPORT_SYMBOL(spectrum_read_pda); +EXPORT_SYMBOL(hermes_read_pda); -/* Parse PDA and write the records into the adapter */ -int -spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - __le16 *pda) +/* Parse PDA and write the records into the adapter + * + * Attempt to write every records that is in the specified pda + * which also has a valid production data record for the firmware. + */ +int hermes_apply_pda(hermes_t *hw, + const char *first_pdr, + const __le16 *pda) { int ret; - struct pdi *pdi; - struct pdr *first_pdr; - const struct dblock *blk = first_block; - - /* Skip all blocks to locate Plug Data References */ - while (dblock_addr(blk) != BLOCK_END) - blk = (struct dblock *) &blk->data[dblock_len(blk)]; + const struct pdi *pdi; + struct pdr *pdr; - first_pdr = (struct pdr *) blk; + pdr = (struct pdr *) first_pdr; /* Go through every PDI and plug them into the adapter */ - pdi = (struct pdi *) (pda + 2); + pdi = (const struct pdi *) (pda + 2); while (pdi_id(pdi) != PDI_END) { - ret = spectrum_plug_pdi(hw, first_pdr, pdi); + ret = hermes_plug_pdi(hw, pdr, pdi); if (ret) return ret; /* Increment to the next PDI */ - pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; + pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)]; } return 0; } -EXPORT_SYMBOL(spectrum_apply_pda); +EXPORT_SYMBOL(hermes_apply_pda); + +/* Identify the total number of bytes in all blocks + * including the header data. + */ +size_t +hermes_blocks_length(const char *first_block) +{ + const struct dblock *blk = (const struct dblock *) first_block; + int total_len = 0; + int len; + + /* Skip all blocks to locate Plug Data References + * (Spectrum CS) */ + while (dblock_addr(blk) != BLOCK_END) { + len = dblock_len(blk); + total_len += sizeof(*blk) + len; + blk = (struct dblock *) &blk->data[len]; + } + + return total_len; +} +EXPORT_SYMBOL(hermes_blocks_length); + +/*** Hermes programming ***/ -/* Load firmware blocks into the adapter */ -int -spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block) +/* Program the data blocks */ +int hermes_program(hermes_t *hw, const char *first_block, const char *end) { const struct dblock *blk; u32 blkaddr; u32 blklen; +#if LIMIT_PROGRAM_SIZE + u32 addr; + u32 len; +#endif + + blk = (const struct dblock *) first_block; + + if ((const char *) blk > (end - sizeof(*blk))) + return -EIO; - blk = first_block; blkaddr = dblock_addr(blk); blklen = dblock_len(blk); - while (dblock_addr(blk) != BLOCK_END) { - spectrum_aux_setaddr(hw, blkaddr); + while ((blkaddr != BLOCK_END) && + (((const char *) blk + blklen) <= end)) { + printk(KERN_DEBUG PFX + "Programming block of length %d to address 0x%08x\n", + blklen, blkaddr); + +#if !LIMIT_PROGRAM_SIZE + /* wl_lkm driver splits this into writes of 2000 bytes */ + hermes_aux_setaddr(hw, blkaddr); hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, blklen); +#else + len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE; + addr = blkaddr; + + while (addr < (blkaddr + blklen)) { + printk(KERN_DEBUG PFX + "Programming subblock of length %d " + "to address 0x%08x. Data @ %p\n", + len, addr, &blk->data[addr - blkaddr]); + + hermes_aux_setaddr(hw, addr); + hermes_write_bytes(hw, HERMES_AUXDATA, + &blk->data[addr - blkaddr], + len); + + addr += len; + len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ? + (blkaddr + blklen - addr) : MAX_DL_SIZE; + } +#endif + blk = (const struct dblock *) &blk->data[blklen]; + + if ((const char *) blk > (end - sizeof(*blk))) + return -EIO; - blk = (struct dblock *) &blk->data[blklen]; blkaddr = dblock_addr(blk); blklen = dblock_len(blk); } return 0; } -EXPORT_SYMBOL(spectrum_load_blocks); +EXPORT_SYMBOL(hermes_program); static int __init init_hermes_dld(void) { diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h index 2c8892ac635..af75c030b11 100644 --- a/drivers/net/wireless/hermes_dld.h +++ b/drivers/net/wireless/hermes_dld.h @@ -27,19 +27,17 @@ #include "hermes.h" -/* Position of PDA in the adapter memory */ -#define EEPROM_ADDR 0x3000 -#define EEPROM_LEN 0x200 -#define PDA_OFFSET 0x100 +int hermes_program(hermes_t *hw, const char *first_block, const char *end); -#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET) -#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2) +int hermes_read_pda(hermes_t *hw, + __le16 *pda, + u32 pda_addr, + u16 pda_len, + int use_eeprom); +int hermes_apply_pda(hermes_t *hw, + const char *first_pdr, + const __le16 *pda); -struct dblock; - -int spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len); -int spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, - __le16 *pda); -int spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block); +size_t hermes_blocks_length(const char *first_block); #endif /* _HERMES_DLD_H */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 579873d0e8c..2fb00183cd7 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -166,11 +166,12 @@ spectrum_reset(struct pcmcia_device *link, int idle) */ static int spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, - const unsigned char *image, int secondary) + const unsigned char *image, const unsigned char *end, + int secondary) { int ret; const unsigned char *ptr; - const struct dblock *first_block; + const unsigned char *first_block; /* Plug Data Area (PDA) */ __le16 pda[PDA_WORDS]; @@ -178,11 +179,11 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, /* Binary block begins after the 0x1A marker */ ptr = image; while (*ptr++ != TEXT_END); - first_block = (const struct dblock *) ptr; + first_block = ptr; - /* Read the PDA */ + /* Read the PDA from EEPROM */ if (secondary) { - ret = spectrum_read_pda(hw, pda, sizeof(pda)); + ret = hermes_read_pda(hw, pda, PDA_ADDR, sizeof(pda), 1); if (ret) return ret; } @@ -193,13 +194,15 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, return ret; /* Program the adapter with new firmware */ - ret = spectrum_load_blocks(hw, first_block); + ret = hermes_program(hw, first_block, end); if (ret) return ret; /* Write the PDA to the adapter */ if (secondary) { - ret = spectrum_apply_pda(hw, first_block, pda); + size_t len = hermes_blocks_length(first_block); + ptr = first_block + len; + ret = hermes_apply_pda(hw, ptr, pda); if (ret) return ret; } @@ -242,7 +245,8 @@ spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) } /* Load primary firmware */ - ret = spectrum_dl_image(hw, link, fw_entry->data, 0); + ret = spectrum_dl_image(hw, link, fw_entry->data, + fw_entry->data + fw_entry->size, 0); release_firmware(fw_entry); if (ret) { printk(KERN_ERR PFX "Primary firmware download failed\n"); @@ -257,7 +261,8 @@ spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) } /* Load secondary firmware */ - ret = spectrum_dl_image(hw, link, fw_entry->data, 1); + ret = spectrum_dl_image(hw, link, fw_entry->data, + fw_entry->data + fw_entry->size, 1); release_firmware(fw_entry); if (ret) { printk(KERN_ERR PFX "Secondary firmware download failed\n"); -- cgit v1.2.3 From 8f5ae73c5366128d3800cf9765507422bcf1ef96 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:53 +0100 Subject: orinoco: Extend hermes_dld routines for Agere firmware Add programming initialisation and termination functions. Add checks to avoid overrunning the firmware image or PDA areas. Extra algorithm to program PDA values using defaults where necessary. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes_dld.c | 285 ++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/hermes_dld.h | 5 + 2 files changed, 290 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c index 22ae79dae41..d8c626e61a3 100644 --- a/drivers/net/wireless/hermes_dld.c +++ b/drivers/net/wireless/hermes_dld.c @@ -70,6 +70,12 @@ MODULE_LICENSE("Dual MPL/GPL"); #define HERMES_AUX_PW1 0xDC23 #define HERMES_AUX_PW2 0xBA45 +/* HERMES_CMD_DOWNLD */ +#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) +#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) + /* End markers used in dblocks */ #define PDI_END 0x00000000 /* End of PDA */ #define BLOCK_END 0xFFFFFFFF /* Last image block */ @@ -247,6 +253,23 @@ hermes_find_pdr(struct pdr *first_pdr, u32 record_id) return NULL; } +/* Scan production data items for a particular entry */ +static struct pdi * +hermes_find_pdi(struct pdi *first_pdi, u32 record_id) +{ + struct pdi *pdi = first_pdi; + + while (pdi_id(pdi) != PDI_END) { + + /* If the record ID matches, we are done */ + if (pdi_id(pdi) == record_id) + return pdi; + + pdi = (struct pdi *) &pdi->data[pdi_len(pdi)]; + } + return NULL; +} + /* Process one Plug Data Item - find corresponding PDR and plug it */ static int hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) @@ -290,6 +313,15 @@ int hermes_read_pda(hermes_t *hw, ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); if (ret) return ret; + } else { + /* wl_lkm does not include PDA size in the PDA area. + * We will pad the information into pda, so other routines + * don't have to be modified */ + pda[0] = cpu_to_le16(pda_len - 2); + /* Includes CFG_PROD_DATA but not itself */ + pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ + data_len = pda_len - 4; + data = pda + 2; } /* Open auxiliary port */ @@ -370,6 +402,94 @@ EXPORT_SYMBOL(hermes_blocks_length); /*** Hermes programming ***/ +/* About to start programming data (Hermes I) + * offset is the entry point + * + * Spectrum_cs' Symbol fw does not require this + * wl_lkm Agere fw does + * Don't know about intersil + */ +int hermesi_program_init(hermes_t *hw, u32 offset) +{ + int err; + + /* Disable interrupts?*/ + /*hw->inten = 0x0;*/ + /*hermes_write_regn(hw, INTEN, 0);*/ + /*hermes_set_irqmask(hw, 0);*/ + + /* Acknowledge any outstanding command */ + hermes_write_regn(hw, EVACK, 0xFFFF); + + /* Using doicmd_wait rather than docmd_wait */ + err = hermes_doicmd_wait(hw, + 0x0100 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + if (err) + return err; + + err = hermes_doicmd_wait(hw, + 0x0000 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + if (err) + return err; + + err = hermes_aux_control(hw, 1); + printk(KERN_DEBUG PFX "AUX enable returned %d\n", err); + + if (err) + return err; + + printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); + err = hermes_doicmd_wait(hw, + HERMES_PROGRAM_ENABLE_VOLATILE, + offset & 0xFFFFu, + offset >> 16, + 0, + NULL); + printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n", + err); + + return err; +} +EXPORT_SYMBOL(hermesi_program_init); + +/* Done programming data (Hermes I) + * + * Spectrum_cs' Symbol fw does not require this + * wl_lkm Agere fw does + * Don't know about intersil + */ +int hermesi_program_end(hermes_t *hw) +{ + struct hermes_response resp; + int rc = 0; + int err; + + rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); + + printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, " + "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", + rc, resp.resp0, resp.resp1, resp.resp2); + + if ((rc == 0) && + ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) + rc = -EIO; + + err = hermes_aux_control(hw, 0); + printk(KERN_DEBUG PFX "AUX disable returned %d\n", err); + + /* Acknowledge any outstanding command */ + hermes_write_regn(hw, EVACK, 0xFFFF); + + /* Reinitialise, ignoring return */ + (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT, + 0, 0, 0, NULL); + + return rc ? rc : err; +} +EXPORT_SYMBOL(hermesi_program_end); + /* Program the data blocks */ int hermes_program(hermes_t *hw, const char *first_block, const char *end) { @@ -443,3 +563,168 @@ static void __exit exit_hermes_dld(void) module_init(init_hermes_dld); module_exit(exit_hermes_dld); + +/*** Default plugging data for Hermes I ***/ +/* Values from wl_lkm_718/hcf/dhf.c */ + +#define DEFINE_DEFAULT_PDR(pid, length, data) \ +static const struct { \ + __le16 len; \ + __le16 id; \ + u8 val[length]; \ +} __attribute__ ((packed)) default_pdr_data_##pid = { \ + __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ + sizeof(__le16)) - 1), \ + __constant_cpu_to_le16(pid), \ + data \ +} + +#define DEFAULT_PDR(pid) default_pdr_data_##pid + +/* HWIF Compatiblity */ +DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00"); + +/* PPPPSign */ +DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00"); + +/* PPPPProf */ +DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00"); + +/* Antenna diversity */ +DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F"); + +/* Modem VCO band Set-up */ +DEFINE_DEFAULT_PDR(0x0160, 28, + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00"); + +/* Modem Rx Gain Table Values */ +DEFINE_DEFAULT_PDR(0x0161, 256, + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3F\01\x3F\x01\x3F\x01" + "\x3F\x01\x3E\01\x3E\x01\x3D\x01" + "\x3D\x01\x3C\01\x3C\x01\x3B\x01" + "\x3B\x01\x3A\01\x3A\x01\x39\x01" + "\x39\x01\x38\01\x38\x01\x37\x01" + "\x37\x01\x36\01\x36\x01\x35\x01" + "\x35\x01\x34\01\x34\x01\x33\x01" + "\x33\x01\x32\x01\x32\x01\x31\x01" + "\x31\x01\x30\x01\x30\x01\x7B\x01" + "\x7B\x01\x7A\x01\x7A\x01\x79\x01" + "\x79\x01\x78\x01\x78\x01\x77\x01" + "\x77\x01\x76\x01\x76\x01\x75\x01" + "\x75\x01\x74\x01\x74\x01\x73\x01" + "\x73\x01\x72\x01\x72\x01\x71\x01" + "\x71\x01\x70\x01\x70\x01\x68\x01" + "\x68\x01\x67\x01\x67\x01\x66\x01" + "\x66\x01\x65\x01\x65\x01\x57\x01" + "\x57\x01\x56\x01\x56\x01\x55\x01" + "\x55\x01\x54\x01\x54\x01\x53\x01" + "\x53\x01\x52\x01\x52\x01\x51\x01" + "\x51\x01\x50\x01\x50\x01\x48\x01" + "\x48\x01\x47\x01\x47\x01\x46\x01" + "\x46\x01\x45\x01\x45\x01\x44\x01" + "\x44\x01\x43\x01\x43\x01\x42\x01" + "\x42\x01\x41\x01\x41\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01" + "\x40\x01\x40\x01\x40\x01\x40\x01"); + +/* Write PDA according to certain rules. + * + * For every production data record, look for a previous setting in + * the pda, and use that. + * + * For certain records, use defaults if they are not found in pda. + */ +int hermes_apply_pda_with_defaults(hermes_t *hw, + const char *first_pdr, + const __le16 *pda) +{ + const struct pdr *pdr = (const struct pdr *) first_pdr; + struct pdi *first_pdi = (struct pdi *) &pda[2]; + struct pdi *pdi; + struct pdi *default_pdi = NULL; + struct pdi *outdoor_pdi; + void *end = (void *)first_pdr + MAX_PDA_SIZE; + int record_id; + + while (((void *)pdr < end) && + (pdr_id(pdr) != PDI_END)) { + /* + * For spectrum_cs firmwares, + * PDR area is currently not terminated by PDI_END. + * It's followed by CRC records, which have the type + * field where PDR has length. The type can be 0 or 1. + */ + if (pdr_len(pdr) < 2) + break; + record_id = pdr_id(pdr); + + pdi = hermes_find_pdi(first_pdi, record_id); + if (pdi) + printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", + record_id, pdi); + + switch (record_id) { + case 0x110: /* Modem REFDAC values */ + case 0x120: /* Modem VGDAC values */ + outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); + default_pdi = NULL; + if (outdoor_pdi) { + pdi = outdoor_pdi; + printk(KERN_DEBUG PFX + "Using outdoor record 0x%04x at %p\n", + record_id + 1, pdi); + } + break; + case 0x5: /* HWIF Compatiblity */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005); + break; + case 0x108: /* PPPPSign */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108); + break; + case 0x109: /* PPPPProf */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109); + break; + case 0x150: /* Antenna diversity */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150); + break; + case 0x160: /* Modem VCO band Set-up */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160); + break; + case 0x161: /* Modem Rx Gain Table Values */ + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161); + break; + default: + default_pdi = NULL; + break; + } + if (!pdi && default_pdi) { + /* Use default */ + pdi = default_pdi; + printk(KERN_DEBUG PFX + "Using default record 0x%04x at %p\n", + record_id, pdi); + } + + if (pdi) { + /* Lengths of the data in PDI and PDR must match */ + if (pdi_len(pdi) == pdr_len(pdr)) { + /* do the actual plugging */ + hermes_aux_setaddr(hw, pdr_addr(pdr)); + hermes_write_bytes(hw, HERMES_AUXDATA, + pdi->data, pdi_len(pdi)); + } + } + + pdr++; + } + return 0; +} +EXPORT_SYMBOL(hermes_apply_pda_with_defaults); diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h index af75c030b11..6fcb2627799 100644 --- a/drivers/net/wireless/hermes_dld.h +++ b/drivers/net/wireless/hermes_dld.h @@ -27,6 +27,8 @@ #include "hermes.h" +int hermesi_program_init(hermes_t *hw, u32 offset); +int hermesi_program_end(hermes_t *hw); int hermes_program(hermes_t *hw, const char *first_block, const char *end); int hermes_read_pda(hermes_t *hw, @@ -37,6 +39,9 @@ int hermes_read_pda(hermes_t *hw, int hermes_apply_pda(hermes_t *hw, const char *first_pdr, const __le16 *pda); +int hermes_apply_pda_with_defaults(hermes_t *hw, + const char *first_pdr, + const __le16 *pda); size_t hermes_blocks_length(const char *first_block); -- cgit v1.2.3 From 3994d502017a2239e30152d1231843ad05d04a7b Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:54 +0100 Subject: orinoco: Invoke firmware download in main driver Firmware download is enabled for Agere in orinoco_cs. Symbol firmware download has been moved out of spectrum_cs into orinoco_cs. Firmware download is not enabled for Intersil. Symbol based firmware is restricted to only download on spectrum_cs based cards. The firmware names are hardcoded for each firmware type. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 +- drivers/net/wireless/airport.c | 3 +- drivers/net/wireless/orinoco.c | 314 +++++++++++++++++++++++++++++++++- drivers/net/wireless/orinoco.h | 9 +- drivers/net/wireless/orinoco_cs.c | 3 +- drivers/net/wireless/orinoco_nortel.c | 3 +- drivers/net/wireless/orinoco_pci.c | 3 +- drivers/net/wireless/orinoco_plx.c | 3 +- drivers/net/wireless/orinoco_tmd.c | 3 +- drivers/net/wireless/spectrum_cs.c | 159 ++--------------- 10 files changed, 346 insertions(+), 156 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 1ac46ad48c3..ea7da7117f4 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -335,6 +335,7 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 select WIRELESS_EXT + select FW_LOADER ---help--- A driver for 802.11b wireless cards based on the "Hermes" or Intersil HFA384x (Prism 2) MAC controller. This includes the vast @@ -424,7 +425,6 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" depends on PCMCIA && HERMES - select FW_LOADER ---help--- This is a driver for 802.11b cards using RAM-loadable Symbol diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 6f7eb9f5922..ce03a2e865f 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -180,7 +180,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } /* Allocate space for private device-specific data */ - dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); + dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, + airport_hard_reset, NULL); if (! dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 00b1d595fa3..306697aa333 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -82,12 +82,14 @@ #include #include #include +#include #include #include #include #include #include "hermes_rid.h" +#include "hermes_dld.h" #include "orinoco.h" /********************************************************************/ @@ -301,6 +303,272 @@ static void orinoco_bss_data_init(struct orinoco_private *priv) list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list); } + +/********************************************************************/ +/* Download functionality */ +/********************************************************************/ + +struct fw_info { + char *pri_fw; + char *sta_fw; + char *ap_fw; + u32 pda_addr; + u16 pda_size; +}; + +const static struct fw_info orinoco_fw[] = { + { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, + { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 } +}; + +/* Structure used to access fields in FW + * Make sure LE decoding macros are used + */ +struct orinoco_fw_header { + char hdr_vers[6]; /* ASCII string for header version */ + __le16 headersize; /* Total length of header */ + __le32 entry_point; /* NIC entry point */ + __le32 blocks; /* Number of blocks to program */ + __le32 block_offset; /* Offset of block data from eof header */ + __le32 pdr_offset; /* Offset to PDR data from eof header */ + __le32 pri_offset; /* Offset to primary plug data */ + __le32 compat_offset; /* Offset to compatibility data*/ + char signature[0]; /* FW signature length headersize-20 */ +} __attribute__ ((packed)); + +/* Download either STA or AP firmware into the card. */ +static int +orinoco_dl_firmware(struct orinoco_private *priv, + const struct fw_info *fw, + int ap) +{ + /* Plug Data Area (PDA) */ + __le16 pda[512] = { 0 }; + + hermes_t *hw = &priv->hw; + const struct firmware *fw_entry; + const struct orinoco_fw_header *hdr; + const unsigned char *first_block; + const unsigned char *end; + const char *firmware; + struct net_device *dev = priv->ndev; + int err; + + if (ap) + firmware = fw->ap_fw; + else + firmware = fw->sta_fw; + + printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", + dev->name, firmware); + + /* Read current plug data */ + err = hermes_read_pda(hw, pda, fw->pda_addr, + min_t(u16, fw->pda_size, sizeof(pda)), 0); + printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); + if (err) + return err; + + err = request_firmware(&fw_entry, firmware, priv->dev); + if (err) { + printk(KERN_ERR "%s: Cannot find firmware %s\n", + dev->name, firmware); + return -ENOENT; + } + + hdr = (const struct orinoco_fw_header *) fw_entry->data; + + /* Enable aux port to allow programming */ + err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); + printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Program data */ + first_block = (fw_entry->data + + le16_to_cpu(hdr->headersize) + + le32_to_cpu(hdr->block_offset)); + end = fw_entry->data + fw_entry->size; + + err = hermes_program(hw, first_block, end); + printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Update production data */ + first_block = (fw_entry->data + + le16_to_cpu(hdr->headersize) + + le32_to_cpu(hdr->pdr_offset)); + + err = hermes_apply_pda_with_defaults(hw, first_block, pda); + printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); + if (err) + goto abort; + + /* Tell card we've finished */ + err = hermesi_program_end(hw); + printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); + if (err != 0) + goto abort; + + /* Check if we're running */ + printk(KERN_DEBUG "%s: hermes_present returned %d\n", + dev->name, hermes_present(hw)); + +abort: + release_firmware(fw_entry); + return err; +} + +/* End markers */ +#define TEXT_END 0x1A /* End of text header */ + +/* + * Process a firmware image - stop the card, load the firmware, reset + * the card and make sure it responds. For the secondary firmware take + * care of the PDA - read it and then write it on top of the firmware. + */ +static int +symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, + const unsigned char *image, const unsigned char *end, + int secondary) +{ + hermes_t *hw = &priv->hw; + int ret; + const unsigned char *ptr; + const unsigned char *first_block; + + /* Plug Data Area (PDA) */ + __le16 pda[256]; + + /* Binary block begins after the 0x1A marker */ + ptr = image; + while (*ptr++ != TEXT_END); + first_block = ptr; + + /* Read the PDA from EEPROM */ + if (secondary) { + ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); + if (ret) + return ret; + } + + /* Stop the firmware, so that it can be safely rewritten */ + if (priv->stop_fw) { + ret = priv->stop_fw(priv, 1); + if (ret) + return ret; + } + + /* Program the adapter with new firmware */ + ret = hermes_program(hw, first_block, end); + if (ret) + return ret; + + /* Write the PDA to the adapter */ + if (secondary) { + size_t len = hermes_blocks_length(first_block); + ptr = first_block + len; + ret = hermes_apply_pda(hw, ptr, pda); + if (ret) + return ret; + } + + /* Run the firmware */ + if (priv->stop_fw) { + ret = priv->stop_fw(priv, 0); + if (ret) + return ret; + } + + /* Reset hermes chip and make sure it responds */ + ret = hermes_init(hw); + + /* hermes_reset() should return 0 with the secondary firmware */ + if (secondary && ret != 0) + return -ENODEV; + + /* And this should work with any firmware */ + if (!hermes_present(hw)) + return -ENODEV; + + return 0; +} + + +/* + * Download the firmware into the card, this also does a PCMCIA soft + * reset on the card, to make sure it's in a sane state. + */ +static int +symbol_dl_firmware(struct orinoco_private *priv, + const struct fw_info *fw) +{ + struct net_device *dev = priv->ndev; + int ret; + const struct firmware *fw_entry; + + if (request_firmware(&fw_entry, fw->pri_fw, + priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->pri_fw); + return -ENOENT; + } + + /* Load primary firmware */ + ret = symbol_dl_image(priv, fw, fw_entry->data, + fw_entry->data + fw_entry->size, 0); + release_firmware(fw_entry); + if (ret) { + printk(KERN_ERR "%s: Primary firmware download failed\n", + dev->name); + return ret; + } + + if (request_firmware(&fw_entry, fw->sta_fw, + priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->sta_fw); + return -ENOENT; + } + + /* Load secondary firmware */ + ret = symbol_dl_image(priv, fw, fw_entry->data, + fw_entry->data + fw_entry->size, 1); + release_firmware(fw_entry); + if (ret) { + printk(KERN_ERR "%s: Secondary firmware download failed\n", + dev->name); + } + + return ret; +} + +static int orinoco_download(struct orinoco_private *priv) +{ + int err = 0; + /* Reload firmware */ + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* case FIRMWARE_TYPE_INTERSIL: */ + err = orinoco_dl_firmware(priv, + &orinoco_fw[priv->firmware_type], 0); + break; + + case FIRMWARE_TYPE_SYMBOL: + err = symbol_dl_firmware(priv, + &orinoco_fw[priv->firmware_type]); + break; + case FIRMWARE_TYPE_INTERSIL: + break; + } + /* TODO: if we fail we probably need to reinitialise + * the driver */ + + return err; +} + /********************************************************************/ /* Device methods */ /********************************************************************/ @@ -2043,6 +2311,12 @@ 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", @@ -2254,6 +2528,7 @@ static int determine_firmware(struct net_device *dev) priv->has_ibss = 1; priv->has_wep = 0; priv->has_big_wep = 0; + priv->do_fw_download = 0; /* Determine capabilities from the firmware version */ switch (priv->firmware_type) { @@ -2273,6 +2548,7 @@ static int determine_firmware(struct net_device *dev) priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->ibss_port = 1; priv->has_hostscan = (firmver >= 0x8000a); + priv->do_fw_download = 1; priv->broken_monitor = (firmver >= 0x80000); /* Tested with Agere firmware : @@ -2317,6 +2593,21 @@ static int determine_firmware(struct net_device *dev) firmver >= 0x31000; priv->has_preamble = (firmver >= 0x20000); priv->ibss_port = 4; + + /* Symbol firmware is found on various cards, but + * there has been no attempt to check firmware + * download on non-spectrum_cs based cards. + * + * Given that the Agere firmware download works + * differently, we should avoid doing a firmware + * download with the Symbol algorithm on non-spectrum + * cards. + * + * For now we can identify a spectrum_cs based card + * because it has a firmware reset function. + */ + priv->do_fw_download = (priv->stop_fw != NULL); + priv->broken_disableport = (firmver == 0x25013) || (firmver >= 0x30000 && firmver <= 0x31000); priv->has_hostscan = (firmver >= 0x31001) || @@ -2387,6 +2678,20 @@ static int orinoco_init(struct net_device *dev) goto out; } + if (priv->do_fw_download) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + + /* Check firmware version again */ + err = determine_firmware(dev); + if (err != 0) { + printk(KERN_ERR "%s: Incompatible firmware, aborting\n", + dev->name); + goto out; + } + } + if (priv->has_port3) printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); if (priv->has_ibss) @@ -2529,8 +2834,11 @@ static int orinoco_init(struct net_device *dev) return err; } -struct net_device *alloc_orinocodev(int sizeof_card, - int (*hard_reset)(struct orinoco_private *)) +struct net_device +*alloc_orinocodev(int sizeof_card, + struct device *device, + int (*hard_reset)(struct orinoco_private *), + int (*stop_fw)(struct orinoco_private *, int)) { struct net_device *dev; struct orinoco_private *priv; @@ -2545,6 +2853,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, + sizeof(struct orinoco_private)); else priv->card = NULL; + priv->dev = device; if (orinoco_bss_data_allocate(priv)) goto err_out_free; @@ -2570,6 +2879,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, dev->open = orinoco_open; dev->stop = orinoco_stop; priv->hard_reset = hard_reset; + priv->stop_fw = stop_fw; spin_lock_init(&priv->lock); priv->open = 0; diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index c6b1858abde..e0acb633e9d 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -44,7 +44,9 @@ typedef struct { struct orinoco_private { void *card; /* Pointer to card dependent structure */ + struct device *dev; int (*hard_reset)(struct orinoco_private *); + int (*stop_fw)(struct orinoco_private *, int); /* Synchronisation stuff */ spinlock_t lock; @@ -83,6 +85,7 @@ struct orinoco_private { unsigned int has_preamble:1; unsigned int has_sensitivity:1; unsigned int has_hostscan:1; + unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; @@ -130,8 +133,10 @@ extern int orinoco_debug; /* Exported prototypes */ /********************************************************************/ -extern struct net_device *alloc_orinocodev(int sizeof_card, - int (*hard_reset)(struct orinoco_private *)); +extern struct net_device *alloc_orinocodev( + int sizeof_card, struct device *device, + int (*hard_reset)(struct orinoco_private *), + int (*stop_fw)(struct orinoco_private *, int)); extern void free_orinocodev(struct net_device *dev); extern int __orinoco_up(struct net_device *dev); extern int __orinoco_down(struct net_device *dev); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1c216e015f6..1ccf5a40cf0 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -109,7 +109,8 @@ orinoco_cs_probe(struct pcmcia_device *link) struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); + dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + orinoco_cs_hard_reset, NULL); if (! dev) return -ENOMEM; priv = netdev_priv(dev); diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index 35ec5fcf81a..2fc86596302 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -182,7 +182,8 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_nortel_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 2547d5dac0d..4ebd638a073 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -139,7 +139,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_pci_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 98fe165337d..ef761857bb3 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -221,7 +221,8 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_plx_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index df493185a4a..ede24ec309c 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -124,7 +124,8 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset); + dev = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_tmd_cor_reset, NULL); if (!dev) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 2fb00183cd7..e368759d1d8 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -33,10 +32,6 @@ #include #include "orinoco.h" -#include "hermes_dld.h" - -static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; -static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; /********************************************************************/ /* Module stuff */ @@ -72,26 +67,11 @@ struct orinoco_pccard { static int spectrum_cs_config(struct pcmcia_device *link); static void spectrum_cs_release(struct pcmcia_device *link); -/********************************************************************/ -/* Firmware downloader */ -/********************************************************************/ - -/* Position of PDA in the adapter memory */ -#define EEPROM_ADDR 0x3000 -#define EEPROM_LEN 0x200 -#define PDA_OFFSET 0x100 - -#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET) -#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2) - /* Constants for the CISREG_CCSR register */ #define HCR_RUN 0x07 /* run firmware after reset */ #define HCR_IDLE 0x0E /* don't run firmware after reset */ #define HCR_MEM16 0x10 /* memory width bit, should be preserved */ -/* End markers */ -#define TEXT_END 0x1A /* End of text header */ - #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) @@ -158,142 +138,29 @@ spectrum_reset(struct pcmcia_device *link, int idle) return -ENODEV; } +/********************************************************************/ +/* Device methods */ +/********************************************************************/ -/* - * Process a firmware image - stop the card, load the firmware, reset - * the card and make sure it responds. For the secondary firmware take - * care of the PDA - read it and then write it on top of the firmware. - */ static int -spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, - const unsigned char *image, const unsigned char *end, - int secondary) +spectrum_cs_hard_reset(struct orinoco_private *priv) { - int ret; - const unsigned char *ptr; - const unsigned char *first_block; - - /* Plug Data Area (PDA) */ - __le16 pda[PDA_WORDS]; - - /* Binary block begins after the 0x1A marker */ - ptr = image; - while (*ptr++ != TEXT_END); - first_block = ptr; - - /* Read the PDA from EEPROM */ - if (secondary) { - ret = hermes_read_pda(hw, pda, PDA_ADDR, sizeof(pda), 1); - if (ret) - return ret; - } - - /* Stop the firmware, so that it can be safely rewritten */ - ret = spectrum_reset(link, 1); - if (ret) - return ret; - - /* Program the adapter with new firmware */ - ret = hermes_program(hw, first_block, end); - if (ret) - return ret; - - /* Write the PDA to the adapter */ - if (secondary) { - size_t len = hermes_blocks_length(first_block); - ptr = first_block + len; - ret = hermes_apply_pda(hw, ptr, pda); - if (ret) - return ret; - } - - /* Run the firmware */ - ret = spectrum_reset(link, 0); - if (ret) - return ret; - - /* Reset hermes chip and make sure it responds */ - ret = hermes_init(hw); - - /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; + struct orinoco_pccard *card = priv->card; + struct pcmcia_device *link = card->p_dev; - /* And this should work with any firmware */ - if (!hermes_present(hw)) - return -ENODEV; + /* Soft reset using COR and HCR */ + spectrum_reset(link, 0); return 0; } - -/* - * Download the firmware into the card, this also does a PCMCIA soft - * reset on the card, to make sure it's in a sane state. - */ static int -spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) -{ - int ret; - const struct firmware *fw_entry; - - if (request_firmware(&fw_entry, primary_fw_name, - &handle_to_dev(link)) != 0) { - printk(KERN_ERR PFX "Cannot find firmware: %s\n", - primary_fw_name); - return -ENOENT; - } - - /* Load primary firmware */ - ret = spectrum_dl_image(hw, link, fw_entry->data, - fw_entry->data + fw_entry->size, 0); - release_firmware(fw_entry); - if (ret) { - printk(KERN_ERR PFX "Primary firmware download failed\n"); - return ret; - } - - if (request_firmware(&fw_entry, secondary_fw_name, - &handle_to_dev(link)) != 0) { - printk(KERN_ERR PFX "Cannot find firmware: %s\n", - secondary_fw_name); - return -ENOENT; - } - - /* Load secondary firmware */ - ret = spectrum_dl_image(hw, link, fw_entry->data, - fw_entry->data + fw_entry->size, 1); - release_firmware(fw_entry); - if (ret) { - printk(KERN_ERR PFX "Secondary firmware download failed\n"); - } - - return ret; -} - -/********************************************************************/ -/* Device methods */ -/********************************************************************/ - -static int -spectrum_cs_hard_reset(struct orinoco_private *priv) +spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) { struct orinoco_pccard *card = priv->card; struct pcmcia_device *link = card->p_dev; - int err; - if (!hermes_present(&priv->hw)) { - /* The firmware needs to be reloaded */ - if (spectrum_dl_firmware(&priv->hw, link) != 0) { - printk(KERN_ERR PFX "Firmware download failed\n"); - err = -ENODEV; - } - } else { - /* Soft reset using COR and HCR */ - spectrum_reset(link, 0); - } - - return 0; + return spectrum_reset(link, idle); } /********************************************************************/ @@ -315,7 +182,9 @@ spectrum_cs_probe(struct pcmcia_device *link) struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); + dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + spectrum_cs_hard_reset, + spectrum_cs_stop_firmware); if (! dev) return -ENOMEM; priv = netdev_priv(dev); @@ -517,7 +386,7 @@ spectrum_cs_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; - /* Reset card and download firmware */ + /* Reset card */ if (spectrum_cs_hard_reset(priv) != 0) { goto failed; } -- cgit v1.2.3 From 6eecad77861b193bcfc109de12835ca0bddf7c58 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:56 +0100 Subject: orinoco: Fix transmit for Agere/Lucent with fw 9.x The tx control word has moved into the 802.11 header area on these firmwares. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes.h | 1 + drivers/net/wireless/orinoco.c | 59 +++++++++++++++++++++++++++++++----------- drivers/net/wireless/orinoco.h | 1 + 3 files changed, 46 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 287f5363fda..1d0c5840f82 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -179,6 +179,7 @@ #define HERMES_802_11_OFFSET (14) #define HERMES_802_3_OFFSET (14+32) #define HERMES_802_2_OFFSET (14+32+14) +#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2) #define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_BADCRC (0x0001) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 306697aa333..b83415daa72 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -722,7 +722,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) u16 txfid = priv->txfid; struct ethhdr *eh; int data_off; - struct hermes_tx_descriptor desc; + int tx_control; unsigned long flags; if (! netif_running(dev)) { @@ -756,21 +756,48 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) eh = (struct ethhdr *)skb->data; - memset(&desc, 0, sizeof(desc)); - desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); - err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing Tx descriptor " - "to BAP\n", dev->name, err); - goto busy; - } + tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - /* Clear the 802.11 header and data length fields - some - * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused - * if this isn't done. */ - hermes_clear_words(hw, HERMES_DATA0, - HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + if (priv->has_alt_txcntl) { + /* WPA enabled firmwares have tx_cntl at the end of + * the 802.11 header. So write zeroed descriptor and + * 802.11 header at the same time + */ + char desc[HERMES_802_3_OFFSET]; + __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET]; + + memset(&desc, 0, sizeof(desc)); + + *txcntl = cpu_to_le16(tx_control); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), + txfid, 0); + if (err) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx " + "descriptor to BAP\n", dev->name, err); + goto busy; + } + } else { + struct hermes_tx_descriptor desc; + + memset(&desc, 0, sizeof(desc)); + + desc.tx_control = cpu_to_le16(tx_control); + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), + txfid, 0); + if (err) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error %d writing Tx " + "descriptor to BAP\n", dev->name, err); + goto busy; + } + + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + } /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ @@ -2528,6 +2555,7 @@ static int determine_firmware(struct net_device *dev) priv->has_ibss = 1; priv->has_wep = 0; priv->has_big_wep = 0; + priv->has_alt_txcntl = 0; priv->do_fw_download = 0; /* Determine capabilities from the firmware version */ @@ -2550,6 +2578,7 @@ static int determine_firmware(struct net_device *dev) priv->has_hostscan = (firmver >= 0x8000a); priv->do_fw_download = 1; priv->broken_monitor = (firmver >= 0x80000); + priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index e0acb633e9d..f93752ffb07 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -85,6 +85,7 @@ struct orinoco_private { unsigned int has_preamble:1; unsigned int has_sensitivity:1; unsigned int has_hostscan:1; + unsigned int has_alt_txcntl:1; unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; -- cgit v1.2.3 From 3056c40426b9cd4f7c334d773d69db64e195431d Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:57 +0100 Subject: orinoco: address checkpatch typedef warning Just sprinkle the necessary structs around... Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 13 +++++++------ drivers/net/wireless/orinoco.h | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index b83415daa72..3d5570d0a26 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -279,7 +279,8 @@ static int orinoco_bss_data_allocate(struct orinoco_private *priv) return 0; priv->bss_data = - kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL); + kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(struct bss_element), + GFP_KERNEL); if (!priv->bss_data) { printk(KERN_WARNING "Out of memory allocating beacons"); return -ENOMEM; @@ -1413,8 +1414,8 @@ static void orinoco_send_wevents(struct work_struct *work) static inline void orinoco_clear_scan_results(struct orinoco_private *priv, unsigned long scan_age) { - bss_element *bss; - bss_element *tmp_bss; + struct bss_element *bss; + struct bss_element *tmp_bss; /* Blow away current list of scan results */ list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { @@ -1489,7 +1490,7 @@ static int orinoco_process_scan_results(struct net_device *dev, /* Read the entries one by one */ for (; offset + atom_len <= len; offset += atom_len) { int found = 0; - bss_element *bss = NULL; + struct bss_element *bss = NULL; /* Get next atom */ atom = (union hermes_scan_info *) (buf + offset); @@ -1511,7 +1512,7 @@ static int orinoco_process_scan_results(struct net_device *dev, /* Grab a bss off the free list */ if (!found && !list_empty(&priv->bss_free_list)) { bss = list_entry(priv->bss_free_list.next, - bss_element, list); + struct bss_element, list); list_del(priv->bss_free_list.next); list_add_tail(&bss->list, &priv->bss_list); @@ -4547,7 +4548,7 @@ static int orinoco_ioctl_getscan(struct net_device *dev, char *extra) { struct orinoco_private *priv = netdev_priv(dev); - bss_element *bss; + struct bss_element *bss; int err = 0; unsigned long flags; char *current_ev = extra; diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index f93752ffb07..584d8c92db1 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -36,11 +36,11 @@ typedef enum { FIRMWARE_TYPE_SYMBOL } fwtype_t; -typedef struct { +struct bss_element { union hermes_scan_info bss; unsigned long last_scanned; struct list_head list; -} bss_element; +}; struct orinoco_private { void *card; /* Pointer to card dependent structure */ @@ -117,7 +117,7 @@ struct orinoco_private { /* Scanning support */ struct list_head bss_list; struct list_head bss_free_list; - bss_element *bss_data; + struct bss_element *bss_data; int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ -- cgit v1.2.3 From 01632fa4af34addf78ce999eabb4430f33942ee2 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:58 +0100 Subject: orinoco: Use extended Agere scans available on 9.x series firmwares This provides more information than the standard Agere scan, including the WPA IE. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes.h | 34 +++ drivers/net/wireless/hermes_rid.h | 1 + drivers/net/wireless/orinoco.c | 448 ++++++++++++++++++++++++++++++++++---- drivers/net/wireless/orinoco.h | 9 +- 4 files changed, 448 insertions(+), 44 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 1d0c5840f82..113f3f6cb2d 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -303,6 +303,40 @@ union hermes_scan_info { struct symbol_scan_apinfo s; }; +/* Extended scan struct for HERMES_INQ_CHANNELINFO. + * wl_lkm calls this an ACS scan (Automatic Channel Select). + * Keep out of union hermes_scan_info because it is much bigger than + * the older scan structures. */ +struct agere_ext_scan_info { + __le16 reserved0; + + u8 noise; + u8 level; + u8 rx_flow; + u8 rate; + __le16 reserved1[2]; + + __le16 frame_control; + __le16 dur_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 sequence; + u8 addr4[ETH_ALEN]; + + __le16 data_length; + + /* Next 3 fields do not get filled in. */ + u8 daddr[ETH_ALEN]; + u8 saddr[ETH_ALEN]; + __le16 len_type; + + __le64 timestamp; + __le16 beacon_interval; + __le16 capabilities; + u8 data[316]; +} __attribute__ ((packed)); + #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h index 4f46b4809e5..bcd9c82fe93 100644 --- a/drivers/net/wireless/hermes_rid.h +++ b/drivers/net/wireless/hermes_rid.h @@ -85,6 +85,7 @@ #define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 #define HERMES_RID_CNFBASICRATES 0xFCB3 #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 #define HERMES_RID_CNFTICKTIME 0xFCE0 #define HERMES_RID_CNFSCANREQUEST 0xFCE1 #define HERMES_RID_CNFJOINREQUEST 0xFCE2 diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 3d5570d0a26..22718e8176f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -275,13 +275,19 @@ static inline void set_port_type(struct orinoco_private *priv) #define ORINOCO_MAX_BSS_COUNT 64 static int orinoco_bss_data_allocate(struct orinoco_private *priv) { - if (priv->bss_data) + if (priv->bss_xbss_data) return 0; - priv->bss_data = - kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(struct bss_element), - GFP_KERNEL); - if (!priv->bss_data) { + if (priv->has_ext_scan) + priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * + sizeof(struct xbss_element), + GFP_KERNEL); + else + priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * + sizeof(struct bss_element), + GFP_KERNEL); + + if (!priv->bss_xbss_data) { printk(KERN_WARNING "Out of memory allocating beacons"); return -ENOMEM; } @@ -290,18 +296,53 @@ static int orinoco_bss_data_allocate(struct orinoco_private *priv) static void orinoco_bss_data_free(struct orinoco_private *priv) { - kfree(priv->bss_data); - priv->bss_data = NULL; + kfree(priv->bss_xbss_data); + priv->bss_xbss_data = NULL; } +#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) +#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) static void orinoco_bss_data_init(struct orinoco_private *priv) { int i; INIT_LIST_HEAD(&priv->bss_free_list); INIT_LIST_HEAD(&priv->bss_list); - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list); + if (priv->has_ext_scan) + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&(PRIV_XBSS[i].list), + &priv->bss_free_list); + else + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&(PRIV_BSS[i].list), + &priv->bss_free_list); + +} + +static inline u8 *orinoco_get_ie(u8 *data, size_t len, + enum ieee80211_mfie eid) +{ + u8 *p = data; + while ((p + 2) < (data + len)) { + if (p[0] == eid) + return p; + p += p[1] + 2; + } + return NULL; +} + +#define WPA_OUI_TYPE "\x00\x50\xF2\x01" +#define WPA_SELECTOR_LEN 4 +static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) +{ + u8 *p = data; + while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { + if ((p[0] == MFIE_TYPE_GENERIC) && + (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) + return p; + p += p[1] + 2; + } + return NULL; } @@ -1414,18 +1455,72 @@ static void orinoco_send_wevents(struct work_struct *work) static inline void orinoco_clear_scan_results(struct orinoco_private *priv, unsigned long scan_age) { - struct bss_element *bss; - struct bss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; + if (priv->has_ext_scan) { + struct xbss_element *bss; + struct xbss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, + &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(&bss->bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } } + } else { + struct bss_element *bss; + struct bss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, + &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(&bss->bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } + } + } +} + +static void orinoco_add_ext_scan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *atom) +{ + struct xbss_element *bss = NULL; + int found = 0; + + /* Try to update an existing bss first */ + list_for_each_entry(bss, &priv->bss_list, list) { + if (compare_ether_addr(bss->bss.bssid, atom->bssid)) + continue; + /* ESSID lengths */ + if (bss->bss.data[1] != atom->data[1]) + continue; + if (memcmp(&bss->bss.data[2], &atom->data[2], + atom->data[1])) + continue; + found = 1; + break; + } + + /* Grab a bss off the free list */ + if (!found && !list_empty(&priv->bss_free_list)) { + bss = list_entry(priv->bss_free_list.next, + struct xbss_element, list); + list_del(priv->bss_free_list.next); + + list_add_tail(&bss->list, &priv->bss_list); + } + + if (bss) { + /* Always update the BSS to get latest beacon info */ + memcpy(&bss->bss, atom, sizeof(bss->bss)); + bss->last_scanned = jiffies; } } @@ -1700,6 +1795,63 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) kfree(buf); } break; + case HERMES_INQ_CHANNELINFO: + { + struct agere_ext_scan_info *bss; + + if (!priv->scan_inprogress) { + printk(KERN_DEBUG "%s: Got chaninfo without scan, " + "len=%d\n", dev->name, len); + break; + } + + /* An empty result indicates that the scan is complete */ + if (len == 0) { + union iwreq_data wrqu; + + /* Scan is no longer in progress */ + priv->scan_inprogress = 0; + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + break; + } + + /* Sanity check */ + else if (len > sizeof(*bss)) { + printk(KERN_WARNING + "%s: Ext scan results too large (%d bytes). " + "Truncating results to %zd bytes.\n", + dev->name, len, sizeof(*bss)); + len = sizeof(*bss); + } else if (len < (offsetof(struct agere_ext_scan_info, + data) + 2)) { + /* Drop this result now so we don't have to + * keep checking later */ + printk(KERN_WARNING + "%s: Ext scan results too short (%d bytes)\n", + dev->name, len); + break; + } + + bss = kmalloc(sizeof(*bss), GFP_ATOMIC); + if (bss == NULL) + break; + + /* Read scan data */ + err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, + infofid, sizeof(info)); + if (err) { + kfree(bss); + break; + } + + orinoco_add_ext_scan_result(priv, bss); + + kfree(bss); + break; + } case HERMES_INQ_SEC_STAT_AGERE: /* Security status (Agere specific) */ /* Ignore this frame for now */ @@ -2557,6 +2709,7 @@ static int determine_firmware(struct net_device *dev) priv->has_wep = 0; priv->has_big_wep = 0; priv->has_alt_txcntl = 0; + priv->has_ext_scan = 0; priv->do_fw_download = 0; /* Determine capabilities from the firmware version */ @@ -2580,7 +2733,7 @@ static int determine_firmware(struct net_device *dev) priv->do_fw_download = 1; priv->broken_monitor = (firmver >= 0x80000); priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - + priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ @@ -2735,6 +2888,12 @@ static int orinoco_init(struct net_device *dev) printk("40-bit key\n"); } + /* Now we have the firmware capabilities, allocate appropiate + * sized scan buffers */ + if (orinoco_bss_data_allocate(priv)) + goto out; + orinoco_bss_data_init(priv); + /* Get the MAC address */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev->dev_addr); @@ -2885,10 +3044,6 @@ struct net_device priv->card = NULL; priv->dev = device; - if (orinoco_bss_data_allocate(priv)) - goto err_out_free; - orinoco_bss_data_init(priv); - /* Setup / override net_device fields */ dev->init = orinoco_init; dev->hard_start_xmit = orinoco_xmit; @@ -2924,10 +3079,6 @@ struct net_device priv->last_linkstatus = 0xffff; return dev; - -err_out_free: - free_netdev(dev); - return NULL; } void free_orinocodev(struct net_device *dev) @@ -4375,7 +4526,25 @@ static int orinoco_ioctl_setscan(struct net_device *dev, if (err) break; - err = hermes_inquire(hw, HERMES_INQ_SCAN); + if (priv->has_ext_scan) { + /* Clear scan results at the start of + * an extended scan */ + orinoco_clear_scan_results(priv, + msecs_to_jiffies(15000)); + + /* TODO: Is this available on older firmware? + * Can we use it to scan specific channels + * for IW_SCAN_THIS_FREQ? */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANCHANNELS2GHZ, + 0x7FFF); + if (err) + goto out; + + err = hermes_inquire(hw, + HERMES_INQ_CHANNELINFO); + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); break; } } else @@ -4541,6 +4710,171 @@ static inline char *orinoco_translate_scan(struct net_device *dev, return current_ev; } +static inline char *orinoco_translate_ext_scan(struct net_device *dev, + struct iw_request_info *info, + char *current_ev, + char *end_buf, + struct agere_ext_scan_info *bss, + unsigned int last_scanned) +{ + u16 capabilities; + u16 channel; + struct iw_event iwe; /* Temporary buffer */ + char custom[MAX_CUSTOM_LEN]; + u8 *ie; + + memset(&iwe, 0, sizeof(iwe)); + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + /* Add the ESSID */ + ie = bss->data; + iwe.u.data.length = ie[1]; + if (iwe.u.data.length) { + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, &ie[2]); + } + + /* Add mode */ + capabilities = le16_to_cpu(bss->capabilities); + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + iwe.cmd = SIOCGIWMODE; + if (capabilities & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_UINT_LEN); + } + + ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET); + channel = ie ? ie[2] : 0; + if ((channel >= 1) && (channel <= NUM_CHANNELS)) { + /* Add channel and frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + + iwe.u.freq.m = channel_frequency[channel-1] * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + } + + /* Add quality statistics. level and noise in dB. No link quality */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; + iwe.u.qual.level = bss->level - 0x95; + iwe.u.qual.noise = bss->noise - 0x95; + /* Wireless tools prior to 27.pre22 will show link quality + * anyway, so we provide a reasonable value. */ + if (iwe.u.qual.level > iwe.u.qual.noise) + iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; + else + iwe.u.qual.qual = 0; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, + &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (capabilities & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, NULL); + + /* WPA IE */ + ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); + if (ie) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie[1] + 2; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie); + } + + /* RSN IE */ + ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN); + if (ie) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie[1] + 2; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, ie); + } + + ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES); + if (ie) { + char *p = current_ev + iwe_stream_lcp_len(info); + int i; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + for (i = 2; i < (ie[1] + 2); i++) { + iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); + p = iwe_stream_add_value(info, current_ev, p, end_buf, + &iwe, IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if (p > (current_ev + iwe_stream_lcp_len(info))) + current_ev = p; + } + + /* Timestamp */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "tsf=%016llx", + le64_to_cpu(bss->timestamp)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Beacon interval */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "bcn_int=%d", + le16_to_cpu(bss->beacon_interval)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Capabilites */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + "capab=0x%04x", + capabilities); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(info, current_ev, end_buf, + &iwe, custom); + + return current_ev; +} + /* Return results of a scan */ static int orinoco_ioctl_getscan(struct net_device *dev, struct iw_request_info *info, @@ -4548,7 +4882,6 @@ static int orinoco_ioctl_getscan(struct net_device *dev, char *extra) { struct orinoco_private *priv = netdev_priv(dev); - struct bss_element *bss; int err = 0; unsigned long flags; char *current_ev = extra; @@ -4568,18 +4901,47 @@ static int orinoco_ioctl_getscan(struct net_device *dev, goto out; } - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate to WE format this entry */ - current_ev = orinoco_translate_scan(dev, info, current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a bigger buffer */ - err = -E2BIG; - goto out; + if (priv->has_ext_scan) { + struct xbss_element *bss; + + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate this entry to WE format */ + current_ev = + orinoco_translate_ext_scan(dev, info, + current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); + + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) + <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a + * bigger buffer */ + err = -E2BIG; + goto out; + } + } + + } else { + struct bss_element *bss; + + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate this entry to WE format */ + current_ev = orinoco_translate_scan(dev, info, + current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); + + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) + <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a + * bigger buffer */ + err = -E2BIG; + goto out; + } } } diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 584d8c92db1..f510994ea9f 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -42,6 +42,12 @@ struct bss_element { struct list_head list; }; +struct xbss_element { + struct agere_ext_scan_info bss; + unsigned long last_scanned; + struct list_head list; +}; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ struct device *dev; @@ -86,6 +92,7 @@ struct orinoco_private { unsigned int has_sensitivity:1; unsigned int has_hostscan:1; unsigned int has_alt_txcntl:1; + unsigned int has_ext_scan:1; unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; @@ -117,7 +124,7 @@ struct orinoco_private { /* Scanning support */ struct list_head bss_list; struct list_head bss_free_list; - struct bss_element *bss_data; + void *bss_xbss_data; int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ -- cgit v1.2.3 From 4ae6ee2d72e4904909d63c6ebb0240b254b72e85 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:27:59 +0100 Subject: orinoco: Don't use boolean parameter to record encoding type For WPA support we need to encode NONE, WEP and TKIP in the encoding parameter. In anticipation of this we need to change the usage away from the current boolean usage. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 31 +++++++++++++++++++------------ drivers/net/wireless/orinoco.h | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 22718e8176f..b853ba0cd4e 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2100,8 +2100,9 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) int err = 0; int master_wep_flag; int auth_flag; + int enc_flag; - if (priv->wep_on) + if (priv->encode_alg == IW_ENCODE_ALG_WEP) __orinoco_hw_setup_wepkeys(priv); if (priv->wep_restrict) @@ -2109,9 +2110,14 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) else auth_flag = HERMES_AUTH_OPEN; + if (priv->encode_alg == IW_ENCODE_ALG_WEP) + enc_flag = 1; + else + enc_flag = 0; + switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->wep_on) { + if (priv->encode_alg == IW_ENCODE_ALG_WEP) { /* Enable the shared-key authentication. */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION_AGERE, @@ -2119,14 +2125,14 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPENABLED_AGERE, - priv->wep_on); + enc_flag); if (err) return err; break; case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->wep_on) { + if (priv->encode_alg == IW_ENCODE_ALG_WEP) { if (priv->wep_restrict || (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | @@ -3008,7 +3014,7 @@ static int orinoco_init(struct net_device *dev) priv->channel = 0; /* use firmware default */ priv->promiscuous = 0; - priv->wep_on = 0; + priv->encode_alg = IW_ENCODE_ALG_NONE; priv->tx_key = 0; /* Make the hardware available, as long as it hasn't been @@ -3497,7 +3503,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct orinoco_private *priv = netdev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; - int enable = priv->wep_on; + int encode_alg = priv->encode_alg; int restricted = priv->wep_restrict; u16 xlen = 0; int err = -EINPROGRESS; /* Call commit handler */ @@ -3531,9 +3537,9 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, xlen = 0; /* Switch on WEP if off */ - if ((!enable) && (xlen > 0)) { + if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { setindex = index; - enable = 1; + encode_alg = IW_ENCODE_ALG_WEP; } } else { /* Important note : if the user do "iwconfig eth0 enc off", @@ -3555,7 +3561,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - enable = 0; + encode_alg = IW_ENCODE_ALG_NONE; if (erq->flags & IW_ENCODE_OPEN) restricted = 0; if (erq->flags & IW_ENCODE_RESTRICTED) @@ -3570,14 +3576,15 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, priv->tx_key = setindex; /* Try fast key change if connected and only keys are changed */ - if (priv->wep_on && enable && (priv->wep_restrict == restricted) && + if ((priv->encode_alg == encode_alg) && + (priv->wep_restrict == restricted) && netif_carrier_ok(dev)) { err = __orinoco_hw_setup_wepkeys(priv); /* No need to commit if successful */ goto out; } - priv->wep_on = enable; + priv->encode_alg = encode_alg; priv->wep_restrict = restricted; out: @@ -3606,7 +3613,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, index = priv->tx_key; erq->flags = 0; - if (! priv->wep_on) + if (!priv->encode_alg) erq->flags |= IW_ENCODE_DISABLED; erq->flags |= index + 1; diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index f510994ea9f..5605fd30b81 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -100,7 +100,7 @@ struct orinoco_private { /* Configuration paramaters */ u32 iw_mode; int prefer_port3; - u16 wep_on, wep_restrict, tx_key; + u16 encode_alg, wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; int bitratemode; char nick[IW_ESSID_MAX_SIZE+1]; -- cgit v1.2.3 From 6cd90b1cac290c64a93b7e992bb1ef495988465f Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:28:00 +0100 Subject: orinoco: Split wevent work thread from wevent sending This allows us to send more wevents from the work thread. We will need to do this to support WPA. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index b853ba0cd4e..21bed6c28ad 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1424,34 +1424,38 @@ static void orinoco_join_ap(struct work_struct *work) } /* Send new BSSID to userspace */ -static void orinoco_send_wevents(struct work_struct *work) +static void orinoco_send_bssid_wevent(struct orinoco_private *priv) { - struct orinoco_private *priv = - container_of(work, struct orinoco_private, wevent_work); struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; union iwreq_data wrqu; int err; - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return; err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) - goto out; + return; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +} + +static void orinoco_send_wevents(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, wevent_work); + unsigned long flags; + + if (orinoco_lock(priv, &flags) != 0) + return; + + orinoco_send_bssid_wevent(priv); - out: orinoco_unlock(priv, &flags); } - static inline void orinoco_clear_scan_results(struct orinoco_private *priv, unsigned long scan_age) { -- cgit v1.2.3 From 409644a98bfffef79985f2c39924a06288b1dfcf Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:28:01 +0100 Subject: orinoco: Use a macro to define wireless handlers The macro identifiers for the various ioctls required for WPA support are longer than those currently used by the driver. This makes it messy to keep line length below 80 character. By defining a macro to initialise the handler table, we recover the common text. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 66 ++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 21bed6c28ad..e91e240b637 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -5043,39 +5043,41 @@ static const struct iw_priv_args orinoco_privtab[] = { * Structures to export the Wireless Handlers */ +#define STD_IW_HANDLER(id, func) \ + [IW_IOCTL_IDX(id)] = (iw_handler) func static const iw_handler orinoco_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_commit, - [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getname, - [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfreq, - [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfreq, - [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setmode, - [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getmode, - [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, - [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, - [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, - [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, - [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, - [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, - [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, - [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, - [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, - [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getscan, - [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setessid, - [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getessid, - [SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setnick, - [SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getnick, - [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrate, - [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrate, - [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrts, - [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrts, - [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfrag, - [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfrag, - [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getretry, - [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setiwencode, - [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwencode, - [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setpower, - [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getpower, + STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), + STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), + STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), + STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), + STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), + STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), + STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), + STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), + STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), + STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), + STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), + STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), + STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), + STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), + STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), + STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), + STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), + STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), + STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), + STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), + STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), + STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), + STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), + STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), + STD_IW_HANDLER(SIOCGIWRTS, orinoco_ioctl_getrts), + STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag), + STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag), + STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry), + STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), + STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), + STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), + STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), }; -- cgit v1.2.3 From d03032af511c56d3c1580fa4f54f6285f650e638 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:28:02 +0100 Subject: orinoco: Add WE-18 ioctls for WPA Includes basic plumbing to get the data into firmware, and retrieve it. SIOCxIWGENIE simply record (and return) the IE, and do not act on it. SIOCxIWENCODEEXT, SIOCxIWAUTH and SIOCSIWMLME should be as functional as the driver will support. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/hermes_rid.h | 16 ++ drivers/net/wireless/orinoco.c | 526 +++++++++++++++++++++++++++++++++++++- drivers/net/wireless/orinoco.h | 20 ++ 3 files changed, 554 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h index bcd9c82fe93..42eb67dea1d 100644 --- a/drivers/net/wireless/hermes_rid.h +++ b/drivers/net/wireless/hermes_rid.h @@ -30,6 +30,7 @@ #define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 #define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21 #define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 +#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22 #define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 #define HERMES_RID_CNFDEFAULTKEY0 0xFC24 #define HERMES_RID_CNFDEFAULTKEY1 0xFC25 @@ -85,7 +86,16 @@ #define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2 #define HERMES_RID_CNFBASICRATES 0xFCB3 #define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4 +#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5 +#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6 +#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7 +#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8 +#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9 +#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA +#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB #define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2 +#define HERMES_RID_CNFDISASSOCIATE 0xFCC8 #define HERMES_RID_CNFTICKTIME 0xFCE0 #define HERMES_RID_CNFSCANREQUEST 0xFCE1 #define HERMES_RID_CNFJOINREQUEST 0xFCE2 @@ -138,6 +148,12 @@ #define HERMES_RID_CURRENTTXRATE6 0xFD85 #define HERMES_RID_OWNMACADDR 0xFD86 #define HERMES_RID_SCANRESULTSTABLE 0xFD88 +#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89 +#define HERMES_RID_CURRENT_WPA_IE 0xFD8A +#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B +#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C +#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D +#define HERMES_RID_TXQUEUEEMPTY 0xFD91 #define HERMES_RID_PHYTYPE 0xFDC0 #define HERMES_RID_CURRENTCHANNEL 0xFDC1 #define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index e91e240b637..36b1dc2db89 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -2038,7 +2039,7 @@ static int __orinoco_hw_set_wap(struct orinoco_private *priv) } /* Change the WEP keys and/or the current keys. Can be called - * either from __orinoco_hw_setup_wep() or directly from + * either from __orinoco_hw_setup_enc() or directly from * orinoco_ioctl_setiwencode(). In the later case the association * with the AP is not broken (if the firmware can handle it), * which is needed for 802.1x implementations. */ @@ -2098,7 +2099,7 @@ static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) return 0; } -static int __orinoco_hw_setup_wep(struct orinoco_private *priv) +static int __orinoco_hw_setup_enc(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; @@ -2106,7 +2107,8 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) int auth_flag; int enc_flag; - if (priv->encode_alg == IW_ENCODE_ALG_WEP) + /* Setup WEP keys for WEP and WPA */ + if (priv->encode_alg) __orinoco_hw_setup_wepkeys(priv); if (priv->wep_restrict) @@ -2114,7 +2116,9 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) else auth_flag = HERMES_AUTH_OPEN; - if (priv->encode_alg == IW_ENCODE_ALG_WEP) + if (priv->wpa_enabled) + enc_flag = 2; + else if (priv->encode_alg == IW_ENCODE_ALG_WEP) enc_flag = 1; else enc_flag = 0; @@ -2132,6 +2136,16 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) enc_flag); if (err) return err; + + if (priv->has_wpa) { + /* Set WPA key management */ + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE, + priv->key_mgmt); + if (err) + return err; + } + break; case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ @@ -2168,6 +2182,84 @@ static int __orinoco_hw_setup_wep(struct orinoco_private *priv) return 0; } +/* key must be 32 bytes, including the tx and rx MIC keys. + * rsc must be 8 bytes + * tsc must be 8 bytes or NULL + */ +static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, + u8 *key, u8 *rsc, u8 *tsc) +{ + struct { + __le16 idx; + u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 key[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; + u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; + } __attribute__ ((packed)) buf; + int ret; + int err; + int k; + u16 xmitting; + + key_idx &= 0x3; + + if (set_tx) + key_idx |= 0x8000; + + buf.idx = cpu_to_le16(key_idx); + memcpy(buf.key, key, + sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); + + if (rsc == NULL) + memset(buf.rsc, 0, sizeof(buf.rsc)); + else + memcpy(buf.rsc, rsc, sizeof(buf.rsc)); + + if (tsc == NULL) { + memset(buf.tsc, 0, sizeof(buf.tsc)); + buf.tsc[4] = 0x10; + } else { + memcpy(buf.tsc, tsc, sizeof(buf.tsc)); + } + + /* Wait upto 100ms for tx queue to empty */ + k = 100; + do { + k--; + udelay(1000); + ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, + &xmitting); + if (ret) + break; + } while ((k > 0) && xmitting); + + if (k == 0) + ret = -ETIMEDOUT; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE, + &buf); + + return ret ? ret : err; +} + +static int orinoco_clear_tkip_key(struct orinoco_private *priv, + int key_idx) +{ + hermes_t *hw = &priv->hw; + int err; + + memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, + key_idx); + if (err) + printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n", + priv->ndev->name, err, key_idx); + return err; +} + static int __orinoco_program_rids(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -2364,10 +2456,10 @@ static int __orinoco_program_rids(struct net_device *dev) } /* Set up encryption */ - if (priv->has_wep) { - err = __orinoco_hw_setup_wep(priv); + if (priv->has_wep || priv->has_wpa) { + err = __orinoco_hw_setup_enc(priv); if (err) { - printk(KERN_ERR "%s: Error %d activating WEP\n", + printk(KERN_ERR "%s: Error %d activating encryption\n", dev->name, err); return err; } @@ -2720,6 +2812,7 @@ static int determine_firmware(struct net_device *dev) priv->has_big_wep = 0; priv->has_alt_txcntl = 0; priv->has_ext_scan = 0; + priv->has_wpa = 0; priv->do_fw_download = 0; /* Determine capabilities from the firmware version */ @@ -2744,6 +2837,7 @@ static int determine_firmware(struct net_device *dev) priv->broken_monitor = (firmver >= 0x80000); priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_wpa = (firmver >= 0x9002a); /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ @@ -2897,6 +2991,8 @@ static int orinoco_init(struct net_device *dev) else printk("40-bit key\n"); } + if (priv->has_wpa) + printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); /* Now we have the firmware capabilities, allocate appropiate * sized scan buffers */ @@ -3020,6 +3116,11 @@ static int orinoco_init(struct net_device *dev) priv->promiscuous = 0; priv->encode_alg = IW_ENCODE_ALG_NONE; priv->tx_key = 0; + priv->wpa_enabled = 0; + priv->tkip_cm_active = 0; + priv->key_mgmt = 0; + priv->wpa_ie_len = 0; + priv->wpa_ie = NULL; /* Make the hardware available, as long as it hasn't been * removed elsewhere (e.g. by PCMCIA hot unplug) */ @@ -3095,6 +3196,8 @@ void free_orinocodev(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); + priv->wpa_ie_len = 0; + kfree(priv->wpa_ie); orinoco_bss_data_free(priv); free_netdev(dev); } @@ -3406,7 +3509,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, memset(range, 0, sizeof(struct iw_range)); range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 14; + range->we_version_source = 22; /* Set available channels/frequencies */ range->num_channels = NUM_CHANNELS; @@ -3436,6 +3539,9 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, } } + if (priv->has_wpa) + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; + if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){ /* Quality stats meaningless in ad-hoc mode */ } else { @@ -3528,6 +3634,10 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; + /* Clear any TKIP key we have */ + if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) + (void) orinoco_clear_tkip_key(priv, setindex); + if (erq->length > 0) { if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; @@ -4192,6 +4302,399 @@ static int orinoco_ioctl_getpower(struct net_device *dev, return err; } +static int orinoco_ioctl_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, alg = ext->alg, set_key = 1; + unsigned long flags; + int err = -EINVAL; + u16 key_len; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Determine and validate the key index */ + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if ((idx < 1) || (idx > WEP_KEYS)) + goto out; + idx--; + } else + idx = priv->tx_key; + + if (encoding->flags & IW_ENCODE_DISABLED) + alg = IW_ENCODE_ALG_NONE; + + if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { + /* Clear any TKIP TX key we had */ + (void) orinoco_clear_tkip_key(priv, priv->tx_key); + } + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + priv->tx_key = idx; + set_key = ((alg == IW_ENCODE_ALG_TKIP) || + (ext->key_len > 0)) ? 1 : 0; + } + + if (set_key) { + /* Set the requested key first */ + switch (alg) { + case IW_ENCODE_ALG_NONE: + priv->encode_alg = alg; + priv->keys[idx].len = 0; + break; + + case IW_ENCODE_ALG_WEP: + if (ext->key_len > SMALL_KEY_SIZE) + key_len = LARGE_KEY_SIZE; + else if (ext->key_len > 0) + key_len = SMALL_KEY_SIZE; + else + goto out; + + priv->encode_alg = alg; + priv->keys[idx].len = cpu_to_le16(key_len); + + key_len = min(ext->key_len, key_len); + + memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); + memcpy(priv->keys[idx].data, ext->key, key_len); + break; + + case IW_ENCODE_ALG_TKIP: + { + hermes_t *hw = &priv->hw; + u8 *tkip_iv = NULL; + + if (!priv->has_wpa || + (ext->key_len > sizeof(priv->tkip_key[0]))) + goto out; + + priv->encode_alg = alg; + memset(&priv->tkip_key[idx], 0, + sizeof(priv->tkip_key[idx])); + memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); + + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) + tkip_iv = &ext->rx_seq[0]; + + err = __orinoco_hw_set_tkip_key(hw, idx, + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, + (u8 *) &priv->tkip_key[idx], + tkip_iv, NULL); + if (err) + printk(KERN_ERR "%s: Error %d setting TKIP key" + "\n", dev->name, err); + + goto out; + } + default: + goto out; + } + } + err = -EINPROGRESS; + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, max_key_len; + unsigned long flags; + int err; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + err = -EINVAL; + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if ((idx < 1) || (idx > WEP_KEYS)) + goto out; + idx--; + } else + idx = priv->tx_key; + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + ext->alg = priv->encode_alg; + switch (priv->encode_alg) { + case IW_ENCODE_ALG_NONE: + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + break; + case IW_ENCODE_ALG_WEP: + ext->key_len = min(le16_to_cpu(priv->keys[idx].len), + (u16) max_key_len); + memcpy(ext->key, priv->keys[idx].data, ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + break; + case IW_ENCODE_ALG_TKIP: + ext->key_len = min((u16) sizeof(struct orinoco_tkip_key), + (u16) max_key_len); + memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); + encoding->flags |= IW_ENCODE_ENABLED; + break; + } + + err = 0; + out: + orinoco_unlock(priv, &flags); + + return err; +} + +static int orinoco_ioctl_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_param *param = &wrqu->param; + unsigned long flags; + int ret = -EINPROGRESS; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_PRIVACY_INVOKED: + case IW_AUTH_DROP_UNENCRYPTED: + /* + * orinoco does not use these parameters + */ + break; + + case IW_AUTH_KEY_MGMT: + /* wl_lkm implies value 2 == PSK for Hermes I + * which ties in with WEXT + * no other hints tho :( + */ + priv->key_mgmt = param->value; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + /* When countermeasures are enabled, shut down the + * card; when disabled, re-enable the card. This must + * take effect immediately. + * + * TODO: Make sure that the EAPOL message is getting + * out before card disabled + */ + if (param->value) { + priv->tkip_cm_active = 1; + ret = hermes_enable_port(hw, 0); + } else { + priv->tkip_cm_active = 0; + ret = hermes_disable_port(hw, 0); + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (param->value & IW_AUTH_ALG_SHARED_KEY) + priv->wep_restrict = 1; + else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) + priv->wep_restrict = 0; + else + ret = -EINVAL; + break; + + case IW_AUTH_WPA_ENABLED: + if (priv->has_wpa) { + priv->wpa_enabled = param->value ? 1 : 0; + } else { + if (param->value) + ret = -EOPNOTSUPP; + /* else silently accept disable of WPA */ + priv->wpa_enabled = 0; + } + break; + + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct iw_param *param = &wrqu->param; + unsigned long flags; + int ret = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + param->value = priv->key_mgmt; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + param->value = priv->tkip_cm_active; + break; + + case IW_AUTH_80211_AUTH_ALG: + if (priv->wep_restrict) + param->value = IW_AUTH_ALG_SHARED_KEY; + else + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = priv->wpa_enabled; + break; + + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + +static int orinoco_ioctl_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + u8 *buf; + unsigned long flags; + int err = 0; + + if ((wrqu->data.length > MAX_WPA_IE_LEN) || + (wrqu->data.length && (extra == NULL))) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if (wrqu->data.length) { + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto out; + } + + memcpy(buf, extra, wrqu->data.length); + kfree(priv->wpa_ie); + priv->wpa_ie = buf; + priv->wpa_ie_len = wrqu->data.length; + } else { + kfree(priv->wpa_ie); + priv->wpa_ie = NULL; + priv->wpa_ie_len = 0; + } + + if (priv->wpa_ie) { + /* Looks like wl_lkm wants to check the auth alg, and + * somehow pass it to the firmware. + * Instead it just calls the key mgmt rid + * - we do this in set auth. + */ + } + +out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { + wrqu->data.length = 0; + goto out; + } + + if (wrqu->data.length < priv->wpa_ie_len) { + err = -E2BIG; + goto out; + } + + wrqu->data.length = priv->wpa_ie_len; + memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); + +out: + orinoco_unlock(priv, &flags); + return err; +} + +static int orinoco_ioctl_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct orinoco_private *priv = netdev_priv(dev); + hermes_t *hw = &priv->hw; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + unsigned long flags; + int ret = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + /* silently ignore */ + break; + + case IW_MLME_DISASSOC: + { + struct { + u8 addr[ETH_ALEN]; + __le16 reason_code; + } __attribute__ ((packed)) buf; + + memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); + buf.reason_code = cpu_to_le16(mlme->reason_code); + ret = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFDISASSOCIATE, + &buf); + break; + } + default: + ret = -EOPNOTSUPP; + } + + orinoco_unlock(priv, &flags); + return ret; +} + static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, @@ -5078,6 +5581,13 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), + STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), + STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), + STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), + STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), + STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), + STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), + STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), }; diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 5605fd30b81..bfab88f5136 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -30,6 +30,15 @@ struct orinoco_key { char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); +#define TKIP_KEYLEN 16 +#define MIC_KEYLEN 8 + +struct orinoco_tkip_key { + u8 tkip[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; +}; + typedef enum { FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_INTERSIL, @@ -93,6 +102,7 @@ struct orinoco_private { unsigned int has_hostscan:1; unsigned int has_alt_txcntl:1; unsigned int has_ext_scan:1; + unsigned int has_wpa:1; unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; @@ -128,6 +138,16 @@ struct orinoco_private { int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ + + /* WPA support */ + u8 *wpa_ie; + int wpa_ie_len; + + struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; + + unsigned int wpa_enabled:1; + unsigned int tkip_cm_active:1; + unsigned int key_mgmt:3; }; #ifdef ORINOCO_DEBUG -- cgit v1.2.3 From 06009fda9fde1b97074ab3d932d0468396bf5d10 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:28:03 +0100 Subject: orinoco: Send association events to userspace Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 36b1dc2db89..5e6f90ba908 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1443,6 +1443,66 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv) wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } +static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + u8 buf[88]; + u8 *ie; + + if (!priv->has_wpa) + return; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, + sizeof(buf), NULL, &buf); + if (err != 0) + return; + + ie = orinoco_get_wpa_ie(buf, sizeof(buf)); + if (ie) { + int rem = sizeof(buf) - (ie - &buf[0]); + wrqu.data.length = ie[1] + 2; + if (wrqu.data.length > rem) + wrqu.data.length = rem; + + if (wrqu.data.length) + /* Send event to user space */ + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie); + } +} + +static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + union iwreq_data wrqu; + int err; + u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */ + u8 *ie; + + if (!priv->has_wpa) + return; + + err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, + sizeof(buf), NULL, &buf); + if (err != 0) + return; + + ie = orinoco_get_wpa_ie(buf, sizeof(buf)); + if (ie) { + int rem = sizeof(buf) - (ie - &buf[0]); + wrqu.data.length = ie[1] + 2; + if (wrqu.data.length > rem) + wrqu.data.length = rem; + + if (wrqu.data.length) + /* Send event to user space */ + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie); + } +} + static void orinoco_send_wevents(struct work_struct *work) { struct orinoco_private *priv = @@ -1452,6 +1512,8 @@ static void orinoco_send_wevents(struct work_struct *work) if (orinoco_lock(priv, &flags) != 0) return; + orinoco_send_assocreqie_wevent(priv); + orinoco_send_assocrespie_wevent(priv); orinoco_send_bssid_wevent(priv); orinoco_unlock(priv, &flags); -- cgit v1.2.3 From 31afcef385bb8bf528c6fbe05b359af9f456f02a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:28:04 +0100 Subject: orinoco: Process bulk of receive interrupt in a tasklet Read the packet data off the hardware and straight into an skb in the interrupt. We have to do this in case we don't process the tasklet in time. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 105 +++++++++++++++++++++++++++++++++-------- drivers/net/wireless/orinoco.h | 14 ++++++ 2 files changed, 100 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 5e6f90ba908..768b3945267 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1178,15 +1178,23 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; - u16 rxfid, status, fc; + u16 rxfid, status; int length; - struct hermes_rx_descriptor desc; - struct ethhdr *hdr; + struct hermes_rx_descriptor *desc; + struct orinoco_rx_data *rx_data; int err; + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if (!desc) { + printk(KERN_WARNING + "%s: Can't allocate space for RX descriptor\n", + dev->name); + goto update_stats; + } + rxfid = hermes_read_regn(hw, RXFID); - err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), + err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc), rxfid, 0); if (err) { printk(KERN_ERR "%s: error %d reading Rx descriptor. " @@ -1194,7 +1202,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto update_stats; } - status = le16_to_cpu(desc.status); + status = le16_to_cpu(desc->status); if (status & HERMES_RXSTAT_BADCRC) { DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", @@ -1205,8 +1213,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) /* Handle frames in monitor mode */ if (priv->iw_mode == IW_MODE_MONITOR) { - orinoco_rx_monitor(dev, rxfid, &desc); - return; + orinoco_rx_monitor(dev, rxfid, desc); + goto out; } if (status & HERMES_RXSTAT_UNDECRYPTABLE) { @@ -1216,15 +1224,14 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto update_stats; } - length = le16_to_cpu(desc.data_len); - fc = le16_to_cpu(desc.frame_ctl); + length = le16_to_cpu(desc->data_len); /* Sanity checks */ if (length < 3) { /* No for even an 802.2 LLC header */ /* At least on Symbol firmware with PCF we get quite a lot of these legitimately - Poll frames with no data. */ - return; + goto out; } if (length > IEEE80211_DATA_LEN) { printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", @@ -1259,6 +1266,43 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto drop; } + /* Add desc and skb to rx queue */ + rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC); + if (!rx_data) { + printk(KERN_WARNING "%s: Can't allocate RX packet\n", + dev->name); + goto drop; + } + rx_data->desc = desc; + rx_data->skb = skb; + list_add_tail(&rx_data->list, &priv->rx_list); + tasklet_schedule(&priv->rx_tasklet); + + return; + +drop: + dev_kfree_skb_irq(skb); +update_stats: + stats->rx_errors++; + stats->rx_dropped++; +out: + kfree(desc); +} + +static void orinoco_rx(struct net_device *dev, + struct hermes_rx_descriptor *desc, + struct sk_buff *skb) +{ + struct orinoco_private *priv = netdev_priv(dev); + struct net_device_stats *stats = &priv->stats; + u16 status, fc; + int length; + struct ethhdr *hdr; + + status = le16_to_cpu(desc->status); + length = le16_to_cpu(desc->data_len); + fc = le16_to_cpu(desc->frame_ctl); + /* Handle decapsulation * In most cases, the firmware tell us about SNAP frames. * For some reason, the SNAP frames sent by LinkSys APs @@ -1277,11 +1321,11 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); hdr->h_proto = htons(length); } - memcpy(hdr->h_dest, desc.addr1, ETH_ALEN); + memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); if (fc & IEEE80211_FCTL_FROMDS) - memcpy(hdr->h_source, desc.addr3, ETH_ALEN); + memcpy(hdr->h_source, desc->addr3, ETH_ALEN); else - memcpy(hdr->h_source, desc.addr2, ETH_ALEN); + memcpy(hdr->h_source, desc->addr2, ETH_ALEN); dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); @@ -1290,7 +1334,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) skb->pkt_type = PACKET_OTHERHOST; /* Process the wireless stats if needed */ - orinoco_stat_gather(dev, skb, &desc); + orinoco_stat_gather(dev, skb, desc); /* Pass the packet to the networking stack */ netif_rx(skb); @@ -1298,12 +1342,27 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) stats->rx_bytes += length; return; +} - drop: - dev_kfree_skb_irq(skb); - update_stats: - stats->rx_errors++; - stats->rx_dropped++; +static void orinoco_rx_isr_tasklet(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_rx_data *rx_data, *temp; + struct hermes_rx_descriptor *desc; + struct sk_buff *skb; + + /* extract desc and skb from queue */ + list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) { + desc = rx_data->desc; + skb = rx_data->skb; + list_del(&rx_data->list); + kfree(rx_data); + + orinoco_rx(dev, desc, skb); + + kfree(desc); + } } /********************************************************************/ @@ -3248,6 +3307,10 @@ struct net_device INIT_WORK(&priv->join_work, orinoco_join_ap); INIT_WORK(&priv->wevent_work, orinoco_send_wevents); + INIT_LIST_HEAD(&priv->rx_list); + tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, + (unsigned long) dev); + netif_carrier_off(dev); priv->last_linkstatus = 0xffff; @@ -3258,6 +3321,10 @@ void free_orinocodev(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); + /* No need to empty priv->rx_list: if the tasklet is scheduled + * when we call tasklet_kill it will run one final time, + * emptying the list */ + tasklet_kill(&priv->rx_tasklet); priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_bss_data_free(priv); diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index bfab88f5136..e0c9be3daa3 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -9,6 +9,7 @@ #define DRIVER_VERSION "0.15" +#include #include #include #include @@ -57,6 +58,14 @@ struct xbss_element { struct list_head list; }; +struct hermes_rx_descriptor; + +struct orinoco_rx_data { + struct hermes_rx_descriptor *desc; + struct sk_buff *skb; + struct list_head list; +}; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ struct device *dev; @@ -68,6 +77,11 @@ struct orinoco_private { int hw_unavailable; struct work_struct reset_work; + /* Interrupt tasklets */ + struct tasklet_struct rx_tasklet; + struct list_head rx_list; + struct orinoco_rx_data *rx_data; + /* driver state */ int open; u16 last_linkstatus; -- cgit v1.2.3 From 23edcc4147ad36f8d55f0eb79c21e245ffb9f211 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 21 Aug 2008 23:28:05 +0100 Subject: orinoco: Add MIC on TX and check on RX Use the MIC algorithm from the crypto subsystem. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 + drivers/net/wireless/hermes.h | 7 ++ drivers/net/wireless/orinoco.c | 234 ++++++++++++++++++++++++++++++++++++++--- drivers/net/wireless/orinoco.h | 2 + 4 files changed, 229 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ea7da7117f4..45bdf0b339b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -336,6 +336,8 @@ config HERMES depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 select WIRELESS_EXT select FW_LOADER + select CRYPTO + select CRYPTO_MICHAEL_MIC ---help--- A driver for 802.11b wireless cards based on the "Hermes" or Intersil HFA384x (Prism 2) MAC controller. This includes the vast diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index 113f3f6cb2d..8b13c8fef3d 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h @@ -184,13 +184,18 @@ #define HERMES_RXSTAT_ERR (0x0003) #define HERMES_RXSTAT_BADCRC (0x0001) #define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) +#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */ #define HERMES_RXSTAT_MACPORT (0x0700) #define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */ +#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */ #define HERMES_RXSTAT_MSGTYPE (0xE000) #define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ #define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ #define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ +/* Shift amount for key ID in RXSTAT and TXCTRL */ +#define HERMES_MIC_KEY_ID_SHIFT 11 + struct hermes_tx_descriptor { __le16 status; __le16 reserved1; @@ -209,6 +214,8 @@ struct hermes_tx_descriptor { #define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ #define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ #define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ +#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */ +#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */ #define HERMES_TXCTRL_ALT_RTRY (0x0020) /* Inquiry constants and data types */ diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 768b3945267..6a196c31de4 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -89,6 +89,9 @@ #include #include +#include +#include + #include "hermes_rid.h" #include "hermes_dld.h" #include "orinoco.h" @@ -243,6 +246,74 @@ struct hermes_rx_descriptor { static int __orinoco_program_rids(struct net_device *dev); static void __orinoco_set_multicast_list(struct net_device *dev); +/********************************************************************/ +/* Michael MIC crypto setup */ +/********************************************************************/ +#define MICHAEL_MIC_LEN 8 +static int orinoco_mic_init(struct orinoco_private *priv) +{ + priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); + if (IS_ERR(priv->tx_tfm_mic)) { + printk(KERN_DEBUG "orinoco_mic_init: could not allocate " + "crypto API michael_mic\n"); + priv->tx_tfm_mic = NULL; + return -ENOMEM; + } + + priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0); + if (IS_ERR(priv->rx_tfm_mic)) { + printk(KERN_DEBUG "orinoco_mic_init: could not allocate " + "crypto API michael_mic\n"); + priv->rx_tfm_mic = NULL; + return -ENOMEM; + } + + return 0; +} + +static void orinoco_mic_free(struct orinoco_private *priv) +{ + if (priv->tx_tfm_mic) + crypto_free_hash(priv->tx_tfm_mic); + if (priv->rx_tfm_mic) + crypto_free_hash(priv->rx_tfm_mic); +} + +static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, + u8 *da, u8 *sa, u8 priority, + u8 *data, size_t data_len, u8 *mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ + + if (tfm_michael == NULL) { + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } + + /* Copy header into buffer. We need the padding on the end zeroed */ + memcpy(&hdr[0], da, ETH_ALEN); + memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN); + hdr[ETH_ALEN*2] = priority; + hdr[ETH_ALEN*2+1] = 0; + hdr[ETH_ALEN*2+2] = 0; + hdr[ETH_ALEN*2+3] = 0; + + /* Use scatter gather to MIC header and data in one go */ + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, sizeof(hdr)); + sg_set_buf(&sg[1], data, data_len); + + if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr), + mic); +} + /********************************************************************/ /* Internal helper functions */ /********************************************************************/ @@ -764,7 +835,6 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) int err = 0; u16 txfid = priv->txfid; struct ethhdr *eh; - int data_off; int tx_control; unsigned long flags; @@ -797,10 +867,12 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_HLEN) goto drop; - eh = (struct ethhdr *)skb->data; - tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; + if (priv->encode_alg == IW_ENCODE_ALG_TKIP) + tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | + HERMES_TXCTRL_MIC; + if (priv->has_alt_txcntl) { /* WPA enabled firmwares have tx_cntl at the end of * the 802.11 header. So write zeroed descriptor and @@ -842,6 +914,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); } + eh = (struct ethhdr *)skb->data; + /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ struct header_struct { @@ -851,33 +925,65 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) /* Strip destination and source from the data */ skb_pull(skb, 2 * ETH_ALEN); - data_off = HERMES_802_2_OFFSET + sizeof(encaps_hdr); /* And move them to a separate header */ memcpy(&hdr.eth, eh, 2 * ETH_ALEN); hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len); memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); - err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), - txfid, HERMES_802_3_OFFSET); - if (err) { - if (net_ratelimit()) - printk(KERN_ERR "%s: Error %d writing packet " - "header to BAP\n", dev->name, err); - goto busy; + /* Insert the SNAP header */ + if (skb_headroom(skb) < sizeof(hdr)) { + printk(KERN_ERR + "%s: Not enough headroom for 802.2 headers %d\n", + dev->name, skb_headroom(skb)); + goto drop; } - } else { /* IEEE 802.3 frame */ - data_off = HERMES_802_3_OFFSET; + eh = (struct ethhdr *) skb_push(skb, sizeof(hdr)); + memcpy(eh, &hdr, sizeof(hdr)); } err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len, - txfid, data_off); + txfid, HERMES_802_3_OFFSET); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", dev->name, err); goto busy; } + /* Calculate Michael MIC */ + if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { + u8 mic_buf[MICHAEL_MIC_LEN + 1]; + u8 *mic; + size_t offset; + size_t len; + + if (skb->len % 2) { + /* MIC start is on an odd boundary */ + mic_buf[0] = skb->data[skb->len - 1]; + mic = &mic_buf[1]; + offset = skb->len - 1; + len = MICHAEL_MIC_LEN + 1; + } else { + mic = &mic_buf[0]; + offset = skb->len; + len = MICHAEL_MIC_LEN; + } + + michael_mic(priv->tx_tfm_mic, + priv->tkip_key[priv->tx_key].tx_mic, + eh->h_dest, eh->h_source, 0 /* priority */, + skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); + + /* Write the MIC */ + err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len, + txfid, HERMES_802_3_OFFSET + offset); + if (err) { + printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", + dev->name, err); + goto busy; + } + } + /* Finally, we actually initiate the send */ netif_stop_queue(dev); @@ -892,7 +998,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - stats->tx_bytes += data_off + skb->len; + stats->tx_bytes += HERMES_802_3_OFFSET + skb->len; goto ok; drop: @@ -1172,6 +1278,25 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, stats->rx_dropped++; } +/* Get tsc from the firmware */ +static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, + u8 *tsc) +{ + hermes_t *hw = &priv->hw; + int err = 0; + u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; + + if ((key < 0) || (key > 4)) + return -EINVAL; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV, + sizeof(tsc_arr), NULL, &tsc_arr); + if (!err) + memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0])); + + return err; +} + static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = netdev_priv(dev); @@ -1240,6 +1365,11 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) goto update_stats; } + /* Payload size does not include Michael MIC. Increase payload + * size to read it together with the data. */ + if (status & HERMES_RXSTAT_MIC) + length += MICHAEL_MIC_LEN; + /* We need space for the packet data itself, plus an ethernet header, plus 2 bytes so we can align the IP header on a 32bit boundary, plus 1 byte so we can read in odd length @@ -1303,6 +1433,63 @@ static void orinoco_rx(struct net_device *dev, length = le16_to_cpu(desc->data_len); fc = le16_to_cpu(desc->frame_ctl); + /* Calculate and check MIC */ + if (status & HERMES_RXSTAT_MIC) { + int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> + HERMES_MIC_KEY_ID_SHIFT); + u8 mic[MICHAEL_MIC_LEN]; + u8 *rxmic; + u8 *src = (fc & IEEE80211_FCTL_FROMDS) ? + desc->addr3 : desc->addr2; + + /* Extract Michael MIC from payload */ + rxmic = skb->data + skb->len - MICHAEL_MIC_LEN; + + skb_trim(skb, skb->len - MICHAEL_MIC_LEN); + length -= MICHAEL_MIC_LEN; + + michael_mic(priv->rx_tfm_mic, + priv->tkip_key[key_id].rx_mic, + desc->addr1, + src, + 0, /* priority or QoS? */ + skb->data, + skb->len, + &mic[0]); + + if (memcmp(mic, rxmic, + MICHAEL_MIC_LEN)) { + union iwreq_data wrqu; + struct iw_michaelmicfailure wxmic; + DECLARE_MAC_BUF(mac); + + printk(KERN_WARNING "%s: " + "Invalid Michael MIC in data frame from %s, " + "using key %i\n", + dev->name, print_mac(mac, src), key_id); + + /* TODO: update stats */ + + /* Notify userspace */ + memset(&wxmic, 0, sizeof(wxmic)); + wxmic.flags = key_id & IW_MICFAILURE_KEY_ID; + wxmic.flags |= (desc->addr1[0] & 1) ? + IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE; + wxmic.src_addr.sa_family = ARPHRD_ETHER; + memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN); + + (void) orinoco_hw_get_tkip_iv(priv, key_id, + &wxmic.tsc[0]); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(wxmic); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, + (char *) &wxmic); + + goto drop; + } + } + /* Handle decapsulation * In most cases, the firmware tell us about SNAP frames. * For some reason, the SNAP frames sent by LinkSys APs @@ -1342,6 +1529,11 @@ static void orinoco_rx(struct net_device *dev, stats->rx_bytes += length; return; + + drop: + dev_kfree_skb(skb); + stats->rx_errors++; + stats->rx_dropped++; } static void orinoco_rx_isr_tasklet(unsigned long data) @@ -3112,8 +3304,14 @@ static int orinoco_init(struct net_device *dev) else printk("40-bit key\n"); } - if (priv->has_wpa) + if (priv->has_wpa) { printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); + if (orinoco_mic_init(priv)) { + printk(KERN_ERR "%s: Failed to setup MIC crypto " + "algorithm. Disabling WPA support\n", dev->name); + priv->has_wpa = 0; + } + } /* Now we have the firmware capabilities, allocate appropiate * sized scan buffers */ @@ -3292,6 +3490,9 @@ struct net_device dev->set_multicast_list = orinoco_set_multicast_list; /* we use the default eth_mac_addr for setting the MAC addr */ + /* Reserve space in skb for the SNAP header */ + dev->hard_header_len += ENCAPS_OVERHEAD; + /* Set up default callbacks */ dev->open = orinoco_open; dev->stop = orinoco_stop; @@ -3327,6 +3528,7 @@ void free_orinocodev(struct net_device *dev) tasklet_kill(&priv->rx_tasklet); priv->wpa_ie_len = 0; kfree(priv->wpa_ie); + orinoco_mic_free(priv); orinoco_bss_data_free(priv); free_netdev(dev); } diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index e0c9be3daa3..981570bd3b9 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -158,6 +158,8 @@ struct orinoco_private { int wpa_ie_len; struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; + struct crypto_hash *rx_tfm_mic; + struct crypto_hash *tx_tfm_mic; unsigned int wpa_enabled:1; unsigned int tkip_cm_active:1; -- cgit v1.2.3 From 4c89e88bfde6a3c179790e21004f24e09a058290 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 3 Aug 2008 10:07:45 +0200 Subject: pcmcia: deprecate CS_SUCCESS Instead of using own error or success codes, the PCMCIA code should rely on the generic return values. Therefore, replace all occurrences of CS_SUCCESS with 0. CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/wireless/b43/pcmcia.c | 14 +++++++------- drivers/net/wireless/hostap/hostap_cs.c | 22 +++++++++++----------- drivers/net/wireless/netwave_cs.c | 5 +++-- drivers/net/wireless/ray_cs.c | 4 ++-- drivers/net/wireless/wavelan_cs.c | 16 ++++++++-------- drivers/net/wireless/wl3501_cs.c | 4 ++-- 6 files changed, 33 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index b8aa16307f7..ab42fb6addf 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -82,13 +82,13 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) tuple.TupleOffset = 0; res = pcmcia_get_first_tuple(dev, &tuple); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; res = pcmcia_get_tuple_data(dev, &tuple); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; res = pcmcia_parse_tuple(dev, &tuple, &parse); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; dev->conf.ConfigBase = parse.config.base; @@ -107,13 +107,13 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) win.Size = SSB_CORE_SIZE; win.AccessSpeed = 250; res = pcmcia_request_window(&dev, &win, &dev->win); - if (res != CS_SUCCESS) + if (res != 0) goto err_kfree_ssb; mem.CardOffset = 0; mem.Page = 0; res = pcmcia_map_mem_page(dev->win, &mem); - if (res != CS_SUCCESS) + if (res != 0) goto err_disable; dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; @@ -121,11 +121,11 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) dev->irq.Handler = NULL; /* The handler is registered later. */ dev->irq.Instance = NULL; res = pcmcia_request_irq(dev, &dev->irq); - if (res != CS_SUCCESS) + if (res != 0) goto err_disable; res = pcmcia_request_configuration(dev, &dev->conf); - if (res != CS_SUCCESS) + if (res != 0) goto err_disable; err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index c768d42d517..2826e674a8e 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -234,7 +234,7 @@ static void sandisk_set_iobase(local_info_t *local) reg.Value = hw_priv->link->io.BasePort1 & 0x00ff; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" " res=%d\n", res); } @@ -246,7 +246,7 @@ static void sandisk_set_iobase(local_info_t *local) reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" " res=%d\n", res); } @@ -322,7 +322,7 @@ static int sandisk_enable_wireless(struct net_device *dev) reg.Value = COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", dev->name, res); goto done; @@ -339,7 +339,7 @@ static int sandisk_enable_wireless(struct net_device *dev) reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", dev->name, res); goto done; @@ -374,7 +374,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value = 0; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", res); return; @@ -386,7 +386,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value |= COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", res); return; @@ -399,7 +399,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value |= COR_IREQ_ENA; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", res); return; @@ -433,7 +433,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Value = 0; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " "(%d)\n", res); return; @@ -446,7 +446,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Value |= COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " "(%d)\n", res); return; @@ -460,7 +460,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Offset = CISREG_CCSR; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " "(%d)\n", res); return; @@ -472,7 +472,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Value = old_cor & ~COR_SOFT_RESET; res = pcmcia_access_configuration_register(hw_priv->link, ®); - if (res != CS_SUCCESS) { + if (res != 0) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " "(%d)\n", res); return; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index f479c1af678..bf2dd105792 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -749,9 +749,10 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { for (i = j = 0x0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) break; + if (i == 0) + break; } - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIO, i); goto failed; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 963960dc30f..99c7c8bc257 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -798,9 +798,9 @@ static void ray_release(struct pcmcia_device *link) iounmap(local->amem); /* Do bother checking to see if these succeed or not */ i = pcmcia_release_window(local->amem_handle); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); + if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); i = pcmcia_release_window(local->rmem_handle); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); + if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); pcmcia_disable_device(link); DEBUG(2,"ray_release ending\n"); diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index b584c0ecc62..fee9a025053 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3708,7 +3708,7 @@ wv_pcmcia_reset(struct net_device * dev) #endif i = pcmcia_access_configuration_register(link, ®); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, AccessConfigurationRegister, i); return FALSE; @@ -3722,7 +3722,7 @@ wv_pcmcia_reset(struct net_device * dev) reg.Action = CS_WRITE; reg.Value = reg.Value | COR_SW_RESET; i = pcmcia_access_configuration_register(link, ®); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, AccessConfigurationRegister, i); return FALSE; @@ -3731,7 +3731,7 @@ wv_pcmcia_reset(struct net_device * dev) reg.Action = CS_WRITE; reg.Value = COR_LEVEL_IRQ | COR_CONFIG; i = pcmcia_access_configuration_register(link, ®); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, AccessConfigurationRegister, i); return FALSE; @@ -3909,7 +3909,7 @@ wv_pcmcia_config(struct pcmcia_device * link) do { i = pcmcia_request_io(link, &link->io); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestIO, i); break; @@ -3920,7 +3920,7 @@ wv_pcmcia_config(struct pcmcia_device * link) * actually assign a handler to the interrupt. */ i = pcmcia_request_irq(link, &link->irq); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestIRQ, i); break; @@ -3932,7 +3932,7 @@ wv_pcmcia_config(struct pcmcia_device * link) */ link->conf.ConfigIndex = 1; i = pcmcia_request_configuration(link, &link->conf); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestConfiguration, i); break; @@ -3948,7 +3948,7 @@ wv_pcmcia_config(struct pcmcia_device * link) req.Base = req.Size = 0; req.AccessSpeed = mem_speed; i = pcmcia_request_window(&link, &req, &link->win); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, RequestWindow, i); break; @@ -3960,7 +3960,7 @@ wv_pcmcia_config(struct pcmcia_device * link) mem.CardOffset = 0; mem.Page = 0; i = pcmcia_map_mem_page(link->win, &mem); - if(i != CS_SUCCESS) + if (i != 0) { cs_error(link, MapMemPage, i); break; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 377141995e3..969f53fd705 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1977,10 +1977,10 @@ static int wl3501_config(struct pcmcia_device *link) link->io.BasePort1 = j; link->io.BasePort2 = link->io.BasePort1 + 0x10; i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) + if (i == 0) break; } - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIO, i); goto failed; } -- cgit v1.2.3 From f45144ef412422edf8018825328768e3db3ea45b Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:02:53 +0530 Subject: ath9k: Merge reset functions Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 2 +- drivers/net/wireless/ath9k/core.c | 73 ++++++++++++------------------------- drivers/net/wireless/ath9k/core.h | 3 +- drivers/net/wireless/ath9k/recv.c | 2 +- drivers/net/wireless/ath9k/xmit.c | 2 +- 5 files changed, 27 insertions(+), 55 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index caf569401a3..67a80462675 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -719,7 +719,7 @@ void ath_bstuck_process(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_BEACON, "%s: stuck beacon; resetting (bmiss count %u)\n", __func__, sc->sc_bmisscount); - ath_internal_reset(sc); + ath_reset(sc, false); } /* diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index f6c45288d0e..10f2729a8c4 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -828,29 +828,30 @@ done: return error; } -/* - * Reset the hardware w/o losing operational state. This is - * basically a more efficient way of doing ath_stop, ath_init, - * followed by state transitions to the current 802.11 - * operational state. Used to recover from errors rx overrun - * and to reset the hardware when rf gain settings must be reset. - */ - -static int ath_reset_start(struct ath_softc *sc, u32 flag) +int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; + int status; + int error = 0; + enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, flag & RESET_RETRY_TXQ); /* stop xmit side */ - ath_stoprecv(sc); /* stop recv side */ - ath_flushrecv(sc); /* flush recv queue */ - - return 0; -} + ath_draintxq(sc, retry_tx); /* stop xmit */ + ath_stoprecv(sc); /* stop recv */ + ath_flushrecv(sc); /* flush recv queue */ -static int ath_reset_end(struct ath_softc *sc, u32 flag) -{ - struct ath_hal *ah = sc->sc_ah; + /* Reset chip */ + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, + ht_macmode, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to reset hardware; hal status %u\n", + __func__, status); + error = -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) /* restart recv */ DPRINTF(sc, ATH_DBG_FATAL, @@ -863,14 +864,15 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag) */ ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan)); - ath_update_txpow(sc); /* update tx power state */ + ath_update_txpow(sc); if (sc->sc_beacons) ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + ath9k_hw_set_interrupts(ah, sc->sc_imask); /* Restart the txq */ - if (flag & RESET_RETRY_TXQ) { + if (retry_tx) { int i; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { @@ -880,28 +882,6 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag) } } } - return 0; -} - -int ath_reset(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); - - /* NB: indicate channel change so we do a full reset */ - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, - ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, status); - error = -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); return error; } @@ -1050,7 +1030,7 @@ static void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_FATAL) { /* need a chip reset */ - ath_internal_reset(sc); + ath_reset(sc, false); return; } else { @@ -1815,13 +1795,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, /* Utilities */ /*************/ -void ath_internal_reset(struct ath_softc *sc) -{ - ath_reset_start(sc, 0); - ath_reset(sc); - ath_reset_end(sc, 0); -} - int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) { int qnum; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 673b3d81133..ef8f63766d4 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1030,7 +1030,7 @@ void ath_deinit(struct ath_softc *sc); int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); int ath_suspend(struct ath_softc *sc); irqreturn_t ath_isr(int irq, void *dev); -int ath_reset(struct ath_softc *sc); +int ath_reset(struct ath_softc *sc, bool retry_tx); void ath_scan_start(struct ath_softc *sc); void ath_scan_end(struct ath_softc *sc); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); @@ -1056,7 +1056,6 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -void ath_internal_reset(struct ath_softc *sc); u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc); dma_addr_t ath_skb_map_single(struct ath_softc *sc, struct sk_buff *skb, diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 2fe806175c0..838b656b9da 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -1089,7 +1089,7 @@ rx_next: "%s: Reset rx chain mask. " "Do internal reset\n", __func__); ASSERT(flush == 0); - ath_internal_reset(sc); + ath_reset(sc, false); } return 0; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 157f830ee6b..93064cc4cba 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1242,7 +1242,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, } if (needreset) - ath_internal_reset(sc); + ath_reset(sc, false); return; } -- cgit v1.2.3 From 7dcfdcd908a4540512aaf06b2b35e8c8a084fb69 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:03:13 +0530 Subject: ath9k: RX Filter cleanup Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 53 --------------------------------------- drivers/net/wireless/ath9k/core.h | 5 ++-- drivers/net/wireless/ath9k/main.c | 19 +++++++------- drivers/net/wireless/ath9k/recv.c | 11 +++++--- 4 files changed, 21 insertions(+), 67 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 10f2729a8c4..7f92d469ad0 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -21,9 +21,6 @@ static int ath_outdoor; /* enable outdoor use */ -static const u8 ath_bcast_mac[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - static u32 ath_chainmask_sel_up_rssi_thres = ATH_CHAINMASK_SEL_UP_RSSI_THRES; static u32 ath_chainmask_sel_down_rssi_thres = @@ -306,56 +303,6 @@ static int ath_stop(struct ath_softc *sc) return 0; } -/* - * Start Scan - * - * This function is called when starting a channel scan. It will perform - * power save wakeup processing, set the filter for the scan, and get the - * chip ready to send broadcast packets out during the scan. -*/ - -void ath_scan_start(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 rfilt; - u32 now = (u32) jiffies_to_msecs(get_timestamp()); - - sc->sc_scanning = 1; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - ath9k_hw_write_associd(ah, ath_bcast_mac, 0); - - /* Restore previous power management state. */ - - DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0\n", - now / 1000, now % 1000, __func__, rfilt); -} - -/* - * Scan End - * - * This routine is called by the upper layer when the scan is completed. This - * will set the filters back to normal operating mode, set the BSSID to the - * correct value, and restore the power save state. -*/ - -void ath_scan_end(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 rfilt; - u32 now = (u32) jiffies_to_msecs(get_timestamp()); - - sc->sc_scanning = 0; - /* Request for a full reset due to rx packet filter changes */ - sc->sc_full_reset = 1; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); - - DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0x%x\n", - now / 1000, now % 1000, __func__, rfilt, sc->sc_curaid); -} - /* * Set the current channel * diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index ef8f63766d4..07c958802b7 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -95,6 +95,8 @@ static inline unsigned long get_timestamp(void) return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ); } +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + /*************/ /* Debugging */ /*************/ @@ -919,10 +921,9 @@ struct ath_softc { struct ath_rate_softc *sc_rc; /* tx rate control support */ u32 sc_intrstatus; enum ath9k_opmode sc_opmode; /* current operating mode */ - + unsigned int rx_filter; u8 sc_invalid; /* being detached */ u8 sc_beacons; /* beacons running */ - u8 sc_scanning; /* scanning active */ u8 sc_txaggr; /* enable 11n tx aggregation */ u8 sc_rxaggr; /* enable 11n rx aggregation */ u8 sc_update_chainmask; /* change chain mask */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2888778040e..262fd7a8cd9 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -549,10 +549,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Update ratectrl about the new state */ ath_rate_newstate(sc, avp); - /* Set rx filter */ - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(sc->sc_ah, rfilt); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; @@ -636,8 +632,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | \ FIF_FCSFAIL) -/* Accept unicast, bcast and mcast frames */ - +/* FIXME: sc->sc_full_reset ? */ static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -645,16 +640,22 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, struct dev_mc_list *mclist) { struct ath_softc *sc = hw->priv; + u32 rfilt; changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; + sc->rx_filter = *total_flags; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - ath_scan_start(sc); - else - ath_scan_end(sc); + ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); } + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", + __func__, sc->rx_filter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 838b656b9da..a12584961d6 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -597,6 +597,7 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) + u32 rfilt; rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) @@ -608,14 +609,17 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (sc->sc_opmode == ATH9K_M_MONITOR) { + if (((sc->sc_opmode != ATH9K_M_HOSTAP) && + (sc->rx_filter & FIF_PROMISC_IN_BSS)) || + (sc->sc_opmode == ATH9K_M_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS || - sc->sc_scanning) + if (((sc->sc_opmode == ATH9K_M_STA) && + (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || + (sc->sc_opmode == ATH9K_M_IBSS)) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames @@ -623,6 +627,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->sc_opmode == ATH9K_M_HOSTAP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); return rfilt; + #undef RX_FILTER_PRESERVE } -- cgit v1.2.3 From cd3d39a6875507f4f4d585391fe3d344f0b64b5c Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:03:34 +0530 Subject: ath9k: Use bitfields for buffer type Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 70 +++++++++++++---------------- drivers/net/wireless/ath9k/xmit.c | 92 ++++++++++++++++++++++----------------- 2 files changed, 83 insertions(+), 79 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 07c958802b7..9e16c6c28a3 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -177,11 +177,6 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht); /* Descriptor Management */ /*************************/ -/* Number of descriptors per buffer. The only case where we see skbuff -chains is due to FF aggregation in the driver. */ -#define ATH_TXDESC 1 -/* if there's more fragment for this MSDU */ -#define ATH_BF_MORE_MPDU 1 #define ATH_TXBUF_RESET(_bf) do { \ (_bf)->bf_status = 0; \ (_bf)->bf_lastbf = NULL; \ @@ -191,28 +186,29 @@ chains is due to FF aggregation in the driver. */ sizeof(struct ath_buf_state)); \ } while (0) +enum buffer_type { + BUF_DATA = BIT(0), + BUF_AGGR = BIT(1), + BUF_AMPDU = BIT(2), + BUF_HT = BIT(3), + BUF_RETRY = BIT(4), + BUF_XRETRY = BIT(5), + BUF_SHORT_PREAMBLE = BIT(6), + BUF_BAR = BIT(7), + BUF_PSPOLL = BIT(8), + BUF_AGGR_BURST = BIT(9), + BUF_CALC_AIRTIME = BIT(10), +}; + struct ath_buf_state { - int bfs_nframes; /* # frames in aggregate */ - u16 bfs_al; /* length of aggregate */ - u16 bfs_frmlen; /* length of frame */ - int bfs_seqno; /* sequence number */ - int bfs_tidno; /* tid of this frame */ - int bfs_retries; /* current retries */ + int bfs_nframes; /* # frames in aggregate */ + u16 bfs_al; /* length of aggregate */ + u16 bfs_frmlen; /* length of frame */ + int bfs_seqno; /* sequence number */ + int bfs_tidno; /* tid of this frame */ + int bfs_retries; /* current retries */ struct ath_rc_series bfs_rcs[4]; /* rate series */ - u8 bfs_isdata:1; /* is a data frame/aggregate */ - u8 bfs_isaggr:1; /* is an aggregate */ - u8 bfs_isampdu:1; /* is an a-mpdu, aggregate or not */ - u8 bfs_ht:1; /* is an HT frame */ - u8 bfs_isretried:1; /* is retried */ - u8 bfs_isxretried:1; /* is excessive retried */ - u8 bfs_shpreamble:1; /* is short preamble */ - u8 bfs_isbar:1; /* is a BAR */ - u8 bfs_ispspoll:1; /* is a PS-Poll */ - u8 bfs_aggrburst:1; /* is a aggr burst */ - u8 bfs_calcairtime:1; /* requests airtime be calculated - when set for tx frame */ - int bfs_rifsburst_elem; /* RIFS burst/bar */ - int bfs_nrifsubframes; /* # of elements in burst */ + u32 bf_type; /* BUF_* (enum buffer_type) */ /* key type use to encrypt this frame */ enum ath9k_key_type bfs_keytype; }; @@ -224,26 +220,22 @@ struct ath_buf_state { #define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_rcs bf_state.bfs_rcs -#define bf_isdata bf_state.bfs_isdata -#define bf_isaggr bf_state.bfs_isaggr -#define bf_isampdu bf_state.bfs_isampdu -#define bf_ht bf_state.bfs_ht -#define bf_isretried bf_state.bfs_isretried -#define bf_isxretried bf_state.bfs_isxretried -#define bf_shpreamble bf_state.bfs_shpreamble -#define bf_rifsburst_elem bf_state.bfs_rifsburst_elem -#define bf_nrifsubframes bf_state.bfs_nrifsubframes #define bf_keytype bf_state.bfs_keytype -#define bf_isbar bf_state.bfs_isbar -#define bf_ispspoll bf_state.bfs_ispspoll -#define bf_aggrburst bf_state.bfs_aggrburst -#define bf_calcairtime bf_state.bfs_calcairtime +#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) +#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) +#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) +#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) +#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) +#define bf_isshpreamble(bf) (bf->bf_state.bf_type & BUF_SHORT_PREAMBLE) +#define bf_isbar(bf) (bf->bf_state.bf_type & BUF_BAR) +#define bf_ispspoll(bf) (bf->bf_state.bf_type & BUF_PSPOLL) +#define bf_isaggrburst(bf) (bf->bf_state.bf_type & BUF_AGGR_BURST) /* * Abstraction of a contiguous buffer to transmit/receive. There is only * a single hw descriptor encapsulated here. */ - struct ath_buf { struct list_head list; struct list_head *last; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 93064cc4cba..47cf9f3555a 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -518,7 +518,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, if (!txok) { tx_status.flags |= ATH_TX_ERROR; - if (bf->bf_isxretried) + if (bf_isxretried(bf)) tx_status.flags |= ATH_TX_XRETRY; } /* Unmap this frame */ @@ -629,7 +629,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) return 0; - isaggr = bf->bf_isaggr; + isaggr = bf_isaggr(bf); if (isaggr) { seq_st = ATH_DS_BA_SEQ(ds); memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); @@ -651,7 +651,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) struct sk_buff *skb; struct ieee80211_hdr *hdr; - bf->bf_isretried = 1; + bf->bf_state.bf_type |= BUF_RETRY; bf->bf_retries++; skb = bf->bf_mpdu; @@ -698,7 +698,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rc; int streams, pktlen; - pktlen = bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen; + pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; rc = rt->info[rix].rateCode; /* @@ -781,7 +781,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * let rate series flags determine which rates will actually * use RTS. */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf->bf_isdata) { + if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { BUG_ON(!an); /* * 802.11g protection not needed, use our default behavior @@ -793,7 +793,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * and the second aggregate should have any protection at all. */ if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf->bf_aggrburst) { + if (!bf_isaggrburst(bf)) { flags = ATH9K_TXDESC_RTSENA; dynamic_mimops = 1; } else { @@ -806,7 +806,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Set protection if aggregate protection on */ if (sc->sc_config.ath_aggr_prot && - (!bf->bf_isaggr || (bf->bf_isaggr && bf->bf_al < 8192))) { + (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { flags = ATH9K_TXDESC_RTSENA; cix = rt->info[sc->sc_protrix].controlRate; rtsctsena = 1; @@ -815,7 +815,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* * For AR5416 - RTS cannot be followed by a frame larger than 8K. */ - if (bf->bf_isaggr && (bf->bf_al > aggr_limit_with_rts)) { + if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) { /* * Ensure that in the case of SM Dynamic power save * while we are bursting the second aggregate the @@ -832,7 +832,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* NB: cix is set above where RTS/CTS is enabled */ BUG_ON(cix == 0xff); ctsrate = rt->info[cix].rateCode | - (bf->bf_shpreamble ? rt->info[cix].shortPreamble : 0); + (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); /* * Setup HAL rate series @@ -846,7 +846,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) rix = bf->bf_rcs[i].rix; series[i].Rate = rt->info[rix].rateCode | - (bf->bf_shpreamble ? rt->info[rix].shortPreamble : 0); + (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); series[i].Tries = bf->bf_rcs[i].tries; @@ -862,7 +862,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) sc, rix, bf, (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), - bf->bf_shpreamble); + bf_isshpreamble(bf)); if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { @@ -875,7 +875,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) */ series[i].ChSel = sc->sc_tx_chainmask; } else { - if (bf->bf_ht) + if (bf_isht(bf)) series[i].ChSel = ath_chainmask_sel_logic(sc, an); else @@ -908,7 +908,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * use the precalculated ACK durations. */ if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */ - ctsduration += bf->bf_shpreamble ? + ctsduration += bf_isshpreamble(bf) ? rt->info[cix].spAckDuration : rt->info[cix].lpAckDuration; } @@ -916,7 +916,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) ctsduration += series[0].PktDuration; if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */ - ctsduration += bf->bf_shpreamble ? + ctsduration += bf_isshpreamble(bf) ? rt->info[rix].spAckDuration : rt->info[rix].lpAckDuration; } @@ -932,10 +932,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * set dur_update_en for l-sig computation except for PS-Poll frames */ ath9k_hw_set11n_ratescenario(ah, ds, lastds, - !bf->bf_ispspoll, - ctsrate, - ctsduration, - series, 4, flags); + !bf_ispspoll(bf), + ctsrate, + ctsduration, + series, 4, flags); if (sc->sc_config.ath_aggr_prot && flags) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -958,7 +958,7 @@ static int ath_tx_send_normal(struct ath_softc *sc, BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_isampdu = 0; /* regular HT frame */ + bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); @@ -998,7 +998,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) while (!list_empty(&tid->buf_q)) { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - ASSERT(!bf->bf_isretried); + ASSERT(!bf_isretried(bf)); list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); ath_tx_send_normal(sc, txq, tid, &bf_head); } @@ -1025,7 +1025,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, int isaggr, txfail, txpending, sendbar = 0, needreset = 0; int isnodegone = (an->an_flags & ATH_NODE_CLEAN); - isaggr = bf->bf_isaggr; + isaggr = bf_isaggr(bf); if (isaggr) { if (txok) { if (ATH_DS_TX_BA(ds)) { @@ -1075,7 +1075,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, ath_tx_set_retry(sc, bf); txpending = 1; } else { - bf->bf_isxretried = 1; + bf->bf_state.bf_type |= BUF_XRETRY; txfail = 1; sendbar = 1; } @@ -1331,7 +1331,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_depth--; - if (bf->bf_isaggr) + if (bf_isaggr(bf)) txq->axq_aggr_depth--; txok = (ds->ds_txstat.ts_status == 0); @@ -1345,14 +1345,14 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&sc->sc_txbuflock); } - if (!bf->bf_isampdu) { + if (!bf_isampdu(bf)) { /* * This frame is sent out as a single frame. * Use hardware retry status for this frame. */ bf->bf_retries = ds->ds_txstat.ts_longretry; if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) - bf->bf_isxretried = 1; + bf->bf_state.bf_type |= BUF_XRETRY; nbad = 0; } else { nbad = ath_tx_num_badfrms(sc, bf, txok); @@ -1368,7 +1368,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (ds->ds_txstat.ts_status == 0) nacked++; - if (bf->bf_isdata) { + if (bf_isdata(bf)) { if (isrifs) tmp_ds = bf->bf_rifslast->bf_desc; else @@ -1384,7 +1384,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) /* * Complete this transmit unit */ - if (bf->bf_isampdu) + if (bf_isampdu(bf)) ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok); else ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); @@ -1481,7 +1481,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, { int index, cindex; - if (bf->bf_isretried) + if (bf_isretried(bf)) return; index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); @@ -1516,7 +1516,7 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_isampdu = 1; + bf->bf_state.bf_type |= BUF_AMPDU; bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */ bf->bf_tidno = txctl->tidno; @@ -1860,7 +1860,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, if (bf->bf_nframes == 1) { ASSERT(bf->bf_lastfrm == bf_last); - bf->bf_isaggr = 0; + bf->bf_state.bf_type &= ~BUF_AGGR; /* * clear aggr bits for every descriptor * XXX TODO: is there a way to optimize it? @@ -1877,7 +1877,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, /* * setup first desc with rate and aggr info */ - bf->bf_isaggr = 1; + bf->bf_state.bf_type |= BUF_AGGR; ath_buf_set_rate(sc, bf); ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al); @@ -1925,7 +1925,7 @@ static void ath_tid_drain(struct ath_softc *sc, list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); /* update baw for software retried frame */ - if (bf->bf_isretried) + if (bf_isretried(bf)) ath_tx_update_baw(sc, tid, bf->bf_seqno); /* @@ -2014,11 +2014,21 @@ static int ath_tx_start_dma(struct ath_softc *sc, /* set up this buffer */ ATH_TXBUF_RESET(bf); bf->bf_frmlen = txctl->frmlen; - bf->bf_isdata = ieee80211_is_data(fc); - bf->bf_isbar = ieee80211_is_back_req(fc); - bf->bf_ispspoll = ieee80211_is_pspoll(fc); + + ieee80211_is_data(fc) ? + (bf->bf_state.bf_type |= BUF_DATA) : + (bf->bf_state.bf_type &= ~BUF_DATA); + ieee80211_is_back_req(fc) ? + (bf->bf_state.bf_type |= BUF_BAR) : + (bf->bf_state.bf_type &= ~BUF_BAR); + ieee80211_is_pspoll(fc) ? + (bf->bf_state.bf_type |= BUF_PSPOLL) : + (bf->bf_state.bf_type &= ~BUF_PSPOLL); + (sc->sc_flags & ATH_PREAMBLE_SHORT) ? + (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : + (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); + bf->bf_flags = txctl->flags; - bf->bf_shpreamble = sc->sc_flags & ATH_PREAMBLE_SHORT; bf->bf_keytype = txctl->keytype; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; rcs = tx_info_priv->rcs; @@ -2060,7 +2070,9 @@ static int ath_tx_start_dma(struct ath_softc *sc, ds); /* first descriptor */ bf->bf_lastfrm = bf; - bf->bf_ht = txctl->ht; + (txctl->ht) ? + (bf->bf_state.bf_type |= BUF_HT) : + (bf->bf_state.bf_type &= ~BUF_HT); spin_lock_bh(&txq->axq_lock); @@ -2162,7 +2174,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) /* Setup tx descriptors */ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, - "tx", nbufs * ATH_FRAG_PER_MSDU, ATH_TXDESC); + "tx", nbufs * ATH_FRAG_PER_MSDU, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, "%s: failed to allocate tx descriptors: %d\n", @@ -2486,7 +2498,7 @@ void ath_tx_draintxq(struct ath_softc *sc, spin_unlock_bh(&txq->axq_lock); - if (bf->bf_isampdu) + if (bf_isampdu(bf)) ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0); else ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); @@ -2647,7 +2659,7 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, spin_lock_bh(&txq->axq_lock); while (!list_empty(&txtid->buf_q)) { bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); - if (!bf->bf_isretried) { + if (!bf_isretried(bf)) { /* * NB: it's based on the assumption that * software retried frame will always stay -- cgit v1.2.3 From 556bb8f141d702a84281064751a3242359a9f257 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:03:53 +0530 Subject: ath9k: Remove a few unnecessary macros Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 15 +++------------ drivers/net/wireless/ath9k/xmit.c | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 9e16c6c28a3..19399da8d47 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -396,8 +396,7 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, /* TX */ /******/ -#define ATH_FRAG_PER_MSDU 1 -#define ATH_TXBUF (512/ATH_FRAG_PER_MSDU) +#define ATH_TXBUF 512 /* max number of transmit attempts (tries) */ #define ATH_TXMAXTRY 13 /* max number of 11n transmit attempts (tries) */ @@ -551,10 +550,10 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); void ath_draintxq(struct ath_softc *sc, bool retry_tx); void ath_tx_draintxq(struct ath_softc *sc, - struct ath_txq *txq, bool retry_tx); + struct ath_txq *txq, bool retry_tx); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag); + struct ath_node *an, bool bh_flag); void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); @@ -579,7 +578,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, /* indicates the node is 80211 power save */ #define ATH_NODE_PWRSAVE 0x2 -#define ADDBA_TIMEOUT 200 /* 200 milliseconds */ #define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -699,9 +697,6 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); #define ATH_BCBUF 4 /* number of beacon buffers */ #define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define ATH_BEACON_AIFS_DEFAULT 0 /* Default aifs for ap beacon q */ -#define ATH_BEACON_CWMIN_DEFAULT 0 /* Default cwmin for ap beacon q */ -#define ATH_BEACON_CWMAX_DEFAULT 0 /* Default cwmax for ap beacon q */ #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) /* beacon configuration */ @@ -838,8 +833,6 @@ void ath_setdefantenna(void *sc, u32 antenna); #define ATH_PREAMBLE_SHORT (1<<0) #define ATH_PROTECT_ENABLE (1<<1) #define ATH_MAX_SW_RETRIES 10 -/* Num farmes difference in tx to flip default recv */ -#define ATH_ANTENNA_DIFF 2 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ #define IEEE80211_RATE_VAL 0x7f @@ -853,9 +846,7 @@ void ath_setdefantenna(void *sc, u32 antenna); */ #define ATH_KEYMAX 128 /* max key cache size we handle */ -#define RESET_RETRY_TXQ 0x00000001 #define ATH_IF_ID_ANY 0xff - #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define RSSI_LPF_THRESHOLD -20 diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 47cf9f3555a..a24a3a5b0e6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2174,7 +2174,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) /* Setup tx descriptors */ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, - "tx", nbufs * ATH_FRAG_PER_MSDU, 1); + "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, "%s: failed to allocate tx descriptors: %d\n", -- cgit v1.2.3 From d2d80ee9c6ae3d60bcbffb200959db645f5a558f Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:04:13 +0530 Subject: ath9k: Remove ar5416hal and assign default values directly Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index a17eb130f57..3d879e7a8ea 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -85,29 +85,6 @@ static const struct hal_percal_data adc_init_dc_cal = { ath9k_hw_adc_dccal_calibrate }; -static const struct ath_hal ar5416hal = { - AR5416_MAGIC, - 0, - 0, - NULL, - NULL, - CTRY_DEFAULT, - 0, - 0, - 0, - 0, - 0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }, -}; - static struct ath9k_rate_table ar5416_11a_table = { 8, {0}, @@ -1196,11 +1173,12 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, ah = &ahp->ah; - memcpy(&ahp->ah, &ar5416hal, sizeof(struct ath_hal)); - ah->ah_sc = sc; ah->ah_sh = mem; + ah->ah_magic = AR5416_MAGIC; + ah->ah_countryCode = CTRY_DEFAULT; + ah->ah_devid = devid; ah->ah_subvendorid = 0; -- cgit v1.2.3 From 6a2b9e8c8f4be9954933051719b312adcfb7263d Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:04:32 +0530 Subject: ath9k: Unused macros, variables Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 18 +++--- drivers/net/wireless/ath9k/hw.h | 116 +++++++++++++------------------------ 2 files changed, 50 insertions(+), 84 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index d1b0fbae5a3..3e7072dcb43 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -790,19 +790,20 @@ struct ath_hal { u32 ah_magic; u16 ah_devid; u16 ah_subvendorid; - struct ath_softc *ah_sc; - void __iomem *ah_sh; - u16 ah_countryCode; u32 ah_macVersion; u16 ah_macRev; u16 ah_phyRev; u16 ah_analog5GhzRev; u16 ah_analog2GhzRev; - u8 ah_decompMask[ATH9K_DECOMP_MASK_SIZE]; - u32 ah_flags; + + void __iomem *ah_sh; + struct ath_softc *ah_sc; enum ath9k_opmode ah_opmode; struct ath9k_ops_config ah_config; struct ath9k_hw_capabilities ah_caps; + + u16 ah_countryCode; + u32 ah_flags; int16_t ah_powerLimit; u16 ah_maxPowerLevel; u32 ah_tpScale; @@ -812,15 +813,16 @@ struct ath_hal { u16 ah_currentRD5G; u16 ah_currentRD2G; char ah_iso[4]; - enum start_adhoc_option ah_adHocMode; - bool ah_commonMode; + struct ath9k_channel ah_channels[150]; - u32 ah_nchan; struct ath9k_channel *ah_curchan; + u32 ah_nchan; + u16 ah_rfsilent; bool ah_rfkillEnabled; bool ah_isPciExpress; u16 ah_txTrigLevel; + #ifndef ATH_NF_PER_CHAN struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; #endif diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index ae680f21ba7..5cb3912ad39 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -314,14 +314,11 @@ struct ar5416_desc { #define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ MS(ads->ds_rxstatus0, AR_RxRate) : \ (ads->ds_rxstatus3 >> 2) & 0xFF) -#define RXSTATUS_DUPLICATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ - MS(ads->ds_rxstatus3, AR_Parallel40) : \ - (ads->ds_rxstatus3 >> 10) & 0x1) -#define set11nTries(_series, _index) \ +#define set11nTries(_series, _index) \ (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) -#define set11nRate(_series, _index) \ +#define set11nRate(_series, _index) \ (SM((_series)[_index].Rate, AR_XmitRate##_index)) #define set11nPktDurRTSCTS(_series, _index) \ @@ -330,11 +327,11 @@ struct ar5416_desc { AR_RTSCTSQual##_index : 0)) #define set11nRateFlags(_series, _index) \ - (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ - AR_2040_##_index : 0) \ - |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ - AR_GI##_index : 0) \ - |SM((_series)[_index].ChSel, AR_ChainSel##_index)) + (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ + AR_2040_##_index : 0) \ + |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ + AR_GI##_index : 0) \ + |SM((_series)[_index].ChSel, AR_ChainSel##_index)) #define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100) @@ -346,9 +343,6 @@ struct ar5416_desc { #define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) #define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD -#define NUM_CORNER_FIX_BITS_2133 7 -#define CCK_OFDM_GAIN_DELTA 15 - struct ar5416AniState { struct ath9k_channel c; u8 noiseImmunityLevel; @@ -377,11 +371,8 @@ struct ar5416AniState { }; #define HAL_PROCESS_ANI 0x00000001 -#define HAL_RADAR_EN 0x80000000 -#define HAL_AR_EN 0x40000000 - #define DO_ANI(ah) \ - ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) + ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) struct ar5416Stats { u32 ast_ani_niup; @@ -425,7 +416,6 @@ struct ar5416Stats { #define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_9 0x9 -#define AR5416_EEP_START_LOC 256 #define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_2G_CAL_PIERS 4 #define AR5416_NUM_5G_20_TARGET_POWERS 8 @@ -441,25 +431,10 @@ struct ar5416Stats { #define AR5416_EEPROM_MODAL_SPURS 5 #define AR5416_MAX_RATE_POWER 63 #define AR5416_NUM_PDADC_VALUES 128 -#define AR5416_NUM_RATES 16 #define AR5416_BCHAN_UNUSED 0xFF #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 -#define AR5416_EEPMISC_BIG_ENDIAN 0x01 #define AR5416_MAX_CHAINS 3 -#define AR5416_ANT_16S 25 - -#define AR5416_NUM_ANT_CHAIN_FIELDS 7 -#define AR5416_NUM_ANT_COMMON_FIELDS 4 -#define AR5416_SIZE_ANT_CHAIN_FIELD 3 -#define AR5416_SIZE_ANT_COMMON_FIELD 4 -#define AR5416_ANT_CHAIN_MASK 0x7 -#define AR5416_ANT_COMMON_MASK 0xf -#define AR5416_CHAIN_0_IDX 0 -#define AR5416_CHAIN_1_IDX 1 -#define AR5416_CHAIN_2_IDX 2 - #define AR5416_PWR_TABLE_OFFSET -5 -#define AR5416_LEGACY_CHAINMASK 1 enum eeprom_param { EEP_NFTHRESH_5, @@ -633,7 +608,7 @@ struct ar5416IniArray { }; #define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u32 *)(array); \ + (iniarray)->ia_array = (u32 *)(array); \ (iniarray)->ia_rows = (rows); \ (iniarray)->ia_columns = (columns); \ } while (0) @@ -641,16 +616,16 @@ struct ar5416IniArray { #define INI_RA(iniarray, row, column) \ (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)]) -#define INIT_CAL(_perCal) do { \ - (_perCal)->calState = CAL_WAITING; \ - (_perCal)->calNext = NULL; \ +#define INIT_CAL(_perCal) do { \ + (_perCal)->calState = CAL_WAITING; \ + (_perCal)->calNext = NULL; \ } while (0) #define INSERT_CAL(_ahp, _perCal) \ do { \ if ((_ahp)->ah_cal_list_last == NULL) { \ - (_ahp)->ah_cal_list = \ - (_ahp)->ah_cal_list_last = (_perCal); \ + (_ahp)->ah_cal_list = \ + (_ahp)->ah_cal_list_last = (_perCal); \ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ } else { \ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ @@ -696,25 +671,29 @@ struct hal_cal_list { struct ath_hal_5416 { struct ath_hal ah; struct ar5416_eeprom ah_eeprom; + struct ar5416Stats ah_stats; + struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; + void __iomem *ah_cal_mem; + u8 ah_macaddr[ETH_ALEN]; u8 ah_bssid[ETH_ALEN]; u8 ah_bssidmask[ETH_ALEN]; u16 ah_assocId; + int16_t ah_curchanRadIndex; u32 ah_maskReg; - struct ar5416Stats ah_stats; - u32 ah_txDescMask; u32 ah_txOkInterruptMask; u32 ah_txErrInterruptMask; u32 ah_txDescInterruptMask; u32 ah_txEolInterruptMask; u32 ah_txUrnInterruptMask; - struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; - enum ath9k_power_mode ah_powerMode; bool ah_chipFullSleep; u32 ah_atimWindow; - enum ath9k_ant_setting ah_diversityControl; u16 ah_antennaSwitchSwap; + enum ath9k_power_mode ah_powerMode; + enum ath9k_ant_setting ah_diversityControl; + + /* Calibration */ enum hal_cal_types ah_suppCals; struct hal_cal_list ah_iqCalData; struct hal_cal_list ah_adcGainCalData; @@ -751,16 +730,16 @@ struct ath_hal_5416 { int32_t sign[AR5416_MAX_CHAINS]; } ah_Meas3; u16 ah_CalSamples; - u32 ah_tx6PowerInHalfDbm; + u32 ah_staId1Defaults; u32 ah_miscMode; - bool ah_tpcEnabled; - u32 ah_beaconInterval; enum { AUTO_32KHZ, USE_32KHZ, DONT_USE_32KHZ, } ah_enable32kHzClock; + + /* RF */ u32 *ah_analogBank0Data; u32 *ah_analogBank1Data; u32 *ah_analogBank2Data; @@ -770,8 +749,9 @@ struct ath_hal_5416 { u32 *ah_analogBank7Data; u32 *ah_addac5416_21; u32 *ah_bank6Temp; - u32 ah_ofdmTxPower; + int16_t ah_txPowerIndexOffset; + u32 ah_beaconInterval; u32 ah_slottime; u32 ah_acktimeout; u32 ah_ctstimeout; @@ -780,7 +760,8 @@ struct ath_hal_5416 { u32 ah_gpioSelect; u32 ah_polarity; u32 ah_gpioBit; - bool ah_eepEnabled; + + /* ANI */ u32 ah_procPhyErr; bool ah_hasHwPhyCounters; u32 ah_aniPeriod; @@ -790,18 +771,14 @@ struct ath_hal_5416 { int ah_coarseHigh[5]; int ah_coarseLow[5]; int ah_firpwr[5]; - u16 ah_ratesArray[16]; + enum ath9k_ani_cmd ah_ani_function; + u32 ah_intrTxqs; bool ah_intrMitigation; - u32 ah_cycleCount; - u32 ah_ctlBusy; - u32 ah_extBusy; enum ath9k_ht_extprotspacing ah_extprotspacing; u8 ah_txchainmask; u8 ah_rxchainmask; - int ah_hwp; - void __iomem *ah_cal_mem; - enum ath9k_ani_cmd ah_ani_function; + struct ar5416IniArray ah_iniModes; struct ar5416IniArray ah_iniCommon; struct ar5416IniArray ah_iniBank0; @@ -820,10 +797,6 @@ struct ath_hal_5416 { #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) -#define IS_5416_EMU(ah) \ - ((ah->ah_devid == AR5416_DEVID_EMU) || \ - (ah->ah_devid == AR5416_DEVID_EMU_PCIE)) - #define ar5416RfDetach(ah) do { \ if (AH5416(ah)->ah_rfHal.rfDetach != NULL) \ AH5416(ah)->ah_rfHal.rfDetach(ah); \ @@ -841,8 +814,8 @@ struct ath_hal_5416 { #define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ int r; \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ + REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ + INI_RA((iniarray), r, (column))); \ DO_DELAY(regWr); \ } \ } while (0) @@ -860,22 +833,17 @@ struct ath_hal_5416 { #define AR5416_EEPROM_S 2 #define AR5416_EEPROM_OFFSET 0x2000 -#define AR5416_EEPROM_START_ADDR \ +#define AR5416_EEPROM_START_ADDR \ (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 #define AR5416_EEPROM_MAX 0xae0 -#define ar5416_get_eep_ver(_ahp) \ +#define ar5416_get_eep_ver(_ahp) \ (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF) -#define ar5416_get_eep_rev(_ahp) \ +#define ar5416_get_eep_rev(_ahp) \ (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF) -#define ar5416_get_ntxchains(_txchainmask) \ +#define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -#define IS_EEP_MINOR_V3(_ahp) \ - (ath9k_hw_get_eeprom((_ahp), EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_3) - -#define FIXED_CCA_THRESHOLD 15 - #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else @@ -910,8 +878,6 @@ struct ath_hal_5416 { #define AR_GPIOD_MASK 0x00001FFF #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) -#define MAX_ANALOG_START 319 - #define HAL_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) #define BEACON_RSSI(ahp) \ @@ -923,8 +889,6 @@ struct ath_hal_5416 { #define AH_TIMEOUT 100000 #define AH_TIME_QUANTUM 10 -#define IS(_c, _f) (((_c)->channelFlags & _f) || 0) - #define AR_KEYTABLE_SIZE 128 #define POWER_UP_TIME 200000 @@ -964,6 +928,6 @@ struct ath_hal_5416 { #define OFDM_SYMBOL_TIME_QUARTER 16 u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param); + enum eeprom_param param); #endif -- cgit v1.2.3 From b4696c8b9233bea812b972a5e79c5db7ecf13867 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:04:52 +0530 Subject: ath9k: Use a single opmode variable ah_opmode and sc_opmode are redundant. This patch removes sc_opmode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath9k/beacon.c | 18 +++++++++--------- drivers/net/wireless/ath9k/core.c | 21 ++++++++++++--------- drivers/net/wireless/ath9k/core.h | 6 +++--- drivers/net/wireless/ath9k/hw.c | 8 +++----- drivers/net/wireless/ath9k/main.c | 3 ++- drivers/net/wireless/ath9k/recv.c | 18 +++++++++--------- drivers/net/wireless/ath9k/xmit.c | 4 ++-- 8 files changed, 41 insertions(+), 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 3e7072dcb43..682d3bb4d49 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -855,7 +855,7 @@ bool ath9k_regd_init_channels(struct ath_hal *ah, u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); -bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 67a80462675..2736a4b4e4a 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -33,7 +33,7 @@ static int ath_beaconq_config(struct ath_softc *sc) struct ath9k_tx_queue_info qi; ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi); - if (sc->sc_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; @@ -85,7 +85,7 @@ static void ath_beacon_setup(struct ath_softc *sc, flags = ATH9K_TXDESC_NOACK; - if (sc->sc_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; @@ -375,7 +375,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_opmode == ATH9K_M_HOSTAP || + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* @@ -750,7 +750,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (if_id != ATH_IF_ID_ANY) av_opmode = sc->sc_vaps[if_id]->av_opmode; else - av_opmode = sc->sc_opmode; + av_opmode = sc->sc_ah->ah_opmode; memzero(&conf, sizeof(struct ath_beacon_config)); @@ -770,7 +770,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4), get_unaligned_le32(conf.u.last_tstamp)); /* XXX conditionalize multi-bss support? */ - if (sc->sc_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* * For multi-bss ap support beacons are either staggered * evenly over N slots or burst together. For the former @@ -791,7 +791,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", __func__, nexttbtt, intval, conf.beacon_interval); /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ - if (sc->sc_opmode == ATH9K_M_STA) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { struct ath9k_beacon_state bs; u64 tsf; u32 tsftu; @@ -911,7 +911,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath9k_hw_set_interrupts(ah, 0); if (nexttbtt == intval) intval |= ATH9K_BEACON_RESET_TSF; - if (sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { /* * Pull nexttbtt forward to reflect the current * TSF . @@ -943,7 +943,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) sc->sc_imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); - } else if (sc->sc_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* * In AP mode we enable the beacon timers and * SWBA interrupts to prepare beacon frames. @@ -959,7 +959,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * When using a self-linked beacon descriptor in * ibss mode load it once here. */ - if (sc->sc_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 7f92d469ad0..8359356ac02 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -355,7 +355,7 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) fastcc = false; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, hchan, + if (!ath9k_hw_reset(ah, hchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, @@ -533,7 +533,8 @@ int ath_vap_listen(struct ath_softc *sc, int if_id) rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(ah, rfilt); - if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA || + sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN); ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); } else @@ -603,7 +604,7 @@ int ath_vap_attach(struct ath_softc *sc, sc->sc_vaps[if_id] = avp; sc->sc_nvaps++; /* Set the device opmode */ - sc->sc_opmode = opmode; + sc->sc_ah->ah_opmode = opmode; /* default VAP configuration */ avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; @@ -677,7 +678,8 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) int error = 0; enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", + __func__, sc->sc_ah->ah_opmode); /* * Stop anything previously setup. This is safe @@ -702,7 +704,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) sc->sc_curchan = *initial_chan; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode, + if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, @@ -749,7 +751,8 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * Note we only do this (at the moment) for station mode. */ if (ath9k_hw_phycounters(ah) && - ((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS))) + ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) sc->sc_imask |= ATH9K_INT_MIB; /* * Some hardware processes the TIM IE and fires an @@ -758,7 +761,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * enable the TIM interrupt when operating as station. */ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_opmode == ATH9K_M_STA) && + (sc->sc_ah->ah_opmode == ATH9K_M_STA) && !sc->sc_config.swBeaconProcess) sc->sc_imask |= ATH9K_INT_TIM; /* @@ -789,7 +792,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, + if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { @@ -1096,7 +1099,7 @@ int ath_init(u16 devid, struct ath_softc *sc) goto bad; /* default to STA mode */ - sc->sc_opmode = ATH9K_M_MONITOR; + sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; /* Setup rate tables */ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 19399da8d47..bfe16230b5e 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -895,15 +895,15 @@ struct ath_ht_info { struct ath_softc { struct ieee80211_hw *hw; struct pci_dev *pdev; - void __iomem *mem; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; struct ath_config sc_config; /* load-time parameters */ - int sc_debug; struct ath_hal *sc_ah; struct ath_rate_softc *sc_rc; /* tx rate control support */ + void __iomem *mem; + + int sc_debug; u32 sc_intrstatus; - enum ath9k_opmode sc_opmode; /* current operating mode */ unsigned int rx_filter; u8 sc_invalid; /* being detached */ u8 sc_beacons; /* beacons running */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 3d879e7a8ea..24b78c2eb44 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -5839,7 +5839,7 @@ static inline bool ath9k_hw_init_cal(struct ath_hal *ah, } -bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, @@ -5953,7 +5953,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, | (ah->ah_config. ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) | ahp->ah_staId1Defaults); - ath9k_hw_set_operating_mode(ah, opmode); + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); @@ -5983,13 +5983,11 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, for (i = 0; i < ah->ah_caps.total_queues; i++) ath9k_hw_resettxqueue(ah, i); - ath9k_hw_init_interrupt_masks(ah, opmode); + ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); ath9k_hw_init_qos(ah); ath9k_hw_init_user_settings(ah); - ah->ah_opmode = opmode; - REG_WRITE(ah, AR_STA_ID1, REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 262fd7a8cd9..7504b64020c 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -472,7 +472,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_rate_newstate(sc, avp); /* Reclaim beacon resources */ - if (sc->sc_opmode == ATH9K_M_HOSTAP || sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || + sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); ath_beacon_return(sc, avp); } diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index a12584961d6..6d1d5035f15 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -184,7 +184,7 @@ static int ath_ampdu_input(struct ath_softc *sc, tid = qc[0] & 0xf; } - if (sc->sc_opmode == ATH9K_M_STA) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { /* Drop the frame not belonging to me. */ if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { dev_kfree_skb(skb); @@ -605,26 +605,26 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_opmode != ATH9K_M_STA) + if (sc->sc_ah->ah_opmode != ATH9K_M_STA) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (((sc->sc_opmode != ATH9K_M_HOSTAP) && + if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && (sc->rx_filter & FIF_PROMISC_IN_BSS)) || - (sc->sc_opmode == ATH9K_M_MONITOR)) { + (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (((sc->sc_opmode == ATH9K_M_STA) && + if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) && (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || - (sc->sc_opmode == ATH9K_M_IBSS)) + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames & beacon frames */ - if (sc->sc_opmode == ATH9K_M_HOSTAP) + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); return rfilt; @@ -905,7 +905,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * Enable this if you want to see * error frames in Monitor mode. */ - if (sc->sc_opmode != ATH9K_M_MONITOR) + if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) goto rx_next; #endif /* fall thru for monitor mode handling... */ @@ -950,7 +950,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (sc->sc_opmode == ATH9K_M_MONITOR) { + if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { if (ds->ds_rxstat.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index a24a3a5b0e6..0b5b2dd9256 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1047,7 +1047,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * when perform internal reset in this routine. * Only enable reset in STA mode for now. */ - if (sc->sc_opmode == ATH9K_M_STA) + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) needreset = 1; } } else { @@ -1454,7 +1454,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, + if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { -- cgit v1.2.3 From 672840ac04f79f499b60b9f0eb41799c837db4eb Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:05:08 +0530 Subject: ath9k: Use bitfields for sc operations Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 4 ++-- drivers/net/wireless/ath9k/core.c | 45 +++++++++++++++++++------------------ drivers/net/wireless/ath9k/core.h | 24 +++++++++++--------- drivers/net/wireless/ath9k/main.c | 14 ++++++------ drivers/net/wireless/ath9k/rc.c | 2 +- drivers/net/wireless/ath9k/recv.c | 8 +++---- drivers/net/wireless/ath9k/xmit.c | 31 ++++++++++++------------- 7 files changed, 66 insertions(+), 62 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 2736a4b4e4a..f1c42014171 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -111,7 +111,7 @@ static void ath_beacon_setup(struct ath_softc *sc, rix = 0; rt = sc->sc_currates; rate = rt->info[rix].rateCode; - if (sc->sc_flags & ATH_PREAMBLE_SHORT) + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= rt->info[rix].shortPreamble; ath9k_hw_set11n_txdesc(ah, ds @@ -975,5 +975,5 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id) * beacon frame we just received. */ ath_beacon_config(sc, if_id); - sc->sc_beacons = 1; + sc->sc_flags |= SC_OP_BEACONS; } diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 8359356ac02..9b8258d9efd 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -272,8 +272,8 @@ static int ath_stop(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %u\n", - __func__, sc->sc_invalid); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", + __func__, sc->sc_flags & SC_OP_INVALID); /* * Shutdown the hardware and driver: @@ -291,10 +291,10 @@ static int ath_stop(struct ath_softc *sc) * hardware is gone (invalid). */ - if (!sc->sc_invalid) + if (!(sc->sc_flags & SC_OP_INVALID)) ath9k_hw_set_interrupts(ah, 0); ath_draintxq(sc, false); - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { ath_stoprecv(sc); ath9k_hw_phy_disable(ah); } else @@ -316,7 +316,7 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) bool fastcc = true, stopped; enum ath9k_ht_macmode ht_macmode; - if (sc->sc_invalid) /* if the device is invalid or removed */ + if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ return -EIO; DPRINTF(sc, ATH_DBG_CONFIG, @@ -332,7 +332,8 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) if (hchan->channel != sc->sc_curchan.channel || hchan->channelFlags != sc->sc_curchan.channelFlags || - sc->sc_update_chainmask || sc->sc_full_reset) { + (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || + (sc->sc_flags & SC_OP_FULL_RESET)) { int status; /* * This is only performed if the channel settings have @@ -351,7 +352,7 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) * to flush data frames already in queue because of * changing channel. */ - if (!stopped || sc->sc_full_reset) + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) fastcc = false; spin_lock_bh(&sc->sc_resetlock); @@ -372,8 +373,8 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) spin_unlock_bh(&sc->sc_resetlock); sc->sc_curchan = *hchan; - sc->sc_update_chainmask = 0; - sc->sc_full_reset = 0; + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; /* Re-enable rx framework */ if (ath_startrecv(sc) != 0) { @@ -484,7 +485,7 @@ int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an) void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - sc->sc_update_chainmask = 1; + sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; if (is_ht) { sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; @@ -553,7 +554,7 @@ int ath_vap_listen(struct ath_softc *sc, int if_id) sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); /* need to reconfigure the beacons when it moves to RUN */ - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS; return 0; } @@ -773,7 +774,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) /* XXX: we must make sure h/w is ready and clear invalid flag * before turning on interrupt. */ - sc->sc_invalid = 0; + sc->sc_flags &= ~SC_OP_INVALID; done: return error; } @@ -816,7 +817,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_update_txpow(sc); - if (sc->sc_beacons) + if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ ath9k_hw_set_interrupts(ah, sc->sc_imask); @@ -841,7 +842,7 @@ int ath_suspend(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; /* No I/O if device has been surprise removed */ - if (sc->sc_invalid) + if (sc->sc_flags & SC_OP_INVALID) return -EIO; /* Shut off the interrupt before setting sc->sc_invalid to '1' */ @@ -849,7 +850,7 @@ int ath_suspend(struct ath_softc *sc) /* XXX: we must make sure h/w will not generate any interrupt * before setting the invalid flag. */ - sc->sc_invalid = 1; + sc->sc_flags |= SC_OP_INVALID; /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); @@ -870,7 +871,7 @@ irqreturn_t ath_isr(int irq, void *dev) bool sched = false; do { - if (sc->sc_invalid) { + if (sc->sc_flags & SC_OP_INVALID) { /* * The hardware is not ready/present, don't * touch anything. Note this can happen early @@ -1026,7 +1027,7 @@ int ath_init(u16 devid, struct ath_softc *sc) u32 rd; /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_invalid = 1; + sc->sc_flags |= SC_OP_INVALID; sc->sc_debug = DBG_DEFAULT; DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); @@ -1210,8 +1211,8 @@ int ath_init(u16 devid, struct ath_softc *sc) /* 11n Capabilities */ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_txaggr = 1; - sc->sc_rxaggr = 1; + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; } sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; @@ -1267,7 +1268,7 @@ void ath_deinit(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); ath_stop(sc); - if (!sc->sc_invalid) + if (!(sc->sc_flags & SC_OP_INVALID)) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); ath_rate_detach(sc->sc_rc); /* cleanup tx queues */ @@ -1394,9 +1395,9 @@ void ath_newassoc(struct ath_softc *sc, /* if station reassociates, tear down the aggregation state. */ if (!isnew) { for (tidno = 0; tidno < WME_NUM_TID; tidno++) { - if (sc->sc_txaggr) + if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_aggr_teardown(sc, an, tidno); - if (sc->sc_rxaggr) + if (sc->sc_flags & SC_OP_RXAGGR) ath_rx_aggr_teardown(sc, an, tidno); } } diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index bfe16230b5e..702f7b8eba5 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -830,8 +830,6 @@ void ath_setdefantenna(void *sc, u32 antenna); #define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_PREAMBLE_SHORT (1<<0) -#define ATH_PROTECT_ENABLE (1<<1) #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -892,25 +890,30 @@ struct ath_ht_info { u8 ext_chan_offset; }; +#define SC_OP_INVALID BIT(0) +#define SC_OP_BEACONS BIT(1) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_CHAINMASK_UPDATE BIT(4) +#define SC_OP_FULL_RESET BIT(5) +#define SC_OP_PREAMBLE_SHORT BIT(6) +#define SC_OP_PROTECT_ENABLE BIT(7) + struct ath_softc { struct ieee80211_hw *hw; struct pci_dev *pdev; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; - struct ath_config sc_config; /* load-time parameters */ + struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; /* tx rate control support */ + struct ath_rate_softc *sc_rc; void __iomem *mem; int sc_debug; u32 sc_intrstatus; + u32 sc_flags; /* SC_OP_* */ unsigned int rx_filter; - u8 sc_invalid; /* being detached */ - u8 sc_beacons; /* beacons running */ - u8 sc_txaggr; /* enable 11n tx aggregation */ - u8 sc_rxaggr; /* enable 11n rx aggregation */ - u8 sc_update_chainmask; /* change chain mask */ - u8 sc_full_reset; /* force full reset */ + enum wireless_mode sc_curmode; /* current phy mode */ u16 sc_curtxpow; u16 sc_curaid; @@ -944,7 +947,6 @@ struct ath_softc { u8 sc_rxchaindetect_delta5GHz; u8 sc_rxchaindetect_delta2GHz; u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */ - u32 sc_flags; #ifdef CONFIG_SLOW_ANT_DIV struct ath_antdiv sc_antdiv; #endif diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7504b64020c..7fb57ee4c43 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -481,7 +481,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, /* Set interrupt mask */ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL); - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS; error = ath_vap_detach(sc, 0); if (error) @@ -582,7 +582,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, print_mac(mac, sc->sc_curbssid), sc->sc_curaid); /* need to reconfigure the beacon */ - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS ; break; default: @@ -833,7 +833,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* Configure the beacon */ ath_beacon_config(sc, 0); - sc->sc_beacons = 1; + sc->sc_flags |= SC_OP_BEACONS; /* Reset rssi stats */ sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; @@ -896,9 +896,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, __func__, bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) - sc->sc_flags |= ATH_PREAMBLE_SHORT; + sc->sc_flags |= SC_OP_PREAMBLE_SHORT; else - sc->sc_flags &= ~ATH_PREAMBLE_SHORT; + sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; } if (changed & BSS_CHANGED_ERP_CTS_PROT) { @@ -907,9 +907,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) - sc->sc_flags |= ATH_PROTECT_ENABLE; + sc->sc_flags |= SC_OP_PROTECT_ENABLE; else - sc->sc_flags &= ~ATH_PROTECT_ENABLE; + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } if (changed & BSS_CHANGED_HT) { diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 73c460ad355..20e10849e93 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1903,7 +1903,7 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, int state; DECLARE_MAC_BUF(mac); - if (!sc->sc_txaggr) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return; txtid = ATH_AN_2_TID(an, tidno); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 6d1d5035f15..9c7583210e3 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -724,7 +724,7 @@ int ath_rx_input(struct ath_softc *sc, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status) { - if (is_ampdu && sc->sc_rxaggr) { + if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { *status = ATH_RX_CONSUMED; return ath_ampdu_input(sc, an, skb, rx_status); } else { @@ -1132,7 +1132,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, rxtid = &an->an_aggr.rx.tid[tid]; spin_lock_bh(&rxtid->tidlock); - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { /* Allow aggregation reception * Adjust rx BA window size. Peer might indicate a * zero buffer size for a _dont_care_ condition. @@ -1232,7 +1232,7 @@ void ath_rx_aggr_teardown(struct ath_softc *sc, void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; int tidno; @@ -1264,7 +1264,7 @@ void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; int tidno, i; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 0b5b2dd9256..75a84924b4d 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -392,7 +392,7 @@ static int ath_tx_prepare(struct ath_softc *sc, * incremented by the fragmentation routine. */ if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) && - txctl->ht && sc->sc_txaggr) { + txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { struct ath_atx_tid *tid; tid = ATH_AN_2_TID(txctl->an, txctl->tidno); @@ -422,7 +422,7 @@ static int ath_tx_prepare(struct ath_softc *sc, /* * XXX not right with fragmentation. */ - if (sc->sc_flags & ATH_PREAMBLE_SHORT) + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) dur = rt->info[rix].spAckDuration; else dur = rt->info[rix].lpAckDuration; @@ -438,8 +438,9 @@ static int ath_tx_prepare(struct ath_softc *sc, ** Add time for next fragment. */ dur += ath9k_hw_computetxtime(sc->sc_ah, rt, - txctl->nextfraglen, - rix, sc->sc_flags & ATH_PREAMBLE_SHORT); + txctl->nextfraglen, + rix, + (sc->sc_flags & SC_OP_PREAMBLE_SHORT)); } if (ieee80211_has_morefrags(fc) || @@ -1406,7 +1407,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) /* * schedule any pending packets if aggregation is enabled */ - if (sc->sc_txaggr) + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } @@ -1433,7 +1434,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); /* XXX return value */ - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { ath_tx_stopdma(sc, &sc->sc_txq[i]); @@ -2024,7 +2025,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, ieee80211_is_pspoll(fc) ? (bf->bf_state.bf_type |= BUF_PSPOLL) : (bf->bf_state.bf_type &= ~BUF_PSPOLL); - (sc->sc_flags & ATH_PREAMBLE_SHORT) ? + (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); @@ -2076,7 +2077,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, spin_lock_bh(&txq->axq_lock); - if (txctl->ht && sc->sc_txaggr) { + if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno); if (ath_aggr_query(sc, an, txctl->tidno)) { /* @@ -2153,7 +2154,7 @@ static void xmit_map_sg(struct ath_softc *sc, tx_status.retries = 0; tx_status.flags = ATH_TX_ERROR; - if (txctl->ht && sc->sc_txaggr) { + if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { /* Reclaim the seqno. */ tid = ATH_AN_2_TID((struct ath_node *) txctl->an, txctl->tidno); @@ -2505,7 +2506,7 @@ void ath_tx_draintxq(struct ath_softc *sc, } /* flush any pending frames if aggregation is enabled */ - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { spin_lock_bh(&txq->axq_lock); ath_txq_drain_pending_buffers(sc, txq, @@ -2521,7 +2522,7 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) { /* stop beacon queue. The beacon will be freed when * we go to INIT state */ - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__, ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); @@ -2548,7 +2549,7 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, struct ath_atx_tid *txtid; DECLARE_MAC_BUF(mac); - if (!sc->sc_txaggr) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return AGGR_NOT_REQUIRED; /* ADDBA exchange must be completed before sending aggregates */ @@ -2595,7 +2596,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, return -1; } - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); txtid->addba_exchangeinprogress = 1; ath_tx_pause_tid(sc, txtid); @@ -2755,7 +2756,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { struct ath_atx_tid *tid; struct ath_atx_ac *ac; int tidno, acno; @@ -2867,7 +2868,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { struct ath_atx_tid *tid; int tidno, i; -- cgit v1.2.3 From 7c56d24bc80112daadc7ef54247a5fc8397dbc5c Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:05:26 +0530 Subject: ath9k: Use ah_curchan and remove sc_curchan which is redundant Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 20 +++++++++----------- drivers/net/wireless/ath9k/core.h | 1 - drivers/net/wireless/ath9k/rc.c | 4 ++-- drivers/net/wireless/ath9k/xmit.c | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 9b8258d9efd..87b4ca525d2 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -322,16 +322,16 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) DPRINTF(sc, ATH_DBG_CONFIG, "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", __func__, - ath9k_hw_mhz2ieee(ah, sc->sc_curchan.channel, - sc->sc_curchan.channelFlags), - sc->sc_curchan.channel, + ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel, + sc->sc_ah->ah_curchan->channelFlags), + sc->sc_ah->ah_curchan->channel, ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), hchan->channel, hchan->channelFlags); ht_macmode = ath_cwm_macmode(sc); - if (hchan->channel != sc->sc_curchan.channel || - hchan->channelFlags != sc->sc_curchan.channelFlags || + if (hchan->channel != sc->sc_ah->ah_curchan->channel || + hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || (sc->sc_flags & SC_OP_FULL_RESET)) { int status; @@ -372,7 +372,6 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) } spin_unlock_bh(&sc->sc_resetlock); - sc->sc_curchan = *hchan; sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; sc->sc_flags &= ~SC_OP_FULL_RESET; @@ -702,16 +701,15 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - sc->sc_curchan = *initial_chan; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, + if (!ath9k_hw_reset(ah, initial_chan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u " "(freq %u flags 0x%x)\n", __func__, status, - sc->sc_curchan.channel, sc->sc_curchan.channelFlags); + initial_chan->channel, initial_chan->channelFlags); error = -EIO; spin_unlock_bh(&sc->sc_resetlock); goto done; @@ -793,7 +791,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, &sc->sc_curchan, + if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { @@ -813,7 +811,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) * that changes the channel so update any state that * might change as a result. */ - ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan)); + ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); ath_update_txpow(sc); diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 702f7b8eba5..7f4bd15fa7e 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1001,7 +1001,6 @@ struct ath_softc { /* Channel, Band */ struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - struct ath9k_channel sc_curchan; /* Locks */ spinlock_t sc_rxflushlock; diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 20e10849e93..1392361ef9a 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -847,9 +847,9 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) /* For half and quarter rate channles use different * rate tables */ - if (sc->sc_curchan.channelFlags & CHANNEL_HALF) + if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF) ar5416_sethalf_ratetable(asc); - else if (sc->sc_curchan.channelFlags & CHANNEL_QUARTER) + else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER) ar5416_setquarter_ratetable(asc); else /* full rate */ ar5416_setfull_ratetable(asc); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 75a84924b4d..9ea5d933330 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1456,7 +1456,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, - &sc->sc_curchan, ht_macmode, + sc->sc_ah->ah_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { -- cgit v1.2.3 From 98deeea0b3464955ec416c30cbd0c3d21cacfa9a Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:05:46 +0530 Subject: ath9k: Trim struct ath_softc Add sc_rxflush and sc_noreset as bitfields to sc_flags. Remove a few variables and function prototypes that are unused. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 8 ++--- drivers/net/wireless/ath9k/core.c | 10 ------- drivers/net/wireless/ath9k/core.h | 58 ++++++++++++++----------------------- drivers/net/wireless/ath9k/recv.c | 8 ++--- drivers/net/wireless/ath9k/xmit.c | 8 ++--- 5 files changed, 31 insertions(+), 61 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index f1c42014171..e0ca0172f8b 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -555,7 +555,7 @@ void ath9k_beacon_tasklet(unsigned long data) u32 tsftu; u16 intval; - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, &rx_clear, &rx_frame, @@ -577,7 +577,7 @@ void ath9k_beacon_tasklet(unsigned long data) * (in that layer). */ if (sc->sc_bmisscount < BSTUCK_THRESH) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "%s: missed %u consecutive beacons\n", __func__, sc->sc_bmisscount); @@ -605,7 +605,7 @@ void ath9k_beacon_tasklet(unsigned long data) __func__, sc->sc_bmisscount); } } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_bmisscount == BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, @@ -624,7 +624,7 @@ void ath9k_beacon_tasklet(unsigned long data) return; } if (sc->sc_bmisscount != 0) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "%s: resume beacon xmit after %u misses\n", diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 87b4ca525d2..0d953f9fdee 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1055,9 +1055,6 @@ int ath_init(u16 devid, struct ath_softc *sc) } sc->sc_ah = ah; - /* Get the chipset-specific aggr limit. */ - sc->sc_rtsaggrlimit = ah->ah_caps.rts_aggr_limit; - /* Get the hardware key cache size. */ sc->sc_keymax = ah->ah_caps.keycache_size; if (sc->sc_keymax > ATH_KEYMAX) { @@ -1216,13 +1213,6 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - /* Configuration for rx chain detection */ - sc->sc_rxchaindetect_ref = 0; - sc->sc_rxchaindetect_thresh5GHz = 35; - sc->sc_rxchaindetect_thresh2GHz = 35; - sc->sc_rxchaindetect_delta5GHz = 30; - sc->sc_rxchaindetect_delta2GHz = 30; - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->sc_defant = ath9k_hw_getdefantenna(ah); diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 7f4bd15fa7e..8243ff049b6 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -724,11 +724,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); int ath_beacon_alloc(struct ath_softc *sc, int if_id); void ath_bstuck_process(struct ath_softc *sc); -void ath_beacon_tasklet(struct ath_softc *sc, int *needmark); -void ath_beacon_free(struct ath_softc *sc); void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); void ath_beacon_sync(struct ath_softc *sc, int if_id); -void ath_update_beacon_info(struct ath_softc *sc, int avgbrssi); void ath_get_beaconconfig(struct ath_softc *sc, int if_id, struct ath_beacon_config *conf); @@ -896,8 +893,10 @@ struct ath_ht_info { #define SC_OP_TXAGGR BIT(3) #define SC_OP_CHAINMASK_UPDATE BIT(4) #define SC_OP_FULL_RESET BIT(5) -#define SC_OP_PREAMBLE_SHORT BIT(6) -#define SC_OP_PROTECT_ENABLE BIT(7) +#define SC_OP_NO_RESET BIT(6) +#define SC_OP_PREAMBLE_SHORT BIT(7) +#define SC_OP_PROTECT_ENABLE BIT(8) +#define SC_OP_RXFLUSH BIT(9) struct ath_softc { struct ieee80211_hw *hw; @@ -909,44 +908,39 @@ struct ath_softc { struct ath_rate_softc *sc_rc; void __iomem *mem; + u8 sc_curbssid[ETH_ALEN]; + u8 sc_myaddr[ETH_ALEN]; + u8 sc_bssidmask[ETH_ALEN]; + int sc_debug; u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ unsigned int rx_filter; - - enum wireless_mode sc_curmode; /* current phy mode */ u16 sc_curtxpow; u16 sc_curaid; - u8 sc_curbssid[ETH_ALEN]; - u8 sc_myaddr[ETH_ALEN]; + u16 sc_cachelsz; + int sc_slotupdate; /* slot to next advance fsm */ + int sc_slottime; + int sc_bslot[ATH_BCBUF]; + u8 sc_tx_chainmask; + u8 sc_rx_chainmask; + enum ath9k_int sc_imask; + enum wireless_mode sc_curmode; /* current phy mode */ enum PROT_MODE sc_protmode; - u8 sc_mcastantenna; - u8 sc_txantenna; /* data tx antenna (fixed or auto) */ + u8 sc_nbcnvaps; /* # of vaps sending beacons */ u16 sc_nvaps; /* # of active virtual ap's */ struct ath_vap *sc_vaps[ATH_BCBUF]; - enum ath9k_int sc_imask; - u8 sc_bssidmask[ETH_ALEN]; + + u8 sc_mcastantenna; u8 sc_defant; /* current default antenna */ u8 sc_rxotherant; /* rx's on non-default antenna */ - u16 sc_cachelsz; - int sc_slotupdate; /* slot to next advance fsm */ - int sc_slottime; - u8 sc_noreset; - int sc_bslot[ATH_BCBUF]; + struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ struct list_head node_list; struct ath_ht_info sc_ht_info; - int16_t sc_noise_floor; /* signal noise floor in dBm */ enum ath9k_ht_extprotspacing sc_ht_extprotspacing; - u8 sc_tx_chainmask; - u8 sc_rx_chainmask; - u8 sc_rxchaindetect_ref; - u8 sc_rxchaindetect_thresh5GHz; - u8 sc_rxchaindetect_thresh2GHz; - u8 sc_rxchaindetect_delta5GHz; - u8 sc_rxchaindetect_delta2GHz; - u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */ + #ifdef CONFIG_SLOW_ANT_DIV struct ath_antdiv sc_antdiv; #endif @@ -967,7 +961,6 @@ struct ath_softc { struct ath_descdma sc_rxdma; int sc_rxbufsize; /* rx size based on mtu */ u32 *sc_rxlink; /* link ptr in last RX desc */ - u32 sc_rxflush; /* rx flush in progress */ u64 sc_lastrx; /* tsf of last rx'd frame */ /* TX */ @@ -977,7 +970,6 @@ struct ath_softc { u32 sc_txqsetup; u32 sc_txintrperiod; /* tx interrupt batching */ int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ - u32 sc_ant_tx[8]; /* recent tx frames/antenna */ /* Beacon */ struct ath9k_tx_queue_info sc_beacon_qi; @@ -1016,13 +1008,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); int ath_suspend(struct ath_softc *sc); irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc, bool retry_tx); -void ath_scan_start(struct ath_softc *sc); -void ath_scan_end(struct ath_softc *sc); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); -void ath_setup_rate(struct ath_softc *sc, - enum wireless_mode wMode, - enum RATE_TYPE type, - const struct ath9k_rate_table *rt); /*********************/ /* Utility Functions */ @@ -1041,7 +1027,6 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc); dma_addr_t ath_skb_map_single(struct ath_softc *sc, struct sk_buff *skb, int direction, @@ -1050,7 +1035,6 @@ void ath_skb_unmap_single(struct ath_softc *sc, struct sk_buff *skb, int direction, dma_addr_t *pa); -void ath_mcast_merge(struct ath_softc *sc, u32 mfilt[2]); enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 9c7583210e3..af2011fb05a 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -504,7 +504,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) do { spin_lock_init(&sc->sc_rxflushlock); - sc->sc_rxflush = 0; + sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->sc_rxbuflock); /* @@ -707,11 +707,11 @@ void ath_flushrecv(struct ath_softc *sc) * progress (see references to sc_rxflush) */ spin_lock_bh(&sc->sc_rxflushlock); - sc->sc_rxflush = 1; + sc->sc_flags |= SC_OP_RXFLUSH; ath_rx_tasklet(sc, 1); - sc->sc_rxflush = 0; + sc->sc_flags &= ~SC_OP_RXFLUSH; spin_unlock_bh(&sc->sc_rxflushlock); } @@ -755,7 +755,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) do { /* If handling rx interrupt and flush is in progress => exit */ - if (sc->sc_rxflush && (flush == 0)) + if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; spin_lock_bh(&sc->sc_rxbuflock); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 9ea5d933330..e2ffa1cdb5e 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -485,12 +485,8 @@ static int ath_tx_prepare(struct ath_softc *sc, if (is_multicast_ether_addr(hdr->addr1)) { antenna = sc->sc_mcastantenna + 1; sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; - } else - antenna = sc->sc_txantenna; + } -#ifdef USE_LEGACY_HAL - txctl->antenna = antenna; -#endif return 0; } @@ -743,7 +739,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) int i, flags, rtsctsena = 0, dynamic_mimops = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; - u32 aggr_limit_with_rts = sc->sc_rtsaggrlimit; + u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; struct ath_node *an = (struct ath_node *) bf->bf_node; /* -- cgit v1.2.3 From 2ad67de3c8a21354b8b2721d5d2baabb7c5013c9 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:47 +0300 Subject: ath9k: Allow AP mode to be enabled Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 12 +++++++++--- drivers/net/wireless/ath9k/main.c | 19 +++++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 0d953f9fdee..9737775aad3 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -549,9 +549,15 @@ int ath_vap_listen(struct ath_softc *sc, int if_id) * XXXX * Disable BMISS interrupt when we're not associated */ - ath9k_hw_set_interrupts(ah, - sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + ath9k_hw_set_interrupts(ah, sc->sc_imask & ~ATH9K_INT_BMISS); + sc->sc_imask &= ~ATH9K_INT_BMISS; + } else { + ath9k_hw_set_interrupts( + ah, + sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); + sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + } /* need to reconfigure the beacons when it moves to RUN */ sc->sc_flags &= ~SC_OP_BEACONS; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7fb57ee4c43..183c76e1187 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -426,10 +426,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, case IEEE80211_IF_TYPE_IBSS: ic_opmode = ATH9K_M_IBSS; break; + case IEEE80211_IF_TYPE_AP: + ic_opmode = ATH9K_M_HOSTAP; + break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Only STA and IBSS are supported currently\n", - __func__); + "%s: Interface type %d not yet supported\n", + __func__, conf->type); return -EOPNOTSUPP; } @@ -530,6 +533,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp; u32 rfilt = 0; int error, i; @@ -542,6 +546,17 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, return -EINVAL; } + /* TODO: Need to decide which hw opmode to use for multi-interface + * cases */ + if (vif->type == IEEE80211_IF_TYPE_AP && + ah->ah_opmode != ATH9K_M_HOSTAP) { + ah->ah_opmode = ATH9K_M_HOSTAP; + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); + /* Request full reset to get hw opmode changed properly */ + sc->sc_flags |= SC_OP_FULL_RESET; + } + if ((conf->changed & IEEE80211_IFCC_BSSID) && !is_zero_ether_addr(conf->bssid)) { switch (vif->type) { -- cgit v1.2.3 From a8fff50e4d6aad520b261b3c32e2c67a7dfb7228 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:48 +0300 Subject: ath9k: Updated Beacon generation to use mac80211-style This change moves ath9k to use mac80211-generated Beacon frames instead of trying to allocate a single Beacon frame and then update it. In addition, the remaining ath_skb_{map,unmap}_single() wrapper calls are replaced with direct pci_{map,unmap}_single() calls in beacon.c. Power save buffering for multicast/broadcast frames is not yet converted to use mac80211-style (frames to be buffered inside mac80211, not in driver). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 72 ++++++++++++++++++------------------- drivers/net/wireless/ath9k/core.h | 5 --- drivers/net/wireless/ath9k/main.c | 21 ++++++----- 3 files changed, 48 insertions(+), 50 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index e0ca0172f8b..8abcd3e8a30 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -172,6 +172,7 @@ static void empty_mcastq_into_cabq(struct ath_hal *ah, mcastq->axq_link = NULL; } +/* TODO: use ieee80211_get_buffered_bc() to fetch power saved mcast frames */ /* This is only run at DTIM. We move everything from the vap's mcast queue * to the hardware cab queue. Caller must hold the mcastq lock. */ static void trigger_mcastq(struct ath_hal *ah, @@ -206,7 +207,6 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) int cabq_depth; int mcastq_depth; int is_beacon_dtim = 0; - unsigned int curlen; struct ath_txq *cabq; struct ath_txq *mcastq; avp = sc->sc_vaps[if_id]; @@ -223,33 +223,27 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) } bf = avp->av_bcbuf; skb = (struct sk_buff *) bf->bf_mpdu; + if (skb) { + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); + } - /* - * Update dynamic beacon contents. If this returns - * non-zero then we need to remap the memory because - * the beacon frame changed size (probably because - * of the TIM bitmap). - */ - curlen = skb->len; + skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + bf->bf_mpdu = skb; + if (skb == NULL) + return NULL; + bf->bf_buf_addr = bf->bf_dmacontext = + pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); + /* TODO: convert to use ieee80211_get_buffered_bc() */ /* XXX: spin_lock_bh should not be used here, but sparse bitches * otherwise. We should fix sparse :) */ spin_lock_bh(&mcastq->axq_lock); mcastq_depth = avp->av_mcastq.axq_depth; - if (ath_update_beacon(sc, if_id, &avp->av_boff, skb, mcastq_depth) == - 1) { - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - } else { - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - skb_tailroom(skb), - PCI_DMA_TODEVICE); - } - /* * if the CABQ traffic from previous DTIM is pending and the current * beacon is also a DTIM. @@ -262,7 +256,8 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); - is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; + if (avp->av_boff.bo_tim) + is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; if (mcastq_depth && is_beacon_dtim && cabq_depth) { /* @@ -408,8 +403,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { skb = (struct sk_buff *)bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -439,9 +435,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) __le64 val; int intval; - /* FIXME: Use default value for now: Sujith */ - - intval = ATH_DEFAULT_BINTVAL; + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; /* * The beacon interval is in TU's; the TSF in usecs. @@ -466,8 +461,10 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) memcpy(&wh[1], &val, sizeof(val)); } - bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = bf->bf_dmacontext = + pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); bf->bf_mpdu = skb; return 0; @@ -493,8 +490,9 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -520,8 +518,9 @@ void ath_beacon_free(struct ath_softc *sc) list_for_each_entry(bf, &sc->sc_bbuf, list) { if (bf->bf_mpdu != NULL) { struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -643,8 +642,8 @@ void ath9k_beacon_tasklet(unsigned long data) * on the tsf to safeguard against missing an swba. */ - /* FIXME: Use default value for now - Sujith */ - intval = ATH_DEFAULT_BINTVAL; + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); @@ -760,7 +759,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * Protocol stack doesn't support dynamic beacon configuration, * use default configurations. */ - conf.beacon_interval = ATH_DEFAULT_BINTVAL; + conf.beacon_interval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; conf.listen_interval = 1; conf.dtim_period = conf.beacon_interval; conf.dtim_count = 1; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 8243ff049b6..bf731940188 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -729,11 +729,6 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id); void ath_get_beaconconfig(struct ath_softc *sc, int if_id, struct ath_beacon_config *conf); -int ath_update_beacon(struct ath_softc *sc, - int if_id, - struct ath_beacon_offset *bo, - struct sk_buff *skb, - int mcast); /********/ /* VAPs */ /********/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 183c76e1187..f904cf67dba 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -624,6 +624,18 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, ath_beacon_sync(sc, 0); } + if ((conf->changed & IEEE80211_IFCC_BEACON) && + (vif->type == IEEE80211_IF_TYPE_AP)) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + + error = ath_beacon_alloc(sc, 0); + if (error != 0) + return error; + + ath_beacon_config(sc, 0); + sc->sc_flags |= SC_OP_BEACONS; + } + /* Check for WLAN_CAPABILITY_PRIVACY ? */ if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) @@ -1052,15 +1064,6 @@ void ath_get_beaconconfig(struct ath_softc *sc, conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; } -int ath_update_beacon(struct ath_softc *sc, - int if_id, - struct ath_beacon_offset *bo, - struct sk_buff *skb, - int mcast) -{ - return 0; -} - void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ath_xmit_status *tx_status, struct ath_node *an) { -- cgit v1.2.3 From 580f0b8a6dc1cb4d32c351a507d1c1d319bdc1eb Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:49 +0300 Subject: ath9k: Fix TX status reporting Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f904cf67dba..4b61666261e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1085,8 +1085,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; tx_status->flags &= ~ATH_TX_BAR; } - if (tx_status->flags) - tx_info->status.excessive_retries = 1; + + if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { + /* Frame was not ACKed, but an ACK was expected */ + tx_info->status.excessive_retries = 1; + } + } else { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } tx_info->status.retry_count = tx_status->retries; -- cgit v1.2.3 From 147583c057c43095925b5f331fe304f2d5b997ba Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:50 +0300 Subject: ath9k: Assign seq# when mac80211 requests this Use TX control flag IEEE80211_TX_CTL_ASSIGN_SEQ as a request to update the seq# for the frames. This will likely require some further cleanup to get seq# correctly for Beacons vs. other frames and also potentially for multiple BSSes. Anyway, this is better than ending up sending out most frames with seq# 0. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 12 ++++++++++++ drivers/net/wireless/ath9k/core.h | 1 + drivers/net/wireless/ath9k/main.c | 14 ++++++++++++++ 3 files changed, 27 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 8abcd3e8a30..a020f9a2154 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -209,6 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) int is_beacon_dtim = 0; struct ath_txq *cabq; struct ath_txq *mcastq; + struct ieee80211_tx_info *info; avp = sc->sc_vaps[if_id]; mcastq = &avp->av_mcastq; @@ -233,6 +234,17 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) bf->bf_mpdu = skb; if (skb == NULL) return NULL; + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + /* + * TODO: make sure the seq# gets assigned properly (vs. other + * TX frames) + */ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb_end_pointer(skb) - skb->head, diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index bf731940188..c242942bbc1 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -965,6 +965,7 @@ struct ath_softc { u32 sc_txqsetup; u32 sc_txintrperiod; /* tx interrupt batching */ int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ + u16 seq_no; /* TX sequence number */ /* Beacon */ struct ath9k_tx_queue_info sc_beacon_qi; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 4b61666261e..8fbde897406 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -368,6 +368,20 @@ static int ath9k_tx(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } /* Add the padding after the header if this is not already done */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); -- cgit v1.2.3 From b14ecdd0afa4f616fcd1fcff4b902e15334256c7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:51 +0300 Subject: ath9k: Fix TX control flag use for no ACK and RTS/CTS Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index e2ffa1cdb5e..55f3c8e5bbb 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc, txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - tx_info->flags |= ATH9K_TXDESC_NOACK; + txctl->flags |= ATH9K_TXDESC_NOACK; if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - tx_info->flags |= ATH9K_TXDESC_RTSENA; + txctl->flags |= ATH9K_TXDESC_RTSENA; /* * Setup for rate calculations. -- cgit v1.2.3 From 927e70e9244e6ecdc7c28bc5424b0b8c11dee314 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:26:34 +0530 Subject: ath9k: Remove remaining occurences of ath_skb_map functions Use direct pci functions instead. Also, use sc_ht_info.tx_chan_width directly and remove ath_cwm_macmode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 27 ++++++++++++-------------- drivers/net/wireless/ath9k/core.h | 9 --------- drivers/net/wireless/ath9k/recv.c | 40 ++++++++------------------------------- drivers/net/wireless/ath9k/xmit.c | 8 ++++---- 4 files changed, 24 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 9737775aad3..a9e8ad053a3 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -314,7 +314,6 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) { struct ath_hal *ah = sc->sc_ah; bool fastcc = true, stopped; - enum ath9k_ht_macmode ht_macmode; if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ return -EIO; @@ -328,8 +327,6 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), hchan->channel, hchan->channelFlags); - ht_macmode = ath_cwm_macmode(sc); - if (hchan->channel != sc->sc_ah->ah_curchan->channel || hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || @@ -357,10 +354,11 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, hchan, - ht_macmode, sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - fastcc, &status)) { + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, + sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, + fastcc, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset channel %u (%uMhz) " "flags 0x%x hal status %u\n", __func__, @@ -682,7 +680,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) struct ath_hal *ah = sc->sc_ah; int status; int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_ah->ah_opmode); @@ -709,9 +706,10 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, initial_chan, ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + if (!ath9k_hw_reset(ah, initial_chan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u " "(freq %u flags 0x%x)\n", __func__, status, @@ -788,7 +786,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) struct ath_hal *ah = sc->sc_ah; int status; int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ ath_draintxq(sc, retry_tx); /* stop xmit */ @@ -798,9 +795,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u\n", __func__, status); diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index c242942bbc1..51bf528e4c1 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1023,14 +1023,5 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -dma_addr_t ath_skb_map_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa); -void ath_skb_unmap_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa); -enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index af2011fb05a..91f635411ab 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -454,11 +454,10 @@ static int ath_rx_indicate(struct ath_softc *sc, nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); if (nskb != NULL) { bf->bf_mpdu = nskb; - bf->bf_buf_addr = ath_skb_map_single(sc, - nskb, - PCI_DMA_FROMDEVICE, - /* XXX: Remove get_dma_mem_context() */ - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data, + skb_end_pointer(nskb) - nskb->head, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; /* queue the new wbuf to H/W */ @@ -541,9 +540,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } bf->bf_mpdu = skb; - bf->bf_buf_addr = - ath_skb_map_single(sc, skb, PCI_DMA_FROMDEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf; } sc->sc_rxlink = NULL; @@ -1297,27 +1297,3 @@ void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) { ath_rx_node_cleanup(sc, an); } - -dma_addr_t ath_skb_map_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa) -{ - /* - * NB: do NOT use skb->len, which is 0 on initialization. - * Use skb's entire data area instead. - */ - *pa = pci_map_single(sc->pdev, skb->data, - skb_end_pointer(skb) - skb->head, direction); - return *pa; -} - -void ath_skb_unmap_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa) -{ - /* Unmap skb's entire data area */ - pci_unmap_single(sc->pdev, *pa, - skb_end_pointer(skb) - skb->head, direction); -} diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 55f3c8e5bbb..8d31ad7952b 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1427,7 +1427,6 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) struct ath_hal *ah = sc->sc_ah; int i; int npend = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); /* XXX return value */ if (!(sc->sc_flags & SC_OP_INVALID)) { @@ -1452,9 +1451,10 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, - sc->sc_ah->ah_curchan, ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, true, &status)) { + sc->sc_ah->ah_curchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, true, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u\n", -- cgit v1.2.3 From dc2222a85fd63103b9aad0d4b77c4d87b78c58a2 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:26:55 +0530 Subject: ath9k: Random cleanup Remove dead code, add newlines, fix indentation. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 5 +- drivers/net/wireless/ath9k/hw.c | 13 +--- drivers/net/wireless/ath9k/rc.c | 159 +++++++++++++++++++------------------- 3 files changed, 83 insertions(+), 94 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index a9e8ad053a3..e3682b6ccfb 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1025,7 +1025,6 @@ int ath_init(u16 devid, struct ath_softc *sc) int status; int error = 0, i; int csz = 0; - u32 rd; /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; @@ -1091,8 +1090,6 @@ int ath_init(u16 devid, struct ath_softc *sc) * is resposible for filtering this list based on settings * like the phy mode. */ - rd = ah->ah_currentRD; - error = ath_setup_channels(sc); if (error) goto bad; @@ -1169,7 +1166,7 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_rc = ath_rate_attach(ah); if (sc->sc_rc == NULL) { - error = EIO; + error = -EIO; goto bad2; } diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 24b78c2eb44..7d8c908d69d 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -7654,8 +7654,7 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) REG_WRITE(ah, AR_DRETRY_LIMIT(q), SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) - | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) - ); + | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); REG_WRITE(ah, AR_DMISC(q), @@ -8300,15 +8299,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, *error = -ENXIO; break; } - if (ah != NULL) { - ah->ah_devid = ah->ah_devid; - ah->ah_subvendorid = ah->ah_subvendorid; - ah->ah_macVersion = ah->ah_macVersion; - ah->ah_macRev = ah->ah_macRev; - ah->ah_phyRev = ah->ah_phyRev; - ah->ah_analog5GhzRev = ah->ah_analog5GhzRev; - ah->ah_analog2GhzRev = ah->ah_analog2GhzRev; - } + return ah; } diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1392361ef9a..1dd7c71daf0 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -653,8 +653,8 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); for (i = 0; i < rate_table->rate_cnt; i++) { valid = (ath_rc_priv->single_stream ? - rate_table->info[i].valid_single_stream : - rate_table->info[i].valid); + rate_table->info[i].valid_single_stream : + rate_table->info[i].valid); if (valid == TRUE) { u32 phy = rate_table->info[i].phy; u8 valid_rate_count = 0; @@ -740,14 +740,14 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; u32 valid = (ath_rc_priv->single_stream ? - rate_table->info[j].valid_single_stream : - rate_table->info[j].valid); + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); if (((((struct ath_rateset *) - mcs_set)->rs_rates[i] & 0x7F) != - (rate_table->info[j].dot11rate & 0x7F)) || - !WLAN_RC_PHY_HT(phy) || - !WLAN_RC_PHY_HT_VALID(valid, capflag)) + mcs_set)->rs_rates[i] & 0x7F) != + (rate_table->info[j].dot11rate & 0x7F)) || + !WLAN_RC_PHY_HT(phy) || + !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) @@ -866,10 +866,10 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - int probe_allowed, int *is_probing, - int is_retry) + struct ath_rate_node *ath_rc_priv, + const struct ath_rate_table *rate_table, + int probe_allowed, int *is_probing, + int is_retry) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -997,8 +997,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, rate = rate_ctrl->rate_table_size - 1; ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || - (rate_table->info[rate].valid_single_stream && - ath_rc_priv->single_stream)); + (rate_table->info[rate].valid_single_stream && + ath_rc_priv->single_stream)); return rate; } @@ -1023,10 +1023,10 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table , } static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown, - u16 min_rate) + struct ath_rate_node *ath_rc_priv, + const struct ath_rate_table *rate_table, + u8 rix, u16 stepdown, + u16 min_rate) { u32 j; u8 nextindex; @@ -1066,8 +1066,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, rate_table = (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, - is_probe, is_retry); + (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + is_probe, is_retry); nrix = rix; if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) { @@ -1099,13 +1099,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_num = ((i + 1) == num_rates) ? num_tries - (try_per_rate * i) : try_per_rate ; min_rate = (((i + 1) == num_rates) && - (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; + (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, min_rate); + rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, - &series[i], try_num, nrix, TRUE); + &series[i], try_num, nrix, TRUE); } /* @@ -1124,13 +1124,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, * above conditions. */ if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { + (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || + (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || - (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { + (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { series[3].rix = series[2].rix; series[3].flags = series[2].flags; series[3].max_4ms_framelen = series[2].max_4ms_framelen; @@ -1152,7 +1152,8 @@ void ath_rate_findrate(struct ath_softc *sc, { struct ath_vap *avp = ath_rc_priv->avp; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + if (!num_rates || !num_tries) return; @@ -1174,9 +1175,8 @@ void ath_rate_findrate(struct ath_softc *sc, unsigned int mcs; u8 series_rix = 0; - series[idx].tries = - IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_retryset, idx); + series[idx].tries = IEEE80211_RATE_IDX_ENTRY( + avp->av_config.av_fixed_retryset, idx); mcs = IEEE80211_RATE_IDX_ENTRY( avp->av_config.av_fixed_rateset, idx); @@ -1228,7 +1228,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, u32 now_msec = jiffies_to_msecs(jiffies); int state_change = FALSE, rate, count; u8 last_per; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table = (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; @@ -1272,14 +1272,14 @@ static void ath_rc_update_ht(struct ath_softc *sc, } else { /* xretries == 2 */ count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + sizeof(nretry_to_per_lookup[0]); if (retries >= count) retries = count - 1; /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ rate_ctrl->state[tx_rate].per = (u8)(rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100) >> 3)); + (rate_ctrl->state[tx_rate].per >> 3) + + ((100) >> 3)); } /* xretries == 1 or 2 */ @@ -1295,8 +1295,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (retries >= count) retries = count - 1; if (info_priv->n_bad_frames) { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - /* + /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER * from the retries is 100 * retries / (retries+1), * since the first retries attempts failed, and the @@ -1386,7 +1385,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, * rssi_ack values. */ if (tx_rate == rate_ctrl->rate_max_phy && - rate_ctrl->hw_maxretry_pktcnt < 255) { + rate_ctrl->hw_maxretry_pktcnt < 255) { rate_ctrl->hw_maxretry_pktcnt++; } @@ -1418,7 +1417,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Now reduce the current * rssi threshold. */ if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { + (rssi_thres > rssi_ack_vmin)) { rate_ctrl->state[tx_rate]. rssi_thres--; } @@ -1436,10 +1435,10 @@ static void ath_rc_update_ht(struct ath_softc *sc, * a while (except if we are probing). */ if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { + rate_table->info[tx_rate].ratekbps <= + rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl, - (u8) tx_rate, &rate_ctrl->rate_max_phy); + (u8) tx_rate, &rate_ctrl->rate_max_phy); /* Don't probe for a little while. */ rate_ctrl->probe_time = now_msec; @@ -1460,43 +1459,43 @@ static void ath_rc_update_ht(struct ath_softc *sc, break; if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { + rate_table->info[rate].rssi_ack_deltamin > + rate_ctrl->state[rate+1].rssi_thres) { rate_ctrl->state[rate+1].rssi_thres = rate_ctrl->state[rate]. - rssi_thres + + rssi_thres + rate_table->info[rate]. - rssi_ack_deltamin; + rssi_ack_deltamin; } } /* Make sure the rates below this have lower rssi thresholds. */ for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { + rate_table->info[rate].rssi_ack_deltamin > + rate_ctrl->state[rate+1].rssi_thres) { if (rate_ctrl->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) + rate_table->info[rate]. + rssi_ack_deltamin) rate_ctrl->state[rate].rssi_thres = 0; else { rate_ctrl->state[rate].rssi_thres = rate_ctrl->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + rssi_thres - + rate_table->info[rate]. + rssi_ack_deltamin; } if (rate_ctrl->state[rate].rssi_thres < - rate_table->info[rate]. - rssi_ack_validmin) { + rate_table->info[rate]. + rssi_ack_validmin) { rate_ctrl->state[rate].rssi_thres = rate_table->info[rate]. - rssi_ack_validmin; + rssi_ack_validmin; } } } @@ -1507,11 +1506,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (rate_ctrl->state[tx_rate].per < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; if (rate_ctrl->state[rate].per > - rate_ctrl->state[rate+1].per) { + rate_ctrl->state[rate+1].per) { rate_ctrl->state[rate].per = rate_ctrl->state[rate+1].per; } @@ -1528,11 +1527,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds and * PER (different for CCK and OFDM). */ if (now_msec - rate_ctrl->rssi_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->rssi_reduce_interval) { for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { if (rate_ctrl->state[rate].rssi_thres > - rate_table->info[rate].rssi_ack_validmin) + rate_table->info[rate].rssi_ack_validmin) rate_ctrl->state[rate].rssi_thres -= 1; } rate_ctrl->rssi_down_time = now_msec; @@ -1541,7 +1540,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - rate_ctrl->per_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->rssi_reduce_interval) { for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { rate_ctrl->state[rate].per = 7 * rate_ctrl->state[rate].per / 8; @@ -1560,7 +1559,7 @@ static void ath_rc_update(struct ath_softc *sc, struct ath_tx_info_priv *info_priv, int final_ts_idx, int xretries, int long_retry) { - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table; struct ath_tx_ratectrl *rate_ctrl; struct ath_rc_series rcs[4]; @@ -1637,7 +1636,6 @@ static void ath_rc_update(struct ath_softc *sc, xretries, long_retry); } - /* * Process a tx descriptor for a completed transmit (success or failure). */ @@ -1651,13 +1649,13 @@ static void ath_rate_tx_complete(struct ath_softc *sc, struct ath_vap *avp; avp = rc_priv->avp; - if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) - || info_priv->tx.ts_status & ATH9K_TXERR_FILT) + if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) || + (info_priv->tx.ts_status & ATH9K_TXERR_FILT)) return; if (info_priv->tx.ts_rssi > 0) { ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, - info_priv->tx.ts_rssi); + info_priv->tx.ts_rssi); } /* @@ -1682,7 +1680,6 @@ static void ath_rate_tx_complete(struct ath_softc *sc, info_priv->tx.ts_longretry); } - /* * Update the SIB's rate control information * @@ -1701,8 +1698,8 @@ static void ath_rc_sib_update(struct ath_softc *sc, struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rateset *rateset = negotiated_rates; u8 *ht_mcs = (u8 *)negotiated_htrates; - struct ath_tx_ratectrl *rate_ctrl = (struct ath_tx_ratectrl *) - (ath_rc_priv); + struct ath_tx_ratectrl *rate_ctrl = + (struct ath_tx_ratectrl *)ath_rc_priv; u8 i, j, k, hi = 0, hthi = 0; rate_table = (struct ath_rate_table *) @@ -1824,7 +1821,8 @@ static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta) struct ath_rate_node *rc_priv = sta->rate_ctrl_priv; int i, j = 0; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < sband->n_bitrates; i++) { if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) { @@ -1962,7 +1960,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; /* lowest rate for management and multicast/broadcast frames */ if (!ieee80211_is_data(fc) || - is_multicast_ether_addr(hdr->addr1) || !sta) { + is_multicast_ether_addr(hdr->addr1) || !sta) { sel->rate_idx = lowest_idx; return; } @@ -1978,7 +1976,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, false); if (is_probe) sel->probe_idx = ((struct ath_tx_ratectrl *) - sta->rate_ctrl_priv)->probe_rate; + sta->rate_ctrl_priv)->probe_rate; /* Ratecontrol sometimes returns invalid rate index */ if (tx_info_priv->rcs[0].rix != 0xff) @@ -2035,6 +2033,7 @@ static void ath_rate_init(void *priv, void *priv_sta, struct ieee80211_hw *hw = local_to_hw(local); struct ieee80211_conf *conf = &local->hw.conf; struct ath_softc *sc = hw->priv; + struct ath_rate_node *ath_rc_priv = priv_sta; int i, j = 0; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); @@ -2046,12 +2045,11 @@ static void ath_rate_init(void *priv, void *priv_sta, if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { for (i = 0; i < MCS_SET_SIZE; i++) { if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) - ((struct ath_rate_node *) - priv_sta)->neg_ht_rates.rs_rates[j++] = i; + ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; } - ((struct ath_rate_node *)priv_sta)->neg_ht_rates.rs_nrates = j; + ath_rc_priv->neg_ht_rates.rs_nrates = j; } ath_rc_node_update(hw, priv_sta); } @@ -2066,7 +2064,7 @@ static void *ath_rate_alloc(struct ieee80211_local *local) struct ieee80211_hw *hw = local_to_hw(local); struct ath_softc *sc = hw->priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); return local->hw.priv; } @@ -2081,14 +2079,17 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp) struct ath_vap *avp = sc->sc_vaps[0]; struct ath_rate_node *rate_priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); if (!rate_priv) { - DPRINTF(sc, ATH_DBG_FATAL, "%s:Unable to allocate" - "private rate control structure", __func__); + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to allocate private rc structure\n", + __func__); return NULL; } ath_rc_sib_init(rate_priv); + return rate_priv; } -- cgit v1.2.3 From ff9b662dab1fcd885fb728de3a8c13ebb5455117 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:27:16 +0530 Subject: ath9k: Miscellaneous fixes This patch removes ath_vap_listen() and dma wrapper macros. Also, Inline abuse is cleaned up and a few typos are fixed. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 52 +++++++++++++------------- drivers/net/wireless/ath9k/core.c | 74 ++----------------------------------- drivers/net/wireless/ath9k/core.h | 6 +-- drivers/net/wireless/ath9k/hw.c | 68 +++++++++++++++++----------------- drivers/net/wireless/ath9k/main.c | 19 ++-------- drivers/net/wireless/ath9k/xmit.c | 29 ++++++--------- 6 files changed, 79 insertions(+), 169 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index a020f9a2154..89e5c65accd 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -114,21 +114,21 @@ static void ath_beacon_setup(struct ath_softc *sc, if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= rt->info[rix].shortPreamble; - ath9k_hw_set11n_txdesc(ah, ds - , skb->len + FCS_LEN /* frame length */ - , ATH9K_PKT_TYPE_BEACON /* Atheros packet type */ - , avp->av_btxctl.txpower /* txpower XXX */ - , ATH9K_TXKEYIX_INVALID /* no encryption */ - , ATH9K_KEY_TYPE_CLEAR /* no encryption */ - , flags /* no ack, veol for beacons */ + ath9k_hw_set11n_txdesc(ah, ds, + skb->len + FCS_LEN, /* frame length */ + ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ + avp->av_btxctl.txpower, /* txpower XXX */ + ATH9K_TXKEYIX_INVALID, /* no encryption */ + ATH9K_KEY_TYPE_CLEAR, /* no encryption */ + flags /* no ack, veol for beacons */ ); /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ath9k_hw_filltxdesc(ah, ds - , roundup(skb->len, 4) /* buffer length */ - , true /* first segment */ - , true /* last segment */ - , ds /* first descriptor */ + ath9k_hw_filltxdesc(ah, ds, + roundup(skb->len, 4), /* buffer length */ + true, /* first segment */ + true, /* last segment */ + ds /* first descriptor */ ); memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); @@ -551,7 +551,7 @@ void ath_beacon_free(struct ath_softc *sc) void ath9k_beacon_tasklet(unsigned long data) { -#define TSF_TO_TU(_h,_l) \ +#define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) struct ath_softc *sc = (struct ath_softc *)data; @@ -898,19 +898,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) "cfp:period %u " "maxdur %u " "next %u " - "timoffset %u\n" - , __func__ - , (unsigned long long)tsf, tsftu - , bs.bs_intval - , bs.bs_nexttbtt - , bs.bs_dtimperiod - , bs.bs_nextdtim - , bs.bs_bmissthreshold - , bs.bs_sleepduration - , bs.bs_cfpperiod - , bs.bs_cfpmaxduration - , bs.bs_cfpnext - , bs.bs_timoffset + "timoffset %u\n", + __func__, + (unsigned long long)tsf, tsftu, + bs.bs_intval, + bs.bs_nexttbtt, + bs.bs_dtimperiod, + bs.bs_nextdtim, + bs.bs_bmissthreshold, + bs.bs_sleepduration, + bs.bs_cfpperiod, + bs.bs_cfpmaxduration, + bs.bs_cfpnext, + bs.bs_timoffset ); ath9k_hw_set_interrupts(ah, 0); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index e3682b6ccfb..57645ee83ef 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -51,10 +51,8 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz) * Set current operating mode * * This function initializes and fills the rate table in the ATH object based - * on the operating mode. The blink rates are also set up here, although - * they have been superceeded by the ath_led module. + * on the operating mode. */ - static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { const struct ath9k_rate_table *rt; @@ -232,7 +230,7 @@ static int ath_setup_channels(struct ath_softc *sc) * Determine mode from channel flags * * This routine will provide the enumerated WIRELESSS_MODE value based - * on the settings of the channel flags. If ho valid set of flags + * on the settings of the channel flags. If no valid set of flags * exist, the lowest mode (11b) is selected. */ @@ -257,7 +255,8 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) else if (chan->chanmode == CHANNEL_G_HT40MINUS) return ATH9K_MODE_11NG_HT40MINUS; - /* NB: should not get here */ + WARN_ON(1); /* should not get here */ + return ATH9K_MODE_11B; } @@ -278,8 +277,6 @@ static int ath_stop(struct ath_softc *sc) /* * Shutdown the hardware and driver: * stop output from above - * reset 802.11 state machine - * (sends station deassoc/deauth frames) * turn off timers * disable interrupts * clear transmit machinery @@ -499,69 +496,6 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) /* VAP management */ /******************/ -/* - * VAP in Listen mode - * - * This routine brings the VAP out of the down state into a "listen" state - * where it waits for association requests. This is used in AP and AdHoc - * modes. -*/ - -int ath_vap_listen(struct ath_softc *sc, int if_id) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - u32 rfilt = 0; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[if_id]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n", - __func__, if_id); - return -EINVAL; - } - -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif - - /* update ratectrl about the new state */ - ath_rate_newstate(sc, avp); - - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - - if (sc->sc_ah->ah_opmode == ATH9K_M_STA || - sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { - memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN); - ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); - } else - sc->sc_curaid = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, print_mac(mac, - sc->sc_curbssid), sc->sc_curaid); - - /* - * XXXX - * Disable BMISS interrupt when we're not associated - */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { - ath9k_hw_set_interrupts(ah, sc->sc_imask & ~ATH9K_INT_BMISS); - sc->sc_imask &= ~ATH9K_INT_BMISS; - } else { - ath9k_hw_set_interrupts( - ah, - sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - } - /* need to reconfigure the beacons when it moves to RUN */ - sc->sc_flags &= ~SC_OP_BEACONS; - - return 0; -} - int ath_vap_attach(struct ath_softc *sc, int if_id, struct ieee80211_vif *if_data, diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 51bf528e4c1..406225ba452 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -82,9 +82,6 @@ struct ath_node; /* XXX: remove */ #define memzero(_buf, _len) memset(_buf, 0, _len) -#define get_dma_mem_context(var, field) (&((var)->field)) -#define copy_dma_mem_context(dst, src) (*dst = *src) - #define ATH9K_BH_STATUS_INTACT 0 #define ATH9K_BH_STATUS_CHANGE 1 @@ -769,8 +766,7 @@ int ath_vap_attach(struct ath_softc *sc, enum ath9k_opmode opmode); int ath_vap_detach(struct ath_softc *sc, int if_id); int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config); -int ath_vap_listen(struct ath_softc *sc, int if_id); + int if_id, struct ath_vap_config *if_config); /*********************/ /* Antenna diversity */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 7d8c908d69d..47c60acac41 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -348,7 +348,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) ah->ah_config.intr_mitigation = 0; } -static inline void ath9k_hw_override_ini(struct ath_hal *ah, +static void ath9k_hw_override_ini(struct ath_hal *ah, struct ath9k_channel *chan) { if (!AR_SREV_5416_V20_OR_LATER(ah) @@ -358,8 +358,8 @@ static inline void ath9k_hw_override_ini(struct ath_hal *ah, REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } -static inline void ath9k_hw_init_bb(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { u32 synthDelay; @@ -374,8 +374,8 @@ static inline void ath9k_hw_init_bb(struct ath_hal *ah, udelay(synthDelay + BASE_ACTIVATE_DELAY); } -static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, + enum ath9k_opmode opmode) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -405,7 +405,7 @@ static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, } } -static inline void ath9k_hw_init_qos(struct ath_hal *ah) +static void ath9k_hw_init_qos(struct ath_hal *ah) { REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); @@ -500,7 +500,7 @@ static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, return ath9k_hw_eeprom_read(ah, off, data); } -static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom *eep = &ahp->ah_eeprom; @@ -767,7 +767,7 @@ ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, return true; } -static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) +static int ath9k_hw_check_eeprom(struct ath_hal *ah) { u32 sum = 0, el; u16 *eepdata; @@ -1272,7 +1272,7 @@ u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, } } -static inline int ath9k_hw_get_radiorev(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { u32 val; int i; @@ -1285,7 +1285,7 @@ static inline int ath9k_hw_get_radiorev(struct ath_hal *ah) return ath9k_hw_reverse_bits(val, 8); } -static inline int ath9k_hw_init_macaddr(struct ath_hal *ah) +static int ath9k_hw_init_macaddr(struct ath_hal *ah) { u32 sum; int i; @@ -1367,7 +1367,7 @@ static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, return spur_val; } -static inline int ath9k_hw_rfattach(struct ath_hal *ah) +static int ath9k_hw_rfattach(struct ath_hal *ah) { bool rfStatus = false; int ecode = 0; @@ -1412,8 +1412,8 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah) return 0; } -static inline void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { u32 pll; @@ -1531,7 +1531,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) } } -static inline void +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { u32 rfMode = 0; @@ -1601,7 +1601,7 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) return true; } -static inline bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) { REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); @@ -1642,7 +1642,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, } } -static inline +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, struct ath9k_channel *chan) { @@ -2076,7 +2076,7 @@ static void ath9k_hw_ani_attach(struct ath_hal *ah) ahp->ah_procPhyErr |= HAL_PROCESS_ANI; } -static inline void ath9k_hw_ani_setup(struct ath_hal *ah) +static void ath9k_hw_ani_setup(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); int i; @@ -2861,7 +2861,7 @@ static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) } } -static inline int ath9k_hw_post_attach(struct ath_hal *ah) +static int ath9k_hw_post_attach(struct ath_hal *ah) { int ecode; @@ -3573,7 +3573,7 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, return true; } -static inline void +static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_data_per_freq *pRawDataSet, @@ -3755,7 +3755,7 @@ ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, return; } -static inline bool +static bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, struct ar5416_eeprom *pEepData, struct ath9k_channel *chan, @@ -3958,7 +3958,7 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) } } -static inline void +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_target_power_leg *powInfo, @@ -4024,7 +4024,7 @@ ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, } } -static inline void +static void ath9k_hw_get_target_powers(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_target_power_ht *powInfo, @@ -4091,7 +4091,7 @@ ath9k_hw_get_target_powers(struct ath_hal *ah, } } -static inline u16 +static u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, bool is2GHz) @@ -4121,7 +4121,7 @@ ath9k_hw_get_max_edge_power(u16 freq, return twiceMaxEdgePower; } -static inline bool +static bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, struct ar5416_eeprom *pEepData, struct ath9k_channel *chan, @@ -5100,7 +5100,7 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static inline void ath9k_hw_init_chain_masks(struct ath_hal *ah) +static void ath9k_hw_init_chain_masks(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); int rx_chainmask, tx_chainmask; @@ -5304,7 +5304,7 @@ bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) } } -static inline void ath9k_hw_init_user_settings(struct ath_hal *ah) +static void ath9k_hw_init_user_settings(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -5323,7 +5323,7 @@ static inline void ath9k_hw_init_user_settings(struct ath_hal *ah) ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); } -static inline int +static int ath9k_hw_process_ini(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -5454,7 +5454,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, return 0; } -static inline void ath9k_hw_setup_calibration(struct ath_hal *ah, +static void ath9k_hw_setup_calibration(struct ath_hal *ah, struct hal_cal_list *currCal) { REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), @@ -5490,8 +5490,8 @@ static inline void ath9k_hw_setup_calibration(struct ath_hal *ah, AR_PHY_TIMING_CTRL4_DO_CAL); } -static inline void ath9k_hw_reset_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +static void ath9k_hw_reset_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) { struct ath_hal_5416 *ahp = AH5416(ah); int i; @@ -5510,7 +5510,7 @@ static inline void ath9k_hw_reset_calibration(struct ath_hal *ah, ahp->ah_CalSamples = 0; } -static inline void +static void ath9k_hw_per_calibration(struct ath_hal *ah, struct ath9k_channel *ichan, u8 rxchainmask, @@ -5600,7 +5600,7 @@ static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, return true; } -static inline bool +static bool ath9k_hw_channel_change(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -5777,8 +5777,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hal *ah, return retval; } -static inline bool ath9k_hw_init_cal(struct ath_hal *ah, - struct ath9k_channel *chan) +static bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_channel *ichan = diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 8fbde897406..605599eb6d3 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -212,12 +212,10 @@ static int ath_key_config(struct ath_softc *sc, static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) { -#define ATH_MAX_NUM_KEYS 4 int freeslot; - freeslot = (key->keyidx >= ATH_MAX_NUM_KEYS) ? 1 : 0; + freeslot = (key->keyidx >= 4) ? 1 : 0; ath_key_reset(sc, key->keyidx, freeslot); -#undef ATH_MAX_NUM_KEYS } static void setup_ht_cap(struct ieee80211_ht_info *ht_info) @@ -620,7 +618,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } if ((conf->changed & IEEE80211_IFCC_BEACON) && - (vif->type == IEEE80211_IF_TYPE_IBSS)) { + ((vif->type == IEEE80211_IF_TYPE_IBSS) || + (vif->type == IEEE80211_IF_TYPE_AP))) { /* * Allocate and setup the beacon frame. * @@ -638,18 +637,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, ath_beacon_sync(sc, 0); } - if ((conf->changed & IEEE80211_IFCC_BEACON) && - (vif->type == IEEE80211_IF_TYPE_AP)) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); - - error = ath_beacon_alloc(sc, 0); - if (error != 0) - return error; - - ath_beacon_config(sc, 0); - sc->sc_flags |= SC_OP_BEACONS; - } - /* Check for WLAN_CAPABILITY_PRIVACY ? */ if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 8d31ad7952b..04f94d2c801 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -499,7 +499,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, { struct sk_buff *skb = bf->bf_mpdu; struct ath_xmit_status tx_status; - dma_addr_t *pa; /* * Set retry information. @@ -519,9 +518,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, tx_status.flags |= ATH_TX_XRETRY; } /* Unmap this frame */ - pa = get_dma_mem_context(bf, bf_dmacontext); pci_unmap_single(sc->pdev, - *pa, + bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); /* complete this frame */ @@ -1172,11 +1170,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, tbf->bf_lastfrm->bf_desc); /* copy the DMA context */ - copy_dma_mem_context( - get_dma_mem_context(tbf, - bf_dmacontext), - get_dma_mem_context(bf_last, - bf_dmacontext)); + tbf->bf_dmacontext = + bf_last->bf_dmacontext; } list_add_tail(&tbf->list, &bf_head); } else { @@ -1185,7 +1180,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * software retry */ ath9k_hw_cleartxdesc(sc->sc_ah, - bf->bf_lastfrm->bf_desc); + bf->bf_lastfrm->bf_desc); } /* @@ -2045,8 +2040,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, /* * Save the DMA context in the first ath_buf */ - copy_dma_mem_context(get_dma_mem_context(bf, bf_dmacontext), - get_dma_mem_context(txctl, dmacontext)); + bf->bf_dmacontext = txctl->dmacontext; /* * Formulate first tx descriptor with tx controls. @@ -2127,25 +2121,26 @@ static int ath_tx_start_dma(struct ath_softc *sc, static void xmit_map_sg(struct ath_softc *sc, struct sk_buff *skb, - dma_addr_t *pa, struct ath_tx_control *txctl) { struct ath_xmit_status tx_status; struct ath_atx_tid *tid; struct scatterlist sg; - *pa = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + txctl->dmacontext = pci_map_single(sc->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); /* setup S/G list */ memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = *pa; + sg_dma_address(&sg) = txctl->dmacontext; sg_dma_len(&sg) = skb->len; if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) { /* * We have to do drop frame here. */ - pci_unmap_single(sc->pdev, *pa, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(sc->pdev, txctl->dmacontext, + skb->len, PCI_DMA_TODEVICE); tx_status.retries = 0; tx_status.flags = ATH_TX_ERROR; @@ -2419,9 +2414,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) * ath_tx_start_dma() will be called either synchronously * or asynchrounsly once DMA is complete. */ - xmit_map_sg(sc, skb, - get_dma_mem_context(&txctl, dmacontext), - &txctl); + xmit_map_sg(sc, skb, &txctl); else ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); -- cgit v1.2.3 From 60653678939dcbba3aa936250b58179aa3451eee Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:28:02 +0530 Subject: ath9k: Use definition from ieee80211.h Also, Max RX-ampdu and mpdu-density are ath9k specific. Rename appropriately. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 605599eb6d3..2b3b11bb564 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -22,8 +22,6 @@ #define ATH_PCI_VERSION "0.1" #define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 -#define IEEE80211_ACTION_CAT_HT 7 -#define IEEE80211_ACTION_HT_TXCHWIDTH 0 static char *dev_info = "ath9k"; @@ -220,11 +218,8 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) static void setup_ht_cap(struct ieee80211_ht_info *ht_info) { -/* Until mac80211 includes these fields */ - -#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 -#define IEEE80211_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define IEEE80211_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ +#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ +#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ ht_info->ht_supported = 1; ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH @@ -232,8 +227,8 @@ static void setup_ht_cap(struct ieee80211_ht_info *ht_info) |(u16)IEEE80211_HT_CAP_SGI_40 |(u16)IEEE80211_HT_CAP_DSSSCCK40; - ht_info->ampdu_factor = IEEE80211_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = IEEE80211_HT_CAP_MPDUDENSITY_8; + ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; + ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; /* setup supported mcs set */ memset(ht_info->supp_mcs_set, 0, 16); ht_info->supp_mcs_set[0] = 0xff; -- cgit v1.2.3 From 19b73c7f68fb2eeb180eafa70f9859409ec9aa08 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:28:20 +0530 Subject: ath9k: Add IEEE80211_HW_RX_INCLUDES_FCS to hw flags Don't trim the FCS before passing the frame to mac80211, move TSF_TO_TU to core.h and delete more unused macros. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 13 ------------- drivers/net/wireless/ath9k/beacon.c | 7 ------- drivers/net/wireless/ath9k/core.h | 11 +++++++---- drivers/net/wireless/ath9k/main.c | 8 +++----- drivers/net/wireless/ath9k/phy.h | 12 ++++++------ drivers/net/wireless/ath9k/recv.c | 2 +- 6 files changed, 17 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 682d3bb4d49..18028a3abc5 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -564,8 +564,6 @@ enum ath9k_cipher { #define CTL_5GHT40 8 #define AR_EEPROM_MAC(i) (0x1d+(i)) -#define EEP_SCALE 100 -#define EEP_DELTA 10 #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 @@ -606,9 +604,6 @@ struct ath9k_country_entry { #define REG_CLR_BIT(_a, _r, _f) \ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) -#define ATH9K_COMP_BUF_MAX_SIZE 9216 -#define ATH9K_COMP_BUF_ALIGN_SIZE 512 - #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 #define INIT_AIFS 2 @@ -637,7 +632,6 @@ struct ath9k_country_entry { IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN)) -#define MAX_REG_ADD_COUNT 129 #define MAX_RATE_POWER 63 enum ath9k_power_mode { @@ -707,13 +701,6 @@ enum phytype { }; #define PHY_CCK PHY_DS -enum start_adhoc_option { - START_ADHOC_NO_11A, - START_ADHOC_PER_11D, - START_ADHOC_IN_11A, - START_ADHOC_IN_11B, -}; - enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, ATH9K_TP_SCALE_50, diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 89e5c65accd..ee1185622ba 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -551,9 +551,6 @@ void ath_beacon_free(struct ath_softc *sc) void ath9k_beacon_tasklet(unsigned long data) { -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - struct ath_softc *sc = (struct ath_softc *)data; struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf = NULL; @@ -715,7 +712,6 @@ void ath9k_beacon_tasklet(unsigned long data) sc->ast_be_xmit += bc; /* XXX per-vap? */ } -#undef TSF_TO_TU } /* @@ -751,8 +747,6 @@ void ath_bstuck_process(struct ath_softc *sc) void ath_beacon_config(struct ath_softc *sc, int if_id) { -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) struct ath_hal *ah = sc->sc_ah; u32 nexttbtt, intval; struct ath_beacon_config conf; @@ -975,7 +969,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } -#undef TSF_TO_TU } /* Function to collect beacon rssi data and resync beacon if necessary */ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 406225ba452..ca7e6135354 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -79,6 +79,9 @@ struct ath_node; } \ } while (0) +#define TSF_TO_TU(_h,_l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) + /* XXX: remove */ #define memzero(_buf, _len) memset(_buf, 0, _len) @@ -382,10 +385,10 @@ int ath_rx_input(struct ath_softc *sc, struct sk_buff *skb, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status); -int ath__rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix); +int _ath_rx_indicate(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_recv_status *status, + u16 keyix); int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, struct ath_recv_status *status); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2b3b11bb564..55f48685b5e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1099,7 +1099,7 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); } -int ath__rx_indicate(struct ath_softc *sc, +int _ath_rx_indicate(struct ath_softc *sc, struct sk_buff *skb, struct ath_recv_status *status, u16 keyix) @@ -1119,9 +1119,6 @@ int ath__rx_indicate(struct ath_softc *sc, skb_pull(skb, padsize); } - /* remove FCS before passing up to protocol stack */ - skb_trim(skb, (skb->len - FCS_LEN)); - /* Prepare rx status */ ath9k_rx_prepare(sc, skb, status, &rx_status); @@ -1364,7 +1361,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad2; } - hw->flags = IEEE80211_HW_SIGNAL_DBM | + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; SET_IEEE80211_DEV(hw, &pdev->dev); diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 0cd399a5344..14702344448 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -18,19 +18,19 @@ #define PHY_H bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah, - struct ath9k_channel - *chan); + struct ath9k_channel + *chan); bool ath9k_hw_set_channel(struct ath_hal *ah, - struct ath9k_channel *chan); + struct ath9k_channel *chan); void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex, int regWrites); bool ath9k_hw_set_rf_regs(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 modesIndex); + struct ath9k_channel *chan, + u16 modesIndex); void ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan); bool ath9k_hw_init_rf(struct ath_hal *ah, - int *status); + int *status); #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 91f635411ab..6e13c638cc0 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -448,7 +448,7 @@ static int ath_rx_indicate(struct ath_softc *sc, int type; /* indicate frame to the stack, which will free the old skb. */ - type = ath__rx_indicate(sc, skb, status, keyix); + type = _ath_rx_indicate(sc, skb, status, keyix); /* allocate a new skb and queue it to for H/W processing */ nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); -- cgit v1.2.3 From 87c8c72d532f96257162f978d5945dcf7f0df19e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 19 Aug 2008 15:15:35 -0400 Subject: libertas: convert CMD_802_11_RF_TX_POWER to a direct command And while we're at it, grab min/max TX power from the firmware and use that to validate incoming TX power requests from WEXT. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 85 +++++++++++++++++++-------------- drivers/net/wireless/libertas/cmd.h | 4 ++ drivers/net/wireless/libertas/cmdresp.c | 19 -------- drivers/net/wireless/libertas/dev.h | 4 +- drivers/net/wireless/libertas/host.h | 10 ---- drivers/net/wireless/libertas/hostcmd.h | 7 ++- drivers/net/wireless/libertas/main.c | 13 +++-- drivers/net/wireless/libertas/wext.c | 83 +++++++++++++++----------------- 8 files changed, 111 insertions(+), 114 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index af5fd709887..c0db988926b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -614,47 +614,67 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) +/** + * @brief Get the min, max, and current TX power + * + * @param priv A pointer to struct lbs_private structure + * @param curlevel Current power level in dBm + * @param minlevel Minimum supported power level in dBm (optional) + * @param maxlevel Maximum supported power level in dBm (optional) + * + * @return 0 on success, error on failure + */ +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel) { - - struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER); - prtp->action = cpu_to_le16(cmd_action); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); + if (ret == 0) { + *curlevel = le16_to_cpu(cmd.curlevel); + if (minlevel) + *minlevel = le16_to_cpu(cmd.minlevel); + if (maxlevel) + *maxlevel = le16_to_cpu(cmd.maxlevel); + } - lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", - le16_to_cpu(cmd->size), le16_to_cpu(cmd->command), - le16_to_cpu(prtp->action)); + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} - switch (cmd_action) { - case CMD_ACT_TX_POWER_OPT_GET: - prtp->action = cpu_to_le16(CMD_ACT_GET); - prtp->currentlevel = 0; - break; +/** + * @brief Set the TX power + * + * @param priv A pointer to struct lbs_private structure + * @param dbm The desired power level in dBm + * + * @return 0 on success, error on failure + */ +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) +{ + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; - case CMD_ACT_TX_POWER_OPT_SET_HIGH: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH); - break; + lbs_deb_enter(LBS_DEB_CMD); - case CMD_ACT_TX_POWER_OPT_SET_MID: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID); - break; + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.curlevel = cpu_to_le16(dbm); - case CMD_ACT_TX_POWER_OPT_SET_LOW: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); - break; - } + lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); lbs_deb_leave(LBS_DEB_CMD); - return 0; + return ret; } static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, @@ -1420,11 +1440,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_RF_TX_POWER: - ret = lbs_cmd_802_11_rf_tx_power(cmdptr, - cmd_action, pdata_buf); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index a53b51f8bdb..6fba8ef7d09 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -61,4 +61,8 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel); +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); + #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 24de3c3cf87..dfaf03a4bbb 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -188,21 +188,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; - - lbs_deb_enter(LBS_DEB_CMD); - - priv->txpowerlevel = le16_to_cpu(rtp->currentlevel); - - lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -287,10 +272,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_snmp_mib(priv, resp); break; - case CMD_RET(CMD_802_11_RF_TX_POWER): - ret = lbs_ret_802_11_rf_tx_power(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f5bb40c54d8..560d4d3db66 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -253,7 +253,9 @@ struct lbs_private { u32 connect_status; u32 mesh_connect_status; u16 regioncode; - u16 txpowerlevel; + s16 txpower_cur; + s16 txpower_min; + s16 txpower_max; /** POWER MANAGEMENT AND PnP SUPPORT */ u8 surpriseremoved; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c92e41b4faf..413030f17d7 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -178,16 +178,6 @@ #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 #define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 -/* Define action or option for CMD_802_11_RF_TX_POWER */ -#define CMD_ACT_TX_POWER_OPT_GET 0x0000 -#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 -#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 -#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 - -#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 -#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 -#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 - /* Define action or option for CMD_802_11_DATA_RATE */ #define CMD_ACT_SET_TX_AUTO 0x0000 #define CMD_ACT_SET_TX_FIX_RATE 0x0001 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 913b480211a..7f155cd1c11 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -435,8 +435,12 @@ struct cmd_ds_802_11_mac_address { }; struct cmd_ds_802_11_rf_tx_power { + struct cmd_header hdr; + __le16 action; - __le16 currentlevel; + __le16 curlevel; + s8 maxlevel; + s8 minlevel; }; struct cmd_ds_802_11_rf_antenna { @@ -701,7 +705,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_snmp_mib smib; - struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_ad_hoc_join adj; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bd32ac0b4e0..3c13619ffa1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -956,17 +956,24 @@ EXPORT_SYMBOL_GPL(lbs_resume); static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; + s16 curlevel = 0, minlevel = 0, maxlevel = 0; lbs_deb_enter(LBS_DEB_FW); - /* - * Read MAC address from HW - */ + /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); if (ret) goto done; + /* Read power levels if available */ + ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); + if (ret == 0) { + priv->txpower_cur = curlevel; + priv->txpower_min = minlevel; + priv->txpower_max = maxlevel; + } + lbs_set_mac_control(priv); done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8b3ed77860b..10a80666600 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -422,26 +422,24 @@ static int lbs_get_txpow(struct net_device *dev, { int ret = 0; struct lbs_private *priv = dev->priv; + s16 curlevel = 0; lbs_deb_enter(LBS_DEB_WEXT); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_GET, - CMD_OPTION_WAITFORRSP, 0, NULL); - + ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); if (ret) goto out; - lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel); - vwrq->value = priv->txpowerlevel; + lbs_deb_wext("tx power level %d dbm\n", curlevel); + + priv->txpower_cur = curlevel; + vwrq->value = curlevel; vwrq->fixed = 1; if (priv->radioon) { vwrq->disabled = 0; vwrq->flags = IW_TXPOW_DBM; - } else { + } else vwrq->disabled = 1; - } out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -693,22 +691,12 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->sensitivity = 0; - /* - * Setup the supported power level ranges - */ + /* Setup the supported power level ranges */ memset(range->txpower, 0, sizeof(range->txpower)); - range->txpower[0] = 5; - range->txpower[1] = 7; - range->txpower[2] = 9; - range->txpower[3] = 11; - range->txpower[4] = 13; - range->txpower[5] = 15; - range->txpower[6] = 17; - range->txpower[7] = 19; - - range->num_txpower = 8; - range->txpower_capa = IW_TXPOW_DBM; - range->txpower_capa |= IW_TXPOW_RANGE; + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = priv->txpower_min; + range->txpower[1] = priv->txpower_max; + range->num_txpower = 2; range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | @@ -1844,39 +1832,46 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, { int ret = 0; struct lbs_private *priv = dev->priv; - - u16 dbm; + s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { lbs_radio_ioctl(priv, RADIO_OFF); - return 0; + goto out; } - priv->preamble = CMD_TYPE_AUTO_PREAMBLE; - - lbs_radio_ioctl(priv, RADIO_ON); + if (vwrq->fixed == 0) { + /* Auto power control */ + priv->preamble = CMD_TYPE_AUTO_PREAMBLE; + dbm = priv->txpower_max; + } else { + /* Userspace check in iwrange if it should use dBm or mW, + * therefore this should never happen... Jean II */ + if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + ret = -EOPNOTSUPP; + goto out; + } - /* Userspace check in iwrange if it should use dBm or mW, - * therefore this should never happen... Jean II */ - if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - return -EOPNOTSUPP; - } else - dbm = (u16) vwrq->value; + /* Validate requested power level against firmware allowed levels */ + if (priv->txpower_min && (dbm < priv->txpower_min)) { + ret = -EINVAL; + goto out; + } - /* auto tx power control */ + if (priv->txpower_max && (dbm > priv->txpower_max)) { + ret = -EINVAL; + goto out; + } + } - if (vwrq->fixed == 0) - dbm = 0xffff; + lbs_radio_ioctl(priv, RADIO_ON); - lbs_deb_wext("txpower set %d dbm\n", dbm); + lbs_deb_wext("txpower set %d dBm\n", dbm); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_SET_LOW, - CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); + ret = lbs_set_tx_power(priv, dbm); +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -- cgit v1.2.3 From 191bb40e725304c5fcfabd92c57eef58799f0e25 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Aug 2008 17:46:18 -0400 Subject: libertas: convert CMD_802_11_DEAUTHENTICATE to a direct command and remove DISASSOCIATE because it's not in any of the specs and has never been used. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 61 ++++++++++++++------------------- drivers/net/wireless/libertas/assoc.h | 5 +-- drivers/net/wireless/libertas/cmd.c | 4 --- drivers/net/wireless/libertas/cmdresp.c | 5 --- drivers/net/wireless/libertas/host.h | 1 - drivers/net/wireless/libertas/hostcmd.h | 11 ++---- drivers/net/wireless/libertas/main.c | 4 ++- drivers/net/wireless/libertas/wext.c | 4 ++- 8 files changed, 36 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a267d6e65f0..5072a8917fd 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1029,7 +1029,9 @@ void lbs_association_worker(struct work_struct *work) */ if (priv->mode == IW_MODE_INFRA) { if (should_deauth_infrastructure(priv, assoc_req)) { - ret = lbs_send_deauthentication(priv); + ret = lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); if (ret) { lbs_deb_assoc("Deauthentication due to new " "configuration request failed: %d\n", @@ -1289,18 +1291,6 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) } } -/** - * @brief Send Deauthentication Request - * - * @param priv A pointer to struct lbs_private structure - * @return 0--success, -1--fail - */ -int lbs_send_deauthentication(struct lbs_private *priv) -{ - return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); -} - /** * @brief This function prepares command of authenticate. * @@ -1353,26 +1343,37 @@ out: return ret; } -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd) +/** + * @brief Deauthenticate from a specific BSS + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The specific BSS to deauthenticate from + * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating + * + * @return 0 on success, error on failure + */ +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], + u16 reason) { - struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + struct cmd_ds_802_11_deauthenticate cmd; + int ret; lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + - S_DS_GEN); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.macaddr, &bssid[0], ETH_ALEN); + cmd.reasoncode = cpu_to_le16(reason); - /* set AP MAC address */ - memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); - /* Reason code 3 = Station is leaving */ -#define REASON_CODE_STA_LEAVING 3 - dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); + /* Clean up everything even if there was an error; can't assume that + * we're still authenticated to the AP after trying to deauth. + */ + lbs_mac_event_disconnected(priv); lbs_deb_leave(LBS_DEB_JOIN); - return 0; + return ret; } int lbs_cmd_80211_associate(struct lbs_private *priv, @@ -1815,16 +1816,6 @@ done: return ret; } -int lbs_ret_80211_disassociate(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} - int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp) { diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index c516fbe518f..92ba2c2b3ee 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -20,7 +20,7 @@ int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd); + u8 bssid[ETH_ALEN], u16 reason); int lbs_cmd_80211_associate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); @@ -28,12 +28,9 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); -int lbs_ret_80211_disassociate(struct lbs_private *priv); int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); int lbs_stop_adhoc_network(struct lbs_private *priv); -int lbs_send_deauthentication(struct lbs_private *priv); - #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c0db988926b..8364a2f71b5 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1413,10 +1413,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_DEAUTHENTICATE: - ret = lbs_cmd_80211_deauthenticate(priv, cmdptr); - break; - case CMD_802_11_AD_HOC_START: ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index dfaf03a4bbb..c94604c536f 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -258,11 +258,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_DISASSOCIATE): - case CMD_RET(CMD_802_11_DEAUTHENTICATE): - ret = lbs_ret_80211_disassociate(priv); - break; - case CMD_RET(CMD_802_11_AD_HOC_START): case CMD_RET(CMD_802_11_AD_HOC_JOIN): ret = lbs_ret_80211_ad_hoc_start(priv, resp); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 413030f17d7..caebb9b5715 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -61,7 +61,6 @@ #define CMD_RF_REG_MAP 0x0023 #define CMD_802_11_DEAUTHENTICATE 0x0024 #define CMD_802_11_REASSOCIATE 0x0025 -#define CMD_802_11_DISASSOCIATE 0x0026 #define CMD_MAC_CONTROL 0x0028 #define CMD_802_11_AD_HOC_START 0x002b #define CMD_802_11_AD_HOC_JOIN 0x002c diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 7f155cd1c11..342c2e3af34 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -232,7 +232,9 @@ struct cmd_ds_802_11_authenticate { }; struct cmd_ds_802_11_deauthenticate { - u8 macaddr[6]; + struct cmd_header hdr; + + u8 macaddr[ETH_ALEN]; __le16 reasoncode; }; @@ -251,11 +253,6 @@ struct cmd_ds_802_11_associate { #endif } __attribute__ ((packed)); -struct cmd_ds_802_11_disassociate { - u8 destmacaddr[6]; - __le16 reasoncode; -}; - struct cmd_ds_802_11_associate_rsp { struct ieeetypes_assocrsp assocRsp; }; @@ -697,7 +694,6 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_deauthenticate deauth; struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; struct cmd_ds_802_11_ad_hoc_result result; @@ -710,7 +706,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; - struct cmd_ds_802_11_disassociate dassociate; struct cmd_ds_mac_reg_access macreg; struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_rf_reg_access rfreg; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 3c13619ffa1..5e4c4e41098 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -291,7 +291,9 @@ static ssize_t lbs_rtap_set(struct device *dev, if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); lbs_add_rtap(priv); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 10a80666600..38295ee1a05 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -986,7 +986,9 @@ static int lbs_mesh_set_freq(struct net_device *dev, if (fwrq->m != priv->curbssparams.channel) { lbs_deb_wext("mesh channel change forces eth disconnect\n"); if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); } -- cgit v1.2.3 From d5db2dfa660de13c3643149b89c7602dd49aa168 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Aug 2008 17:51:07 -0400 Subject: libertas: convert CMD_802_11_RADIO_CONTROL to a direct command and return errors for operations like join & scan that aren't possible when the radio is turned off. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 57 ++++++++++++++++------------- drivers/net/wireless/libertas/cmd.c | 46 +++++++++++++---------- drivers/net/wireless/libertas/cmd.h | 2 + drivers/net/wireless/libertas/decl.h | 1 - drivers/net/wireless/libertas/dev.h | 3 +- drivers/net/wireless/libertas/host.h | 15 ++------ drivers/net/wireless/libertas/main.c | 2 +- drivers/net/wireless/libertas/scan.c | 5 +++ drivers/net/wireless/libertas/wext.c | 69 ++++++++++++++++------------------- 9 files changed, 100 insertions(+), 100 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5072a8917fd..d47e4d5734c 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -25,7 +25,7 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = * @brief Associate to a specific BSS discovered in a scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to the BSS descriptor to associate with. + * @param assoc_req The association request describing the BSS to associate with * * @return 0-success, otherwise fail */ @@ -33,29 +33,29 @@ static int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; + u8 preamble = RADIO_PREAMBLE_LONG; lbs_deb_enter(LBS_DEB_ASSOC); ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); - if (ret) - goto done; + goto out; - /* set preamble to firmware */ + /* Use short preamble only when both the BSS and firmware support it */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - else - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); -done: +out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -64,8 +64,7 @@ done: * @brief Join an adhoc network found in a previous scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to a BSS descriptor found in a previous scan - * to attempt to join + * @param assoc_req The association request describing the BSS to join * * @return 0--success, -1--fail */ @@ -74,6 +73,9 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, { struct bss_descriptor *bss = &assoc_req->bss; int ret = 0; + u8 preamble = RADIO_PREAMBLE_LONG; + + lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_join("current SSID '%s', ssid length %u\n", escape_essid(priv->curbssparams.ssid, @@ -106,18 +108,16 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, goto out; } - /* Use shortpreamble only when both creator and card supports - short preamble */ - if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || - !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { - lbs_deb_join("AdhocJoin: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; - } else { + /* Use short preamble only when both the BSS and firmware support it */ + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; } - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); @@ -129,6 +129,7 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, OID_802_11_SSID, assoc_req); out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -136,25 +137,27 @@ out: * @brief Start an Adhoc Network * * @param priv A pointer to struct lbs_private structure - * @param adhocssid The ssid of the Adhoc Network + * @param assoc_req The association request describing the BSS to start * @return 0--success, -1--fail */ static int lbs_start_adhoc_network(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret = 0; + u8 preamble = RADIO_PREAMBLE_LONG; + + lbs_deb_enter(LBS_DEB_ASSOC); priv->adhoccreate = 1; if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - } else { - lbs_deb_join("AdhocStart: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; } - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); @@ -162,6 +165,8 @@ static int lbs_start_adhoc_network(struct lbs_private *priv, ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); +out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8364a2f71b5..f3073a5a954 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1289,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, priv->cur_cmd = NULL; } -int lbs_set_radio_control(struct lbs_private *priv) +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) { - int ret = 0; struct cmd_ds_802_11_radio_control cmd; + int ret = -EINVAL; lbs_deb_enter(LBS_DEB_CMD); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); - switch (priv->preamble) { - case CMD_TYPE_SHORT_PREAMBLE: - cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); - break; - - case CMD_TYPE_LONG_PREAMBLE: - cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); - break; + /* Only v8 and below support setting the preamble */ + if (priv->fwrelease < 0x09000000) { + switch (preamble) { + case RADIO_PREAMBLE_SHORT: + if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + goto out; + /* Fall through */ + case RADIO_PREAMBLE_AUTO: + case RADIO_PREAMBLE_LONG: + cmd.control = cpu_to_le16(preamble); + break; + default: + goto out; + } + } - case CMD_TYPE_AUTO_PREAMBLE: - default: - cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); - break; + if (radio_on) + cmd.control |= cpu_to_le16(0x1); + else { + cmd.control &= cpu_to_le16(~0x1); + priv->txpower_cur = 0; } - if (priv->radioon) - cmd.control |= cpu_to_le16(TURN_ON_RF); - else - cmd.control &= cpu_to_le16(~TURN_ON_RF); + lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n", + radio_on ? "ON" : "OFF", preamble); - lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon, - priv->preamble); + priv->radio_on = radio_on; ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); +out: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 6fba8ef7d09..11ac996e895 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -65,4 +65,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, s16 *maxlevel); int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); + #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index a8ac974daca..1a8888ccead 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); -int lbs_set_radio_control(struct lbs_private *priv); u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 560d4d3db66..fd59e181646 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -293,8 +293,7 @@ struct lbs_private { u16 nextSNRNF; u16 numSNRNF; - u8 radioon; - u32 preamble; + u8 radio_on; /** data rate stuff */ u8 cur_rate; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index caebb9b5715..da618fc997c 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -152,11 +152,6 @@ #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 #define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 -/* Define action or option for CMD_802_11_RADIO_CONTROL */ -#define CMD_TYPE_AUTO_PREAMBLE 0x0001 -#define CMD_TYPE_SHORT_PREAMBLE 0x0002 -#define CMD_TYPE_LONG_PREAMBLE 0x0003 - /* Event flags for CMD_802_11_SUBSCRIBE_EVENT */ #define CMD_SUBSCRIBE_RSSI_LOW 0x0001 #define CMD_SUBSCRIBE_SNR_LOW 0x0002 @@ -165,13 +160,9 @@ #define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 #define CMD_SUBSCRIBE_SNR_HIGH 0x0020 -#define TURN_ON_RF 0x01 -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - -#define SET_AUTO_PREAMBLE 0x05 -#define SET_SHORT_PREAMBLE 0x03 -#define SET_LONG_PREAMBLE 0x01 +#define RADIO_PREAMBLE_LONG 0x00 +#define RADIO_PREAMBLE_SHORT 0x02 +#define RADIO_PREAMBLE_AUTO 0x04 /* Define action or option for CMD_802_11_RF_CHANNEL */ #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 5e4c4e41098..dafe62e9d3e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1051,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - priv->radioon = RADIO_ON; + priv->radio_on = 1; priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 4b274562f96..8f66903641b 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + if (!netif_running(dev)) { ret = -ENETDOWN; goto out; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 38295ee1a05..4307090f4ef 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -120,34 +120,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( return cfp; } - -/** - * @brief Set Radio On/OFF - * - * @param priv A pointer to struct lbs_private structure - * @option Radio Option - * @return 0 --success, otherwise fail - */ -static int lbs_radio_ioctl(struct lbs_private *priv, u8 option) -{ - int ret = 0; - - lbs_deb_enter(LBS_DEB_WEXT); - - if (priv->radioon != option) { - lbs_deb_wext("switching radio %s\n", option ? "on" : "off"); - priv->radioon = option; - - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RADIO_CONTROL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); - } - - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; -} - /** * @brief Copy active data rates based on adapter mode and status * @@ -420,26 +392,30 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; s16 curlevel = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + lbs_deb_wext("tx power off\n"); + vwrq->value = 0; + vwrq->disabled = 1; + goto out; + } + ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); if (ret) goto out; lbs_deb_wext("tx power level %d dbm\n", curlevel); - priv->txpower_cur = curlevel; + vwrq->value = curlevel; vwrq->fixed = 1; - if (priv->radioon) { - vwrq->disabled = 0; - vwrq->flags = IW_TXPOW_DBM; - } else - vwrq->disabled = 1; + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1839,13 +1815,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - lbs_radio_ioctl(priv, RADIO_OFF); + lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); goto out; } if (vwrq->fixed == 0) { /* Auto power control */ - priv->preamble = CMD_TYPE_AUTO_PREAMBLE; dbm = priv->txpower_max; } else { /* Userspace check in iwrange if it should use dBm or mW, @@ -1867,7 +1842,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, } } - lbs_radio_ioctl(priv, RADIO_ON); + /* If the radio was off, turn it on */ + if (!priv->radio_on) { + ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1); + if (ret) + goto out; + } lbs_deb_wext("txpower set %d dBm\n", dbm); @@ -1925,6 +1905,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (in_ssid_len > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2002,6 +1987,11 @@ static int lbs_mesh_set_essid(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (dwrq->length > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2043,6 +2033,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) + return -EINVAL; + if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; -- cgit v1.2.3 From f5fe1fdaae86a74d6977fafd8fdd8697e398dafd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Aug 2008 21:46:59 -0400 Subject: libertas: convert adhoc operations to direct commands with fixes for v9 and later firmware too. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 632 ++++++++++++++------------------ drivers/net/wireless/libertas/assoc.h | 13 +- drivers/net/wireless/libertas/cmd.c | 12 - drivers/net/wireless/libertas/cmdresp.c | 9 - drivers/net/wireless/libertas/hostcmd.h | 32 +- drivers/net/wireless/libertas/main.c | 2 +- drivers/net/wireless/libertas/wext.c | 2 +- 7 files changed, 302 insertions(+), 400 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index d47e4d5734c..4ddf44b2758 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -8,6 +8,7 @@ #include "scan.h" #include "cmd.h" +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -20,6 +21,82 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = #define CAPINFO_MASK (~(0xda00)) +/** + * @brief This function finds common rates between rates and card rates. + * + * It will fill common rates in rates as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param priv A pointer to struct lbs_private structure + * @param rates the buffer which keeps input and output + * @param rates_size the size of rate1 buffer; new size of buffer on return + * + * @return 0 on success, or -1 on error + */ +static int get_common_rates(struct lbs_private *priv, + u8 *rates, + u16 *rates_size) +{ + u8 *card_rates = lbs_bg_rates; + size_t num_card_rates = sizeof(lbs_bg_rates); + int ret = 0, i, j; + u8 tmp[30]; + size_t tmp_size = 0; + + /* For each rate in card_rates that exists in rate1, copy to tmp */ + for (i = 0; card_rates[i] && (i < num_card_rates); i++) { + for (j = 0; rates[j] && (j < *rates_size); j++) { + if (rates[j] == card_rates[i]) + tmp[tmp_size++] = card_rates[i]; + } + } + + lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + + if (!priv->enablehwauto) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == priv->cur_rate) + goto done; + } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + ret = -1; + goto done; + } + ret = 0; + +done: + memset(rates, 0, *rates_size); + *rates_size = min_t(int, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + return ret; +} + + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void lbs_set_basic_rate_flags(u8 *rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + /** * @brief Associate to a specific BSS discovered in a scan @@ -66,14 +143,17 @@ out: * @param priv A pointer to struct lbs_private structure * @param assoc_req The association request describing the BSS to join * - * @return 0--success, -1--fail + * @return 0 on success, error on failure */ -static int lbs_join_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_join(struct lbs_private *priv, struct assoc_request *assoc_req) { + struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; - int ret = 0; u8 preamble = RADIO_PREAMBLE_LONG; + DECLARE_MAC_BUF(mac); + u16 ratesize = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); @@ -123,10 +203,88 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); priv->adhoccreate = 0; + priv->curbssparams.channel = bss->channel; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_SSID, assoc_req); + /* Build the join command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.bss.type = CMD_BSS_TYPE_IBSS; + cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod); + + memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); + + memcpy(&cmd.bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); + + memcpy(&cmd.bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + + cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); + lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + bss->capability, CAPINFO_MASK); + + /* information on BSSID descriptor passed to FW */ + lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, cmd.bss.bssid), cmd.bss.ssid); + + /* Only v8 and below support setting these */ + if (priv->fwrelease < 0x09000000) { + /* failtimeout */ + cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + /* probedelay */ + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + } + + /* Copy Data rates from the rates recorded in scan response */ + memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); + ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + memcpy(cmd.bss.rates, bss->rates, ratesize); + if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { + lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); + ret = -1; + goto out; + } + + /* Copy the ad-hoc creation rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); + + cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + + if (assoc_req->secinfo.wep_enabled) { + u16 tmp = le16_to_cpu(cmd.bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + cmd.bss.capability = cpu_to_le16(tmp); + } + + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM); + + /* wake up first */ + ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_ACT_SET, 0, 0, + &local_ps_mode); + if (ret) { + ret = -1; + goto out; + } + } + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto out; + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -138,20 +296,22 @@ out: * * @param priv A pointer to struct lbs_private structure * @param assoc_req The association request describing the BSS to start - * @return 0--success, -1--fail + * + * @return 0 on success, error on failure */ -static int lbs_start_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_start(struct lbs_private *priv, struct assoc_request *assoc_req) { - int ret = 0; + struct cmd_ds_802_11_ad_hoc_start cmd; u8 preamble = RADIO_PREAMBLE_LONG; + size_t ratesize = 0; + u16 tmpcap = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); - priv->adhoccreate = 1; - if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { - lbs_deb_join("AdhocStart: Short preamble\n"); + lbs_deb_join("ADHOC_START: Will use short preamble\n"); preamble = RADIO_PREAMBLE_SHORT; } @@ -159,21 +319,107 @@ static int lbs_start_adhoc_network(struct lbs_private *priv, if (ret) goto out; - lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); - lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); + /* Build the start command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); + + lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->ssid_len); + + cmd.bsstype = CMD_BSS_TYPE_IBSS; + + if (priv->beacon_period == 0) + priv->beacon_period = MRVDRV_BEACON_INTERVAL; + cmd.beaconperiod = cpu_to_le16(priv->beacon_period); + + WARN_ON(!assoc_req->channel); + + /* set Physical parameter set */ + cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.len = 1; + cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + + /* set IBSS parameter set */ + cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET; + cmd.ssparamset.ibssparamset.len = 2; + cmd.ssparamset.ibssparamset.atimwindow = 0; + + /* set capability info */ + tmpcap = WLAN_CAPABILITY_IBSS; + if (assoc_req->secinfo.wep_enabled) { + lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + tmpcap |= WLAN_CAPABILITY_PRIVACY; + } else + lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + + cmd.capability = cpu_to_le16(tmpcap); + + /* Only v8 and below support setting probe delay */ + if (priv->fwrelease < 0x09000000) + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + + ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates)); + memcpy(cmd.rates, lbs_bg_rates, ratesize); + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.rates, ratesize); + + lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", + cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); + + if (lbs_create_dnld_countryinfo_11d(priv)) { + lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n"); + ret = -1; + goto out; + } + + lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", + assoc_req->channel, assoc_req->band); + + priv->adhoccreate = 1; + priv->mode = IW_MODE_ADHOC; + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -int lbs_stop_adhoc_network(struct lbs_private *priv) +/** + * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode + * + * @param priv A pointer to struct lbs_private structure + * @return 0 on success, or an error + */ +int lbs_adhoc_stop(struct lbs_private *priv) { - return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); + struct cmd_ds_802_11_ad_hoc_stop cmd; + int ret; + + lbs_deb_enter(LBS_DEB_JOIN); + + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16 (sizeof (cmd)); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); + + /* Clean up everything even if there was an error */ + lbs_mac_event_disconnected(priv); + + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, @@ -485,14 +731,14 @@ static int assoc_helper_essid(struct lbs_private *priv, if (bss != NULL) { lbs_deb_assoc("SSID found, will join\n"); memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } else { /* else send START command */ lbs_deb_assoc("SSID not found, creating adhoc network\n"); memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, IW_ESSID_MAX_SIZE); assoc_req->bss.ssid_len = assoc_req->ssid_len; - lbs_start_adhoc_network(priv, assoc_req); + lbs_adhoc_start(priv, assoc_req); } } @@ -525,7 +771,7 @@ static int assoc_helper_bssid(struct lbs_private *priv, ret = lbs_associate(priv, assoc_req); lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } out: @@ -1045,7 +1291,7 @@ void lbs_association_worker(struct work_struct *work) } } else if (priv->mode == IW_MODE_ADHOC) { if (should_stop_adhoc(priv, assoc_req)) { - ret = lbs_stop_adhoc_network(priv); + ret = lbs_adhoc_stop(priv); if (ret) { lbs_deb_assoc("Teardown of AdHoc network due to " "new configuration request failed: %d\n", @@ -1220,82 +1466,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) } -/** - * @brief This function finds common rates between rate1 and card rates. - * - * It will fill common rates in rate1 as output if found. - * - * NOTE: Setting the MSB of the basic rates need to be taken - * care, either before or after calling this function - * - * @param priv A pointer to struct lbs_private structure - * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer; new size of buffer on return - * - * @return 0 or -1 - */ -static int get_common_rates(struct lbs_private *priv, - u8 *rates, - u16 *rates_size) -{ - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; - u8 tmp[30]; - size_t tmp_size = 0; - - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; - } - } - - lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); - lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - - if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - goto done; - } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; - } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - return ret; -} - - -/** - * @brief Sets the MSB on basic rates as the firmware requires - * - * Scan through an array and set the MSB for basic data rates. - * - * @param rates buffer of data rates - * @param len size of buffer - */ -static void lbs_set_basic_rate_flags(u8 *rates, size_t len) -{ - int i; - - for (i = 0; i < len; i++) { - if (rates[i] == 0x02 || rates[i] == 0x04 || - rates[i] == 0x0b || rates[i] == 0x16) - rates[i] |= 0x80; - } -} - /** * @brief This function prepares command of authenticate. * @@ -1495,231 +1665,6 @@ done: return ret; } -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; - int ret = 0; - int cmdappendsize = 0; - struct assoc_request *assoc_req = pdata_buf; - u16 tmpcap = 0; - size_t ratesize = 0; - - lbs_deb_enter(LBS_DEB_JOIN); - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); - - /* - * Fill in the parameters for 2 data structures: - * 1. cmd_ds_802_11_ad_hoc_start command - * 2. priv->scantable[i] - * - * Driver will fill up SSID, bsstype,IBSS param, Physical Param, - * probe delay, and cap info. - * - * Firmware will fill up beacon period, DTIM, Basic rates - * and operational rates. - */ - - memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); - - lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), - assoc_req->ssid_len); - - /* set the BSS type */ - adhs->bsstype = CMD_BSS_TYPE_IBSS; - priv->mode = IW_MODE_ADHOC; - if (priv->beacon_period == 0) - priv->beacon_period = MRVDRV_BEACON_INTERVAL; - adhs->beaconperiod = cpu_to_le16(priv->beacon_period); - - /* set Physical param set */ -#define DS_PARA_IE_ID 3 -#define DS_PARA_IE_LEN 1 - - adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; - adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; - - WARN_ON(!assoc_req->channel); - - lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n", - assoc_req->channel); - - adhs->phyparamset.dsparamset.currentchan = assoc_req->channel; - - /* set IBSS param set */ -#define IBSS_PARA_IE_ID 6 -#define IBSS_PARA_IE_LEN 2 - - adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; - adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = 0; - - /* set capability info */ - tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_S_CMD: WEP enabled, " - "setting privacy on\n"); - tmpcap |= WLAN_CAPABILITY_PRIVACY; - } else { - lbs_deb_join("ADHOC_S_CMD: WEP disabled, " - "setting privacy off\n"); - } - adhs->capability = cpu_to_le16(tmpcap); - - /* probedelay */ - adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); - memcpy(adhs->rates, lbs_bg_rates, ratesize); - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(adhs->rates, ratesize); - - lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); - - lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); - - if (lbs_create_dnld_countryinfo_11d(priv)) { - lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + - S_DS_GEN + cmdappendsize); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); - cmd->size = cpu_to_le16(S_DS_GEN); - - return 0; -} - -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - int cmdappendsize = 0; - int ret = 0; - u16 ratesize = 0; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - - join_cmd->bss.type = CMD_BSS_TYPE_IBSS; - join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - - memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); - memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - - memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); - - memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); - - join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); - lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - bss->capability, CAPINFO_MASK); - - /* information on BSSID descriptor passed to FW */ - lbs_deb_join( - "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, join_cmd->bss.bssid), - join_cmd->bss.ssid); - - /* failtimeout */ - join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); - - /* probedelay */ - join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - priv->curbssparams.channel = bss->channel; - - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); - ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); - memcpy(join_cmd->bss.rates, bss->rates, ratesize); - if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { - lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); - ret = -1; - goto done; - } - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); - - join_cmd->bss.ssparamset.ibssparamset.atimwindow = - cpu_to_le16(bss->atimwindow); - - if (assoc_req->secinfo.wep_enabled) { - u16 tmp = le16_to_cpu(join_cmd->bss.capability); - tmp |= WLAN_CAPABILITY_PRIVACY; - join_cmd->bss.capability = cpu_to_le16(tmp); - } - - if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { - /* wake up first */ - __le32 Localpsmode; - - Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_PS_MODE, - CMD_ACT_SET, - 0, 0, &Localpsmode); - - if (ret) { - ret = -1; - goto done; - } - } - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + - S_DS_GEN + cmdappendsize); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -1821,24 +1766,19 @@ done: return ret; } -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp) +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) { int ret = 0; u16 command = le16_to_cpu(resp->command); u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *padhocresult; + struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); - padhocresult = &resp->params.result; - - lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size)); - lbs_deb_join("ADHOC_RESP: command = %x\n", command); - lbs_deb_join("ADHOC_RESP: result = %x\n", result); + adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; if (!priv->in_progress_assoc_req) { lbs_deb_join("ADHOC_RESP: no in-progress association " @@ -1852,26 +1792,19 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, * Join result code 0 --> SUCCESS */ if (result) { - lbs_deb_join("ADHOC_RESP: failed\n"); + lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); if (priv->connect_status == LBS_CONNECTED) lbs_mac_event_disconnected(priv); ret = -1; goto done; } - /* - * Now the join cmd should be successful - * If BSSID has changed use SSID to compare instead of BSSID - */ - lbs_deb_join("ADHOC_RESP: associated to '%s'\n", - escape_essid(bss->ssid, bss->ssid_len)); - /* Send a Media Connected event, according to the Spec */ priv->connect_status = LBS_CONNECTED; if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); + memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); } /* Set the BSSID from the joined/started descriptor */ @@ -1890,22 +1823,13 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = %s\n", - print_mac(mac, padhocresult->bssid)); + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", + escape_essid(bss->ssid, bss->ssid_len), + print_mac(mac, priv->curbssparams.bssid), + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); return ret; } -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 92ba2c2b3ee..8b7336dd02a 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -12,13 +12,9 @@ struct cmd_ds_command; int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd); -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); + +int lbs_adhoc_stop(struct lbs_private *priv); + int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], u16 reason); int lbs_cmd_80211_associate(struct lbs_private *priv, @@ -27,10 +23,7 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_stop_adhoc_network(struct lbs_private *priv); - #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index f3073a5a954..802547e7967 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1419,10 +1419,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_AD_HOC_START: - ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RESET: ret = lbs_cmd_802_11_reset(cmdptr, cmd_action); break; @@ -1447,18 +1443,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmd_action, pdata_buf); break; - case CMD_802_11_AD_HOC_JOIN: - ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RSSI: ret = lbs_cmd_802_11_rssi(priv, cmdptr); break; - case CMD_802_11_AD_HOC_STOP: - ret = lbs_cmd_80211_ad_hoc_stop(cmdptr); - break; - case CMD_802_11_SET_AFC: case CMD_802_11_GET_AFC: diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index c94604c536f..0371c83f566 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -258,11 +258,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_AD_HOC_START): - case CMD_RET(CMD_802_11_AD_HOC_JOIN): - ret = lbs_ret_80211_ad_hoc_start(priv, resp); - break; - case CMD_RET(CMD_802_11_SNMP_MIB): ret = lbs_ret_802_11_snmp_mib(priv, resp); break; @@ -285,10 +280,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_rssi(priv, resp); break; - case CMD_RET(CMD_802_11_AD_HOC_STOP): - ret = lbs_ret_80211_ad_hoc_stop(priv); - break; - case CMD_RET(CMD_802_11D_DOMAIN_INFO): ret = lbs_ret_802_11d_domain_info(resp); break; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 342c2e3af34..d27c276b219 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -257,11 +257,6 @@ struct cmd_ds_802_11_associate_rsp { struct ieeetypes_assocrsp assocRsp; }; -struct cmd_ds_802_11_ad_hoc_result { - u8 pad[3]; - u8 bssid[ETH_ALEN]; -}; - struct cmd_ds_802_11_set_wep { struct cmd_header hdr; @@ -508,10 +503,12 @@ struct cmd_ds_802_11_rate_adapt_rateset { }; struct cmd_ds_802_11_ad_hoc_start { + struct cmd_header hdr; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 bsstype; __le16 beaconperiod; - u8 dtimperiod; + u8 dtimperiod; /* Reserved on v9 and later */ union IEEEtypes_ssparamset ssparamset; union ieeetypes_phyparamset phyparamset; __le16 probedelay; @@ -520,9 +517,16 @@ struct cmd_ds_802_11_ad_hoc_start { u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_result { + struct cmd_header hdr; + + u8 pad[3]; + u8 bssid[ETH_ALEN]; +}; + struct adhoc_bssdesc { - u8 bssid[6]; - u8 ssid[32]; + u8 bssid[ETH_ALEN]; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 type; __le16 beaconperiod; u8 dtimperiod; @@ -540,10 +544,15 @@ struct adhoc_bssdesc { } __attribute__ ((packed)); struct cmd_ds_802_11_ad_hoc_join { + struct cmd_header hdr; + struct adhoc_bssdesc bss; - __le16 failtimeout; - __le16 probedelay; + __le16 failtimeout; /* Reserved on v9 and later */ + __le16 probedelay; /* Reserved on v9 and later */ +} __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_stop { + struct cmd_header hdr; } __attribute__ ((packed)); struct cmd_ds_802_11_enable_rsn { @@ -694,16 +703,13 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; - struct cmd_ds_802_11_ad_hoc_result result; struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_snmp_mib smib; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; struct cmd_ds_mac_reg_access macreg; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index dafe62e9d3e..2436634b6b7 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -295,7 +295,7 @@ static ssize_t lbs_rtap_set(struct device *dev, priv->curbssparams.bssid, WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); lbs_add_rtap(priv); } priv->monitormode = monitor_mode; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 4307090f4ef..426f1fe3bb4 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -966,7 +966,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, priv->curbssparams.bssid, WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); } lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); -- cgit v1.2.3 From 87e8b64e6856a41c5204a22c47cc14b1b0b57332 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 21 Aug 2008 21:45:56 +0300 Subject: mac80211_hwsim: Add minimal IEEE 802.11n support Set some semi-random values for HT and add more queues to allow IEEE 802.11n association to be tested with mac80211_hwsim. This with the latest hostapd git tree version can complete a simulated 802.11n association successfully (with mac80211 client MLME). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 248d31a7aa3..732429d4912 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -446,7 +446,8 @@ static int __init init_mac80211_hwsim(void) SET_IEEE80211_PERM_ADDR(hw, addr); hw->channel_change_time = 1; - hw->queues = 1; + hw->queues = 4; + hw->ampdu_queues = 1; memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); @@ -454,6 +455,19 @@ static int __init init_mac80211_hwsim(void) data->band.n_channels = ARRAY_SIZE(hwsim_channels); data->band.bitrates = data->rates; data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); + data->band.ht_info.ht_supported = 1; + data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + data->band.ht_info.ampdu_factor = 0x3; + data->band.ht_info.ampdu_density = 0x6; + memset(data->band.ht_info.supp_mcs_set, 0, + sizeof(data->band.ht_info.supp_mcs_set)); + data->band.ht_info.supp_mcs_set[0] = 0xff; + data->band.ht_info.supp_mcs_set[1] = 0xff; + data->band.ht_info.supp_mcs_set[12] = + IEEE80211_HT_CAP_MCS_TX_DEFINED; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; err = ieee80211_register_hw(hw); -- cgit v1.2.3 From e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 22 Aug 2008 17:31:33 +0300 Subject: ath9k: Use mac80211 for multicast power save buffering Replace the internal ath9k implementation of multicast/broadcast frame power save buffering (AP mode) in ath9k with use of mac80211 ieee80211_get_buffered_bc() mechanism. This removes quite a bit of duplicated functionality and simplifies the driver part. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 1 + drivers/net/wireless/ath9k/beacon.c | 75 ++-------------- drivers/net/wireless/ath9k/core.c | 6 -- drivers/net/wireless/ath9k/core.h | 9 +- drivers/net/wireless/ath9k/main.c | 1 + drivers/net/wireless/ath9k/xmit.c | 173 +++++++++++++++--------------------- 6 files changed, 82 insertions(+), 183 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 18028a3abc5..841893b0b4d 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -144,6 +144,7 @@ struct ath_desc { #define ATH9K_TXDESC_EXT_AND_CTL 0x0080 #define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 +#define ATH9K_TXDESC_CAB 0x0400 #define ATH9K_RXDESC_INTREQ 0x0020 diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index ee1185622ba..fdbabc18022 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -140,56 +140,6 @@ static void ath_beacon_setup(struct ath_softc *sc, ctsrate, ctsduration, series, 4, 0); } -/* Move everything from the vap's mcast queue to the hardware cab queue. - * Caller must hold mcasq lock and cabq lock - * XXX MORE_DATA bit? - */ -static void empty_mcastq_into_cabq(struct ath_hal *ah, - struct ath_txq *mcastq, struct ath_txq *cabq) -{ - struct ath_buf *bfmcast; - - BUG_ON(list_empty(&mcastq->axq_q)); - - bfmcast = list_first_entry(&mcastq->axq_q, struct ath_buf, list); - - /* link the descriptors */ - if (!cabq->axq_link) - ath9k_hw_puttxbuf(ah, cabq->axq_qnum, bfmcast->bf_daddr); - else - *cabq->axq_link = bfmcast->bf_daddr; - - /* append the private vap mcast list to the cabq */ - - cabq->axq_depth += mcastq->axq_depth; - cabq->axq_totalqueued += mcastq->axq_totalqueued; - cabq->axq_linkbuf = mcastq->axq_linkbuf; - cabq->axq_link = mcastq->axq_link; - list_splice_tail_init(&mcastq->axq_q, &cabq->axq_q); - mcastq->axq_depth = 0; - mcastq->axq_totalqueued = 0; - mcastq->axq_linkbuf = NULL; - mcastq->axq_link = NULL; -} - -/* TODO: use ieee80211_get_buffered_bc() to fetch power saved mcast frames */ -/* This is only run at DTIM. We move everything from the vap's mcast queue - * to the hardware cab queue. Caller must hold the mcastq lock. */ -static void trigger_mcastq(struct ath_hal *ah, - struct ath_txq *mcastq, struct ath_txq *cabq) -{ - spin_lock_bh(&cabq->axq_lock); - - if (!list_empty(&mcastq->axq_q)) - empty_mcastq_into_cabq(ah, mcastq, cabq); - - /* cabq is gated by beacon so it is safe to start here */ - if (!list_empty(&cabq->axq_q)) - ath9k_hw_txstart(ah, cabq->axq_qnum); - - spin_unlock_bh(&cabq->axq_lock); -} - /* * Generate beacon frame and queue cab data for a vap. * @@ -200,19 +150,14 @@ static void trigger_mcastq(struct ath_hal *ah, */ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) { - struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; int cabq_depth; - int mcastq_depth; - int is_beacon_dtim = 0; struct ath_txq *cabq; - struct ath_txq *mcastq; struct ieee80211_tx_info *info; avp = sc->sc_vaps[if_id]; - mcastq = &avp->av_mcastq; cabq = sc->sc_cabq; ASSERT(avp); @@ -250,11 +195,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) skb_end_pointer(skb) - skb->head, PCI_DMA_TODEVICE); - /* TODO: convert to use ieee80211_get_buffered_bc() */ - /* XXX: spin_lock_bh should not be used here, but sparse bitches - * otherwise. We should fix sparse :) */ - spin_lock_bh(&mcastq->axq_lock); - mcastq_depth = avp->av_mcastq.axq_depth; + skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); /* * if the CABQ traffic from previous DTIM is pending and the current @@ -268,10 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); - if (avp->av_boff.bo_tim) - is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; - - if (mcastq_depth && is_beacon_dtim && cabq_depth) { + if (skb && cabq_depth) { /* * Unlock the cabq lock as ath_tx_draintxq acquires * the lock again which is a common function and that @@ -291,10 +229,11 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * Enable the CAB queue before the beacon queue to * insure cab frames are triggered by this beacon. */ - if (is_beacon_dtim) - trigger_mcastq(ah, mcastq, cabq); + while (skb) { + ath_tx_cabq(sc, skb); + skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + } - spin_unlock_bh(&mcastq->axq_lock); return bf; } @@ -426,7 +365,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * NB: the beacon data buffer must be 32-bit aligned; * we assume the wbuf routines will return us something * with this alignment (perhaps should assert). - * FIXME: Fill avp->av_boff.bo_tim,avp->av_btxctl.txpower and + * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 57645ee83ef..c262ef279ff 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -533,9 +533,6 @@ int ath_vap_attach(struct ath_softc *sc, /* Set the VAP opmode */ avp->av_opmode = opmode; avp->av_bslot = -1; - INIT_LIST_HEAD(&avp->av_mcastq.axq_q); - INIT_LIST_HEAD(&avp->av_mcastq.axq_acq); - spin_lock_init(&avp->av_mcastq.axq_lock); ath9k_hw_set_tsfadjust(sc->sc_ah, 1); @@ -575,9 +572,6 @@ int ath_vap_detach(struct ath_softc *sc, int if_id) ath_stoprecv(sc); /* stop recv side */ ath_flushrecv(sc); /* flush recv queue */ - /* Reclaim any pending mcast bufs on the vap. */ - ath_tx_draintxq(sc, &avp->av_mcastq, false); - kfree(avp); sc->sc_vaps[if_id] = NULL; sc->sc_nvaps--; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index ca7e6135354..de1d12f7c64 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -568,6 +568,7 @@ u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth); void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ath_xmit_status *tx_status, struct ath_node *an); +void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /**********************/ /* Node / Aggregation */ @@ -713,12 +714,6 @@ struct ath_beacon_config { } u; /* last received beacon/probe response timestamp of this BSS. */ }; -/* offsets in a beacon frame for - * quick acess of beacon content by low-level driver */ -struct ath_beacon_offset { - u8 *bo_tim; /* start of atim/dtim */ -}; - void ath9k_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); @@ -755,10 +750,8 @@ struct ath_vap { struct ieee80211_vif *av_if_data; enum ath9k_opmode av_opmode; /* VAP operational mode */ struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_beacon_offset av_boff; /* dynamic update state */ struct ath_tx_control av_btxctl; /* txctl information for beacon */ int av_bslot; /* beacon slot index */ - struct ath_txq av_mcastq; /* multicast transmit queue */ struct ath_vap_config av_config;/* vap configuration parameters*/ struct ath_rate_node *rc_node; }; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 55f48685b5e..dca00c3a985 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1362,6 +1362,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 04f94d2c801..a18cea69904 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -59,79 +59,6 @@ static u32 bits_per_symbol[][2] = { #define IS_HT_RATE(_rate) ((_rate) & 0x80) -/* - * Insert a chain of ath_buf (descriptors) on a multicast txq - * but do NOT start tx DMA on this queue. - * NB: must be called with txq lock held - */ - -static void ath_tx_mcastqaddbuf(struct ath_softc *sc, - struct ath_txq *txq, - struct list_head *head) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf; - - if (list_empty(head)) - return; - - /* - * Insert the frame on the outbound list and - * pass it on to the hardware. - */ - bf = list_first_entry(head, struct ath_buf, list); - - /* - * The CAB queue is started from the SWBA handler since - * frames only go out on DTIM and to avoid possible races. - */ - ath9k_hw_set_interrupts(ah, 0); - - /* - * If there is anything in the mcastq, we want to set - * the "more data" bit in the last item in the queue to - * indicate that there is "more data". It makes sense to add - * it here since you are *always* going to have - * more data when adding to this queue, no matter where - * you call from. - */ - - if (txq->axq_depth) { - struct ath_buf *lbf; - struct ieee80211_hdr *hdr; - - /* - * Add the "more data flag" to the last frame - */ - - lbf = list_entry(txq->axq_q.prev, struct ath_buf, list); - hdr = (struct ieee80211_hdr *) - ((struct sk_buff *)(lbf->bf_mpdu))->data; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - /* - * Now, concat the frame onto the queue - */ - list_splice_tail_init(head, &txq->axq_q); - txq->axq_depth++; - txq->axq_totalqueued++; - txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); - - DPRINTF(sc, ATH_DBG_QUEUE, - "%s: txq depth = %d\n", __func__, txq->axq_depth); - if (txq->axq_link != NULL) { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, - "%s: link[%u](%p)=%llx (%p)\n", - __func__, - txq->axq_qnum, txq->axq_link, - ito64(bf->bf_daddr), bf->bf_desc); - } - txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); - ath9k_hw_set_interrupts(ah, sc->sc_imask); -} - /* * Insert a chain of ath_buf (descriptors) on a txq and * assume the descriptors are already chained together by caller. @@ -277,8 +204,6 @@ static int ath_tx_prepare(struct ath_softc *sc, __le16 fc; u8 *qc; - memset(txctl, 0, sizeof(struct ath_tx_control)); - txctl->dev = sc; hdr = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -329,12 +254,18 @@ static int ath_tx_prepare(struct ath_softc *sc, /* Fill qnum */ - txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[txctl->qnum]; + if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) { + txctl->qnum = 0; + txq = sc->sc_cabq; + } else { + txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->sc_txq[txctl->qnum]; + } spin_lock_bh(&txq->axq_lock); /* Try to avoid running out of descriptors */ - if (txq->axq_depth >= (ATH_TXBUF - 20)) { + if (txq->axq_depth >= (ATH_TXBUF - 20) && + !(txctl->flags & ATH9K_TXDESC_CAB)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: TX queue: %d is full, depth: %d\n", __func__, @@ -354,7 +285,7 @@ static int ath_tx_prepare(struct ath_softc *sc, /* Fill flags */ - txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) txctl->flags |= ATH9K_TXDESC_NOACK; @@ -1982,13 +1913,18 @@ static int ath_tx_start_dma(struct ath_softc *sc, struct list_head bf_head; struct ath_desc *ds; struct ath_hal *ah = sc->sc_ah; - struct ath_txq *txq = &sc->sc_txq[txctl->qnum]; + struct ath_txq *txq; struct ath_tx_info_priv *tx_info_priv; struct ath_rc_series *rcs; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); __le16 fc = hdr->frame_control; + if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) + txq = sc->sc_cabq; + else + txq = &sc->sc_txq[txctl->qnum]; + /* For each sglist entry, allocate an ath_buf for DMA */ INIT_LIST_HEAD(&bf_head); spin_lock_bh(&sc->sc_txbuflock); @@ -2093,27 +2029,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, bf->bf_tidno = txctl->tidno; } - if (is_multicast_ether_addr(hdr->addr1)) { - struct ath_vap *avp = sc->sc_vaps[txctl->if_id]; - - /* - * When servicing one or more stations in power-save - * mode (or) if there is some mcast data waiting on - * mcast queue (to prevent out of order delivery of - * mcast,bcast packets) multicast frames must be - * buffered until after the beacon. We use the private - * mcast queue for that. - */ - /* XXX? more bit in 802.11 frame header */ - spin_lock_bh(&avp->av_mcastq.axq_lock); - if (txctl->ps || avp->av_mcastq.axq_depth) - ath_tx_mcastqaddbuf(sc, - &avp->av_mcastq, &bf_head); - else - ath_tx_txqaddbuf(sc, txq, &bf_head); - spin_unlock_bh(&avp->av_mcastq.axq_lock); - } else - ath_tx_txqaddbuf(sc, txq, &bf_head); + ath_tx_txqaddbuf(sc, txq, &bf_head); } spin_unlock_bh(&txq->axq_lock); return 0; @@ -2407,6 +2323,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) struct ath_tx_control txctl; int error = 0; + memset(&txctl, 0, sizeof(struct ath_tx_control)); error = ath_tx_prepare(sc, skb, &txctl); if (error == 0) /* @@ -2871,3 +2788,57 @@ void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) } } } + +void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) +{ + int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath_tx_control txctl; + + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } + + /* Add the padding after the header if this is not already done */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + padsize = hdrlen % 4; + if (skb_headroom(skb) < padsize) { + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding " + "failed\n", __func__); + dev_kfree_skb_any(skb); + return; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } + + DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", + __func__, + skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + txctl.flags = ATH9K_TXDESC_CAB; + if (ath_tx_prepare(sc, skb, &txctl) == 0) { + /* + * Start DMA mapping. + * ath_tx_start_dma() will be called either synchronously + * or asynchrounsly once DMA is complete. + */ + xmit_map_sg(sc, skb, &txctl); + } else { + ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); + dev_kfree_skb_any(skb); + } +} + -- cgit v1.2.3 From a3ec233c90f0b8a5c00bf182f2c3ea9119b46caa Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 23 Aug 2008 13:56:25 +0800 Subject: wireless: remove unused #include The driver(s) below do not use LINUX_VERSION_CODE nor KERNEL_VERSION. drivers/net/wireless/b43legacy/main.c drivers/net/wireless/iwlwifi/iwl-3945-led.c drivers/net/wireless/iwlwifi/iwl-led.c drivers/net/wireless/iwlwifi/iwl-rfkill.c This patch removes the said #include . Signed-off-by: Huang Weiyi Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/main.c | 1 - drivers/net/wireless/iwlwifi/iwl-3945-led.c | 1 - drivers/net/wireless/iwlwifi/iwl-led.c | 1 - drivers/net/wireless/iwlwifi/iwl-rfkill.c | 1 - 4 files changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 2541c81932f..1cb77db5c29 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index d3336966b6b..705c65bed9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index cb11c4a4d69..4eee1b163cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index e5e5846e9f2..5d642298f04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -27,7 +27,6 @@ *****************************************************************************/ #include #include -#include #include #include -- cgit v1.2.3 From 154e3af17fdce617605b63f3534dac2c10c90922 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 23 Aug 2008 22:15:25 +0200 Subject: p54: fix rssi auto calibration Ever wondered why the signal was so bad with p54 compared to madwifi, or intel? Well, if you have revision 1 rssi calibration curve points in your EEPROM, then wonder no more. The firmware wants a extra 1 byte padding for every curve point. But someone forgot to put them into the EEPROM's data structure... So now, big question: what happens when we blindly "memcpy" these data points? Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 140 +++++++++++++++++++++++------------ drivers/net/wireless/p54/p54common.h | 23 +++++- 2 files changed, 111 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 29be3dc8ee0..4a6b5363ea4 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -155,14 +155,14 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) } EXPORT_SYMBOL_GPL(p54_parse_firmware); -static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) +static int p54_convert_rev0(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) { struct p54_common *priv = dev->priv; - struct pda_pa_curve_data_sample_rev1 *rev1; - struct pda_pa_curve_data_sample_rev0 *rev0; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev0 *src; size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*rev1) + 2) * + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; @@ -180,27 +180,63 @@ static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, *((__le16 *)target) = *freq; target += sizeof(__le16); for (j = 0; j < curve_data->points_per_channel; j++) { - rev1 = target; - rev0 = source; + dst = target; + src = source; - rev1->rf_power = rev0->rf_power; - rev1->pa_detector = rev0->pa_detector; - rev1->data_64qam = rev0->pcv; + dst->rf_power = src->rf_power; + dst->pa_detector = src->pa_detector; + dst->data_64qam = src->pcv; /* "invent" the points for the other modulations */ #define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) - rev1->data_16qam = SUB(rev0->pcv, 12); - rev1->data_qpsk = SUB(rev1->data_16qam, 12); - rev1->data_bpsk = SUB(rev1->data_qpsk, 12); - rev1->data_barker= SUB(rev1->data_bpsk, 14); + dst->data_16qam = SUB(src->pcv, 12); + dst->data_qpsk = SUB(dst->data_16qam, 12); + dst->data_bpsk = SUB(dst->data_qpsk, 12); + dst->data_barker = SUB(dst->data_bpsk, 14); #undef SUB - target += sizeof(*rev1); - source += sizeof(*rev0); + target += sizeof(*dst); + source += sizeof(*src); } } return 0; } +static int p54_convert_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev1 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(cd_len, GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = priv->curve_data->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + memcpy(target, source, sizeof(*src)); + + target += sizeof(*dst); + source += sizeof(*src); + } + source++; + } + + return 0; +} + int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -250,27 +286,32 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) entry->data[1]*sizeof(*priv->output_limit)); priv->output_limit_len = entry->data[1]; break; - case PDR_PRISM_PA_CAL_CURVE_DATA: - if (data_len < sizeof(struct pda_pa_curve_data)) { + case PDR_PRISM_PA_CAL_CURVE_DATA: { + struct pda_pa_curve_data *curve_data = + (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; } - if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) { - priv->curve_data = kmalloc(data_len, GFP_KERNEL); - if (!priv->curve_data) { - err = -ENOMEM; - goto err; - } - - memcpy(priv->curve_data, entry->data, data_len); - } else { - err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data); - if (err) - goto err; + switch (curve_data->cal_method_rev) { + case 0: + err = p54_convert_rev0(dev, curve_data); + break; + case 1: + err = p54_convert_rev1(dev, curve_data); + break; + default: + printk(KERN_ERR "p54: unknown curve data " + "revision %d\n", + curve_data->cal_method_rev); + err = -ENODEV; + break; } + if (err) + goto err; - break; + } case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); if (!priv->iq_autocal) { @@ -672,12 +713,9 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) struct p54_control_hdr *hdr; struct p54_tx_control_channel *chan; unsigned int i; - size_t payload_len = sizeof(*chan) + sizeof(u32)*2 + - sizeof(*chan->curve_data) * - priv->curve_data->points_per_channel; void *entry; - hdr = kzalloc(sizeof(*hdr) + payload_len + + hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + priv->tx_hdr_len, GFP_KERNEL); if (!hdr) return -ENOMEM; @@ -689,10 +727,10 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*chan)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan)); - chan->magic1 = cpu_to_le16(0x1); - chan->magic2 = cpu_to_le16(0x0); + chan->flags = cpu_to_le16(0x1); + chan->dwell = cpu_to_le16(0x0); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -710,35 +748,41 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) continue; chan->val_barker = 0x38; - chan->val_bpsk = priv->output_limit[i].val_bpsk; - chan->val_qpsk = priv->output_limit[i].val_qpsk; - chan->val_16qam = priv->output_limit[i].val_16qam; - chan->val_64qam = priv->output_limit[i].val_64qam; + chan->val_bpsk = chan->dup_bpsk = + priv->output_limit[i].val_bpsk; + chan->val_qpsk = chan->dup_qpsk = + priv->output_limit[i].val_qpsk; + chan->val_16qam = chan->dup_16qam = + priv->output_limit[i].val_16qam; + chan->val_64qam = chan->dup_64qam = + priv->output_limit[i].val_64qam; break; } if (i == priv->output_limit_len) goto err; - chan->pa_points_per_curve = priv->curve_data->points_per_channel; - entry = priv->curve_data->data; for (i = 0; i < priv->curve_data->channels; i++) { if (*((__le16 *)entry) != freq) { entry += sizeof(__le16); - entry += sizeof(struct pda_pa_curve_data_sample_rev1) * - chan->pa_points_per_curve; + entry += sizeof(struct p54_pa_curve_data_sample) * + priv->curve_data->points_per_channel; continue; } entry += sizeof(__le16); + chan->pa_points_per_curve = + min(priv->curve_data->points_per_channel, (u8) 8); + memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * chan->pa_points_per_curve); break; } - memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4); + chan->rssical_mul = cpu_to_le16(130); + chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */ - priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1); + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1); return 0; err: diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 9bc2a1cf4b5..a79c1a14691 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -89,6 +89,16 @@ struct pda_pa_curve_data_sample_rev1 { u8 data_qpsk; u8 data_16qam; u8 data_64qam; +} __attribute__ ((packed)); + +struct p54_pa_curve_data_sample { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; u8 padding; } __attribute__ ((packed)); @@ -212,8 +222,8 @@ struct p54_tx_control_filter { } __attribute__ ((packed)); struct p54_tx_control_channel { - __le16 magic1; - __le16 magic2; + __le16 flags; + __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; u8 pa_points_per_curve; @@ -222,8 +232,13 @@ struct p54_tx_control_channel { u8 val_qpsk; u8 val_16qam; u8 val_64qam; - struct pda_pa_curve_data_sample_rev1 curve_data[0]; - /* additional padding/data after curve_data */ + struct pda_pa_curve_data_sample_rev1 curve_data[8]; + u8 dup_bpsk; + u8 dup_qpsk; + u8 dup_16qam; + u8 dup_64qam; + __le16 rssical_mul; + __le16 rssical_add; } __attribute__ ((packed)); struct p54_tx_control_led { -- cgit v1.2.3 From 031d10ee5a6df5aba6b4ac8bb01dd023cd5efc02 Mon Sep 17 00:00:00 2001 From: Chr Date: Sun, 24 Aug 2008 03:15:06 +0200 Subject: p54: take tx_queue's lock in rx_frame_sent p54_rx_frame_sent will alter the tx_queue. Therefore we should hold the lock to protect against concurrent p54_assign_address calls. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 4a6b5363ea4..5cd88bcb028 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -432,7 +432,9 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct memrecord *range = NULL; u32 freed = 0; u32 last_addr = priv->rx_start; + unsigned long flags; + spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); range = (void *)info->driver_data; @@ -453,6 +455,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + memset(&info->status, 0, sizeof(info->status)); entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; @@ -470,12 +474,14 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) info->status.ack_signal = le16_to_cpu(payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); ieee80211_tx_status_irqsafe(dev, entry); - break; + goto out; } else last_addr = range->end_addr; entry = entry->next; } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); +out: if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + sizeof(struct p54_control_hdr)) p54_wake_free_queues(dev); -- cgit v1.2.3 From 84df3ed30b72c3516d72bc9734d4425746b15dfc Mon Sep 17 00:00:00 2001 From: Chr Date: Sun, 24 Aug 2008 03:15:16 +0200 Subject: p54: redo queue numbering The firmware supports 8 different queues and not only 4. So, let's make some room for further tasks (ap/adhoc support) in this area. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 +- drivers/net/wireless/p54/p54common.c | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 10df07de9e5..fca8762fa06 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -66,7 +66,7 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - struct ieee80211_tx_queue_stats tx_stats[4]; + struct ieee80211_tx_queue_stats tx_stats[8]; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 5cd88bcb028..17e06bbc996 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -146,10 +146,10 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[0].limit = 3; - priv->tx_stats[1].limit = 4; - priv->tx_stats[2].limit = 3; - priv->tx_stats[3].limit = 1; + priv->tx_stats[4].limit = 3; + priv->tx_stats[5].limit = 4; + priv->tx_stats[6].limit = 3; + priv->tx_stats[7].limit = 1; dev->queues = 4; } } @@ -418,7 +418,7 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) int i; for (i = 0; i < dev->queues; i++) - if (priv->tx_stats[i].len < priv->tx_stats[i].limit) + if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } @@ -463,7 +463,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - priv->tx_stats[entry_data->hw_queue - 4].len--; + priv->tx_stats[entry_data->hw_queue].len--; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -606,7 +606,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u8 rate; u8 cts_rate = 0x20; - current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; @@ -1037,7 +1037,7 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues); + memcpy(stats, &priv->tx_stats[4], sizeof(stats[0]) * dev->queues); return 0; } @@ -1075,7 +1075,11 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->channel_change_time = 1000; /* TODO: find actual value */ dev->max_signal = 127; - priv->tx_stats[0].limit = 5; + priv->tx_stats[0].limit = 1; + priv->tx_stats[1].limit = 1; + priv->tx_stats[2].limit = 1; + priv->tx_stats[3].limit = 1; + priv->tx_stats[4].limit = 5; dev->queues = 1; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + -- cgit v1.2.3 From 7262d59366f972b898ea134639112d34bcac35b3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 24 Aug 2008 22:30:38 +0200 Subject: p54pci: rx tasklet refactoring This patch moves the all of p54pci's receiver code out of the bloated interrupt handler routine and into a less critical tasklet. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54pci.c | 242 +++++++++++++++++++++++++------------- drivers/net/wireless/p54/p54pci.h | 10 +- 2 files changed, 168 insertions(+), 84 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index ea2dc3d93c4..e9db4495c62 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -3,6 +3,7 @@ * Linux device driver for PCI based Prism54 * * Copyright (c) 2006, Michael Wu + * Copyright (c) 2008, Christian Lamparter * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note , et al. @@ -237,20 +238,22 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) return err; } -static void p54p_refill_rx_ring(struct ieee80211_hw *dev) +static void p54p_refill_rx_ring(struct ieee80211_hw *dev, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + struct sk_buff **rx_buf) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; - u32 limit, host_idx, idx; + u32 limit, idx, i; - host_idx = le32_to_cpu(ring_control->host_idx[0]); - limit = host_idx; - limit -= le32_to_cpu(ring_control->device_idx[0]); - limit = ARRAY_SIZE(ring_control->rx_data) - limit; + idx = le32_to_cpu(ring_control->host_idx[ring_index]); + limit = idx; + limit -= le32_to_cpu(ring_control->device_idx[ring_index]); + limit = ring_limit - limit; - idx = host_idx % ARRAY_SIZE(ring_control->rx_data); + i = idx % ring_limit; while (limit-- > 1) { - struct p54p_desc *desc = &ring_control->rx_data[idx]; + struct p54p_desc *desc = &ring[i]; if (!desc->host_addr) { struct sk_buff *skb; @@ -267,16 +270,106 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev) desc->device_addr = 0; // FIXME: necessary? desc->len = cpu_to_le16(MAX_RX_SIZE); desc->flags = 0; - priv->rx_buf[idx] = skb; + rx_buf[i] = skb; } + i++; idx++; - host_idx++; - idx %= ARRAY_SIZE(ring_control->rx_data); + i %= ring_limit; } wmb(); - ring_control->host_idx[0] = cpu_to_le32(host_idx); + ring_control->host_idx[ring_index] = cpu_to_le32(idx); +} + +static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + struct sk_buff **rx_buf) +{ + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + struct p54p_desc *desc; + u32 idx, i; + + i = (*index) % ring_limit; + (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]); + idx %= ring_limit; + while (i != idx) { + u16 len; + struct sk_buff *skb; + desc = &ring[i]; + len = le16_to_cpu(desc->len); + skb = rx_buf[i]; + + if (!skb) + continue; + + skb_put(skb, len); + + if (p54_rx(dev, skb)) { + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + rx_buf[i] = NULL; + desc->host_addr = 0; + } else { + skb_trim(skb, 0); + desc->len = cpu_to_le16(MAX_RX_SIZE); + } + + i++; + i %= ring_limit; + } + + p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); +} + +/* caller must hold priv->lock */ +static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + void **tx_buf) +{ + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + struct p54p_desc *desc; + u32 idx, i; + + i = (*index) % ring_limit; + (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); + idx %= ring_limit; + + while (i != idx) { + desc = &ring[i]; + kfree(tx_buf[i]); + tx_buf[i] = NULL; + + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + + desc->host_addr = 0; + desc->device_addr = 0; + desc->len = 0; + desc->flags = 0; + + i++; + i %= ring_limit; + } +} + +static void p54p_rx_tasklet(unsigned long dev_id) +{ + struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + + p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, + ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); + + p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data, + ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data); + + wmb(); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); } static irqreturn_t p54p_interrupt(int irq, void *dev_id) @@ -298,65 +391,18 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) reg &= P54P_READ(int_enable); if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { - struct p54p_desc *desc; - u32 idx, i; - i = priv->tx_idx; - i %= ARRAY_SIZE(ring_control->tx_data); - priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]); - idx %= ARRAY_SIZE(ring_control->tx_data); - - while (i != idx) { - desc = &ring_control->tx_data[i]; - if (priv->tx_buf[i]) { - kfree(priv->tx_buf[i]); - priv->tx_buf[i] = NULL; - } - - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, + 3, ring_control->tx_mgmt, + ARRAY_SIZE(ring_control->tx_mgmt), + priv->tx_buf_mgmt); - desc->host_addr = 0; - desc->device_addr = 0; - desc->len = 0; - desc->flags = 0; + p54p_check_tx_ring(dev, &priv->tx_idx_data, + 1, ring_control->tx_data, + ARRAY_SIZE(ring_control->tx_data), + priv->tx_buf_data); - i++; - i %= ARRAY_SIZE(ring_control->tx_data); - } - - i = priv->rx_idx; - i %= ARRAY_SIZE(ring_control->rx_data); - priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]); - idx %= ARRAY_SIZE(ring_control->rx_data); - while (i != idx) { - u16 len; - struct sk_buff *skb; - desc = &ring_control->rx_data[i]; - len = le16_to_cpu(desc->len); - skb = priv->rx_buf[i]; - - skb_put(skb, len); - - if (p54_rx(dev, skb)) { - pci_unmap_single(priv->pdev, - le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - - priv->rx_buf[i] = NULL; - desc->host_addr = 0; - } else { - skb_trim(skb, 0); - desc->len = cpu_to_le16(MAX_RX_SIZE); - } - - i++; - i %= ARRAY_SIZE(ring_control->rx_data); - } + tasklet_schedule(&priv->rx_tasklet); - p54p_refill_rx_ring(dev); - - wmb(); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) complete(&priv->boot_comp); @@ -392,7 +438,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, ring_control->host_idx[1] = cpu_to_le32(idx + 1); if (free_on_tx) - priv->tx_buf[i] = data; + priv->tx_buf_data[i] = data; spin_unlock_irqrestore(&priv->lock, flags); @@ -420,8 +466,14 @@ static int p54p_open(struct ieee80211_hw *dev) } memset(priv->ring_control, 0, sizeof(*priv->ring_control)); - priv->rx_idx = priv->tx_idx = 0; - p54p_refill_rx_ring(dev); + priv->rx_idx_data = priv->tx_idx_data = 0; + priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0; + + p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data, + ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data); + + p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt, + ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt); p54p_upload_firmware(dev); @@ -465,6 +517,8 @@ static void p54p_stop(struct ieee80211_hw *dev) unsigned int i; struct p54p_desc *desc; + tasklet_kill(&priv->rx_tasklet); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); @@ -473,26 +527,51 @@ static void p54p_stop(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); - for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { + for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { desc = &ring_control->rx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - kfree_skb(priv->rx_buf[i]); - priv->rx_buf[i] = NULL; + kfree_skb(priv->rx_buf_data[i]); + priv->rx_buf_data[i] = NULL; } - for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { + for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) { + desc = &ring_control->rx_mgmt[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(priv->rx_buf_mgmt[i]); + priv->rx_buf_mgmt[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) { desc = &ring_control->tx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), + PCI_DMA_TODEVICE); + + kfree(priv->tx_buf_data[i]); + priv->tx_buf_data[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) { + desc = &ring_control->tx_mgmt[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), + PCI_DMA_TODEVICE); - kfree(priv->tx_buf[i]); - priv->tx_buf[i] = NULL; + kfree(priv->tx_buf_mgmt[i]); + priv->tx_buf_mgmt[i] = NULL; } - memset(ring_control, 0, sizeof(ring_control)); + memset(ring_control, 0, sizeof(*ring_control)); } static int __devinit p54p_probe(struct pci_dev *pdev, @@ -585,6 +664,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->common.tx = p54p_tx; spin_lock_init(&priv->lock); + tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); err = ieee80211_register_hw(dev); if (err) { diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 07678ef5ddc..4a6778070af 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -92,13 +92,17 @@ struct p54p_priv { struct p54_common common; struct pci_dev *pdev; struct p54p_csr __iomem *map; + struct tasklet_struct rx_tasklet; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; - u32 rx_idx, tx_idx; - struct sk_buff *rx_buf[8]; - void *tx_buf[32]; + u32 rx_idx_data, tx_idx_data; + u32 rx_idx_mgmt, tx_idx_mgmt; + struct sk_buff *rx_buf_data[8]; + struct sk_buff *rx_buf_mgmt[4]; + void *tx_buf_data[32]; + void *tx_buf_mgmt[4]; struct completion boot_comp; }; -- cgit v1.2.3 From c83be6885e2f1ee6e0b290b6cfc82014c675e087 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 25 Aug 2008 20:47:29 +0530 Subject: ath9k: Add LED support Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 16 ++--- drivers/net/wireless/ath9k/core.h | 29 ++++++++ drivers/net/wireless/ath9k/hw.c | 33 ++------- drivers/net/wireless/ath9k/main.c | 138 ++++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath9k/reg.h | 6 -- 5 files changed, 176 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 841893b0b4d..020b97fd208 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -757,14 +757,11 @@ struct ath9k_node_stats { #define ATH9K_RSSI_EP_MULTIPLIER (1<<7) -enum ath9k_gpio_output_mux_type { - ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT, - ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, - ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES -}; +#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 enum { ATH9K_RESET_POWER_ON, @@ -1008,4 +1005,7 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah, bool ath9k_get_channel_edges(struct ath_hal *ah, u16 flags, u16 *low, u16 *high); +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value); #endif diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index de1d12f7c64..0692fc34026 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -39,6 +39,7 @@ #include #include #include +#include #include "ath9k.h" #include "rc.h" @@ -802,6 +803,27 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv, struct ath_rx_status *rx_stats); void ath_setdefantenna(void *sc, u32 antenna); +/********************/ +/* LED Control */ +/********************/ + +#define ATH_LED_PIN 1 + +enum ath_led_type { + ATH_LED_RADIO, + ATH_LED_ASSOC, + ATH_LED_TX, + ATH_LED_RX +}; + +struct ath_led { + struct ath_softc *sc; + struct led_classdev led_cdev; + enum ath_led_type led_type; + char name[32]; + bool registered; +}; + /********************/ /* Main driver core */ /********************/ @@ -884,6 +906,7 @@ struct ath_ht_info { #define SC_OP_PREAMBLE_SHORT BIT(7) #define SC_OP_PROTECT_ENABLE BIT(8) #define SC_OP_RXFLUSH BIT(9) +#define SC_OP_LED_ASSOCIATED BIT(10) struct ath_softc { struct ieee80211_hw *hw; @@ -988,6 +1011,12 @@ struct ath_softc { spinlock_t sc_txbuflock; spinlock_t sc_resetlock; spinlock_t node_lock; + + /* LEDs */ + struct ath_led radio_led; + struct ath_led assoc_led; + struct ath_led tx_led; + struct ath_led rx_led; }; int ath_init(u16 devid, struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 47c60acac41..2578411c601 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2800,32 +2800,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, } } -static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - enum ath9k_gpio_output_mux_type - halSignalType) +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - u32 ah_signal_type; u32 gpio_shift; - static u32 MuxSignalConversionTable[] = { - - AR_GPIO_OUTPUT_MUX_AS_OUTPUT, - - AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, - - AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, - - AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, - - AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, - }; - - if ((halSignalType >= 0) - && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable))) - ah_signal_type = MuxSignalConversionTable[halSignalType]; - else - return false; - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); gpio_shift = 2 * gpio; @@ -2834,16 +2813,12 @@ static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, AR_GPIO_OE_OUT, (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), (AR_GPIO_OE_OUT_DRV << gpio_shift)); - - return true; } -static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, - u32 val) +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) { REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), AR_GPIO_BIT(gpio)); - return true; } static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) @@ -5923,7 +5898,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, else ath9k_hw_set_gpio(ah, 9, 1); } - ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); } ecode = ath9k_hw_process_ini(ah, chan, macmode); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index dca00c3a985..996bb9c6540 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1172,12 +1172,130 @@ enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) return sc->sc_ht_info.tx_chan_width; } +/********************************/ +/* LED functions */ +/********************************/ + +static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath_softc *sc = led->sc; + + switch (brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (led->led_type == ATH_LED_RADIO) ? 1 : + !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + break; + default: + break; + } +} + +static int ath_register_led(struct ath_softc *sc, struct ath_led *led, + char *trigger) +{ + int ret; + + led->sc = sc; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath_led_brightness; + + ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); + if (ret) + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + return ret; +} + +static void ath_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; + } +} + +static void ath_deinit_leds(struct ath_softc *sc) +{ + ath_unregister_led(&sc->assoc_led); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath_unregister_led(&sc->tx_led); + ath_unregister_led(&sc->rx_led); + ath_unregister_led(&sc->radio_led); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); +} + +static void ath_init_leds(struct ath_softc *sc) +{ + char *trigger; + int ret; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + + trigger = ieee80211_get_radio_led_name(sc->hw); + snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), + "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->radio_led, trigger); + sc->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; + + trigger = ieee80211_get_assoc_led_name(sc->hw); + snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), + "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->assoc_led, trigger); + sc->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; + + trigger = ieee80211_get_tx_led_name(sc->hw); + snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), + "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->tx_led, trigger); + sc->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; + + trigger = ieee80211_get_rx_led_name(sc->hw); + snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), + "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->rx_led, trigger); + sc->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; + + return; + +fail: + ath_deinit_leds(sc); +} + static int ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + /* Deinit LED control */ + ath_deinit_leds(sc); + /* Unregister hw */ ieee80211_unregister_hw(hw); @@ -1271,18 +1389,21 @@ static int ath_attach(u16 devid, goto bad; } + /* Initialize LED control */ + ath_init_leds(sc); + /* initialize tx/rx engine */ error = ath_tx_init(sc, ATH_TXBUF); if (error != 0) - goto bad1; + goto detach; error = ath_rx_init(sc, ATH_RXBUF); if (error != 0) - goto bad1; + goto detach; return 0; -bad1: +detach: ath_detach(sc); bad: return error; @@ -1427,6 +1548,10 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; + + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, 3); @@ -1436,6 +1561,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int ath_pci_resume(struct pci_dev *pdev) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; u32 val; int err; @@ -1452,6 +1579,11 @@ static int ath_pci_resume(struct pci_dev *pdev) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + /* Enable LED */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + return 0; } diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 42b0890a468..60617ae6620 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -899,12 +899,6 @@ enum { #define AR_GPIO_OUTPUT_MUX2 0x4064 #define AR_GPIO_OUTPUT_MUX3 0x4068 -#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 - #define AR_INPUT_STATE 0x406c #define AR_EEPROM_STATUS_DATA 0x407c -- cgit v1.2.3 From 822ceaefaaaea4bcd7965e3f4b3479e805f7dfa5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:10:29 +0530 Subject: ath9k: Remove more dead code Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 5 ----- drivers/net/wireless/ath9k/beacon.c | 25 ------------------------- drivers/net/wireless/ath9k/hw.h | 4 ---- drivers/net/wireless/ath9k/main.c | 5 ----- 4 files changed, 39 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 020b97fd208..28b8d84f49b 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -628,11 +628,6 @@ struct ath9k_country_entry { (IEEE80211_WEP_IVLEN + \ IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN)) -#define IEEE80211_MAX_LEN (2300 + FCS_LEN + \ - (IEEE80211_WEP_IVLEN + \ - IEEE80211_WEP_KIDLEN + \ - IEEE80211_WEP_CRCLEN)) - #define MAX_RATE_POWER 63 enum ath9k_power_mode { diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index fdbabc18022..c43fd586116 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -453,31 +453,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) } } -/* - * Reclaim beacon resources and return buffer to the pool. - * - * This function will free any wbuf frames that are still attached to the - * beacon buffers in the ATH object. Note that this does not de-allocate - * any wbuf objects that are in the transmit queue and have not yet returned - * to the ATH object. -*/ - -void ath_beacon_free(struct ath_softc *sc) -{ - struct ath_buf *bf; - - list_for_each_entry(bf, &sc->sc_bbuf, list) { - if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu; - pci_unmap_single(sc->pdev, bf->bf_dmacontext, - skb_end_pointer(skb) - skb->head, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - } - } -} - /* * Tasklet for Sending Beacons * diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 5cb3912ad39..2113818ee93 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -825,10 +825,6 @@ struct ath_hal_5416 { #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 -#define ar5416CheckOpMode(_opmode) \ - ((_opmode == ATH9K_M_STA) || (_opmode == ATH9K_M_IBSS) || \ - (_opmode == ATH9K_M_HOSTAP) || (_opmode == ATH9K_M_MONITOR)) - #define AR5416_EEPROM_MAGIC_OFFSET 0x0 #define AR5416_EEPROM_S 2 diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 996bb9c6540..dc45eef3289 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1167,11 +1167,6 @@ int ath_rx_subframe(struct ath_node *an, return 0; } -enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) -{ - return sc->sc_ht_info.tx_chan_width; -} - /********************************/ /* LED functions */ /********************************/ -- cgit v1.2.3 From 14cc709f338f44f1ff69fa0b0e35e9de3ee62eb5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:10:49 +0530 Subject: ath9k: Do not update frame's duration field When AR_DurUpdateEna is set, the frame's duration field is updated by the MAC based on the current rate. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 - drivers/net/wireless/ath9k/xmit.c | 56 ++++++++------------------------------- 2 files changed, 11 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 0692fc34026..b6b6868195c 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -516,7 +516,6 @@ struct ath_tx_control { u32 keyix; int min_rate; int mcast_rate; - u16 nextfraglen; struct ath_softc *dev; dma_addr_t dmacontext; }; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index a18cea69904..87aebf17573 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -227,7 +227,6 @@ static int ath_tx_prepare(struct ath_softc *sc, } txctl->if_id = 0; - txctl->nextfraglen = 0; txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); txctl->txpower = MAX_RATE_POWER; /* FIXME */ @@ -344,51 +343,18 @@ static int ath_tx_prepare(struct ath_softc *sc, } rix = rcs[0].rix; - /* - * Calculate duration. This logically belongs in the 802.11 - * layer but it lacks sufficient information to calculate it. - */ - if ((txctl->flags & ATH9K_TXDESC_NOACK) == 0 && !ieee80211_is_ctl(fc)) { - u16 dur; + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { /* - * XXX not right with fragmentation. - */ - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - dur = rt->info[rix].spAckDuration; - else - dur = rt->info[rix].lpAckDuration; - - if (le16_to_cpu(hdr->frame_control) & - IEEE80211_FCTL_MOREFRAGS) { - dur += dur; /* Add additional 'SIFS + ACK' */ - - /* - ** Compute size of next fragment in order to compute - ** durations needed to update NAV. - ** The last fragment uses the ACK duration only. - ** Add time for next fragment. - */ - dur += ath9k_hw_computetxtime(sc->sc_ah, rt, - txctl->nextfraglen, - rix, - (sc->sc_flags & SC_OP_PREAMBLE_SHORT)); - } - - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - /* - ** Force hardware to use computed duration for next - ** fragment by disabling multi-rate retry, which - ** updates duration based on the multi-rate - ** duration table. - */ - rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; - rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; - /* reset tries but keep rate index */ - rcs[0].tries = ATH_TXMAXTRY; - } - - hdr->duration_id = cpu_to_le16(dur); + ** Force hardware to use computed duration for next + ** fragment by disabling multi-rate retry, which + ** updates duration based on the multi-rate + ** duration table. + */ + rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; + rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; + /* reset tries but keep rate index */ + rcs[0].tries = ATH_TXMAXTRY; } /* -- cgit v1.2.3 From 1fe1132bad8e98fa34cfb4a3901340d1214b95d7 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:11:06 +0530 Subject: ath9k: Remove sc_lastrx as we don't use it anywhere Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 1 - drivers/net/wireless/ath9k/xmit.c | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index b6b6868195c..1faa1effa02 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -970,7 +970,6 @@ struct ath_softc { struct ath_descdma sc_rxdma; int sc_rxbufsize; /* rx size based on mtu */ u32 *sc_rxlink; /* link ptr in last RX desc */ - u64 sc_lastrx; /* tsf of last rx'd frame */ /* TX */ struct list_head sc_txbuf; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 87aebf17573..3fc6641e8bf 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2309,8 +2309,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) void ath_tx_tasklet(struct ath_softc *sc) { - u64 tsf = ath9k_hw_gettsf64(sc->sc_ah); - int i, nacked = 0; + int i; u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); @@ -2320,10 +2319,8 @@ void ath_tx_tasklet(struct ath_softc *sc) */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - nacked += ath_tx_processq(sc, &sc->sc_txq[i]); + ath_tx_processq(sc, &sc->sc_txq[i]); } - if (nacked) - sc->sc_lastrx = tsf; } void ath_tx_draintxq(struct ath_softc *sc, -- cgit v1.2.3 From 5701ed843ea87bf8a1d2c4dee5edcb463558db4a Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:11:26 +0530 Subject: ath9k: rc.h cleanup Use kernel doc syntax for comments and remove a few unused macros. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 18 ++-- drivers/net/wireless/ath9k/rc.h | 222 +++++++++++++++++++++------------------- 2 files changed, 125 insertions(+), 115 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1dd7c71daf0..390019ed398 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1141,14 +1141,14 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* * Return the Tx rate series. */ -void ath_rate_findrate(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, - int num_rates, - unsigned int rcflag, - struct ath_rc_series series[], - int *is_probe, - int is_retry) +static void ath_rate_findrate(struct ath_softc *sc, + struct ath_rate_node *ath_rc_priv, + int num_tries, + int num_rates, + unsigned int rcflag, + struct ath_rc_series series[], + int *is_probe, + int is_retry) { struct ath_vap *avp = ath_rc_priv->avp; @@ -1942,7 +1942,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, struct ath_rate_node *ath_rc_priv; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe, chk, ret; + int is_probe = FALSE, chk, ret; s8 lowest_idx; __le16 fc = hdr->frame_control; u8 *qc, tid; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 71aef9c7523..b95b41508b9 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -71,9 +71,6 @@ enum ieee80211_fixed_rate_mode { */ #define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) -#define SHORT_PRE 1 -#define LONG_PRE 0 - #define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS #define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS #define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI @@ -102,18 +99,18 @@ enum { WLAN_RC_PHY_MAX }; -#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ + || (_phy == WLAN_RC_PHY_HT_40_DS) \ + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ + || (_phy == WLAN_RC_PHY_HT_40_DS) \ + || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) #define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) #define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) @@ -135,56 +132,59 @@ enum { #define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_HT_FLAG (0x08) -/* Index into the rate table */ -#define INIT_RATE_MAX_20 23 -#define INIT_RATE_MAX_40 40 - #define RATE_TABLE_SIZE 64 -/* XXX: Convert to kdoc */ +/** + * struct ath_rate_table - Rate Control table + * @valid: valid for use in rate control + * @valid_single_stream: valid for use in rate control for + * single stream operation + * @phy: CCK/OFDM + * @ratekbps: rate in Kbits per second + * @user_ratekbps: user rate in Kbits per second + * @ratecode: rate that goes into HW descriptors + * @short_preamble: Mask for enabling short preamble in ratecode for CCK + * @dot11rate: value that goes into supported + * rates info element of MLME + * @ctrl_rate: Index of next lower basic rate, used for duration computation + * @max_4ms_framelen: maximum frame length(bytes) for tx duration + * @probe_interval: interval for rate control to probe for other rates + * @rssi_reduce_interval: interval for rate control to reduce rssi + * @initial_ratemax: initial ratemax value used in ath_rc_sib_update() + */ struct ath_rate_table { int rate_cnt; struct { - int valid; /* Valid for use in rate control */ - int valid_single_stream;/* Valid for use in rate control - for single stream operation */ - u8 phy; /* CCK/OFDM/TURBO/XR */ - u32 ratekbps; /* Rate in Kbits per second */ - u32 user_ratekbps; /* User rate in KBits per second */ - u8 ratecode; /* rate that goes into - hw descriptors */ - u8 short_preamble; /* Mask for enabling short preamble - in rate code for CCK */ - u8 dot11rate; /* Value that goes into supported - rates info element of MLME */ - u8 ctrl_rate; /* Index of next lower basic rate, - used for duration computation */ - int8_t rssi_ack_validmin; /* Rate control related */ - int8_t rssi_ack_deltamin; /* Rate control related */ - u8 base_index; /* base rate index */ - u8 cw40index; /* 40cap rate index */ - u8 sgi_index; /* shortgi rate index */ - u8 ht_index; /* shortgi rate index */ - u32 max_4ms_framelen; /* Maximum frame length(bytes) - for 4ms tx duration */ + int valid; + int valid_single_stream; + u8 phy; + u32 ratekbps; + u32 user_ratekbps; + u8 ratecode; + u8 short_preamble; + u8 dot11rate; + u8 ctrl_rate; + int8_t rssi_ack_validmin; + int8_t rssi_ack_deltamin; + u8 base_index; + u8 cw40index; + u8 sgi_index; + u8 ht_index; + u32 max_4ms_framelen; } info[RATE_TABLE_SIZE]; - u32 probe_interval; /* interval for ratectrl to - probe for other rates */ - u32 rssi_reduce_interval; /* interval for ratectrl - to reduce RSSI */ - u8 initial_ratemax; /* the initial ratemax value used - in ath_rc_sib_update() */ + u32 probe_interval; + u32 rssi_reduce_interval; + u8 initial_ratemax; }; #define ATH_RC_PROBE_ALLOWED 0x00000001 #define ATH_RC_MINRATE_LASTRATE 0x00000002 -#define ATH_RC_SHORT_PREAMBLE 0x00000004 struct ath_rc_series { - u8 rix; - u8 tries; - u8 flags; - u32 max_4ms_framelen; + u8 rix; + u8 tries; + u8 flags; + u32 max_4ms_framelen; }; /* rcs_flags definition */ @@ -201,42 +201,56 @@ struct ath_rc_series { #define MAX_TX_RATE_PHY 48 struct ath_tx_ratectrl_state { - int8_t rssi_thres; /* required rssi for this rate (dB) */ - u8 per; /* recent estimate of packet error rate (%) */ + int8_t rssi_thres; /* required rssi for this rate (dB) */ + u8 per; /* recent estimate of packet error rate (%) */ }; +/** + * struct ath_tx_ratectrl - TX Rate control Information + * @state: RC state + * @rssi_last: last ACK rssi + * @rssi_last_lookup: last ACK rssi used for lookup + * @rssi_last_prev: previous last ACK rssi + * @rssi_last_prev2: 2nd previous last ACK rssi + * @rssi_sum_cnt: count of rssi_sum for averaging + * @rssi_sum_rate: rate that we are averaging + * @rssi_sum: running sum of rssi for averaging + * @probe_rate: rate we are probing at + * @rssi_time: msec timestamp for last ack rssi + * @rssi_down_time: msec timestamp for last down step + * @probe_time: msec timestamp for last probe + * @hw_maxretry_pktcnt: num of packets since we got HW max retry error + * @max_valid_rate: maximum number of valid rate + * @per_down_time: msec timestamp for last PER down step + * @valid_phy_ratecnt: valid rate count + * @rate_max_phy: phy index for the max rate + * @probe_interval: interval for ratectrl to probe for other rates + */ struct ath_tx_ratectrl { - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */ - int8_t rssi_last; /* last ack rssi */ - int8_t rssi_last_lookup; /* last ack rssi used for lookup */ - int8_t rssi_last_prev; /* previous last ack rssi */ - int8_t rssi_last_prev2; /* 2nd previous last ack rssi */ - int32_t rssi_sum_cnt; /* count of rssi_sum for averaging */ - int32_t rssi_sum_rate; /* rate that we are averaging */ - int32_t rssi_sum; /* running sum of rssi for averaging */ - u32 valid_txrate_mask; /* mask of valid rates */ - u8 rate_table_size; /* rate table size */ - u8 rate_max; /* max rate that has recently worked */ - u8 probe_rate; /* rate we are probing at */ - u32 rssi_time; /* msec timestamp for last ack rssi */ - u32 rssi_down_time; /* msec timestamp for last down step */ - u32 probe_time; /* msec timestamp for last probe */ - u8 hw_maxretry_pktcnt; /* num packets since we got - HW max retry error */ - u8 max_valid_rate; /* maximum number of valid rate */ - u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */ - u32 per_down_time; /* msec timstamp for last - PER down step */ + struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; + int8_t rssi_last; + int8_t rssi_last_lookup; + int8_t rssi_last_prev; + int8_t rssi_last_prev2; + int32_t rssi_sum_cnt; + int32_t rssi_sum_rate; + int32_t rssi_sum; + u8 rate_table_size; + u8 probe_rate; + u32 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u8 hw_maxretry_pktcnt; + u8 max_valid_rate; + u8 valid_rate_index[MAX_TX_RATE_TBL]; + u32 per_down_time; /* 11n state */ - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */ - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; - u8 rc_phy_mode; - u8 rate_max_phy; /* Phy index for the max rate */ - u32 rate_max_lastused; /* msec timstamp of when we - last used rateMaxPhy */ - u32 probe_interval; /* interval for ratectrl to probe - for other rates */ + u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; + u8 rc_phy_mode; + u8 rate_max_phy; + u32 probe_interval; }; struct ath_rateset { @@ -248,29 +262,32 @@ struct ath_rateset { struct ath_rate_softc { /* phy tables that contain rate control data */ const void *hw_rate_table[ATH9K_MODE_MAX]; - int fixedrix; /* -1 or index of fixed rate */ + + /* -1 or index of fixed rate */ + int fixedrix; }; /* per-node state */ struct ath_rate_node { - struct ath_tx_ratectrl tx_ratectrl; /* rate control state proper */ - u32 prev_data_rix; /* rate idx of last data frame */ + struct ath_tx_ratectrl tx_ratectrl; - /* map of rate ix -> negotiated rate set ix */ - u8 rixmap[MAX_TX_RATE_TBL]; + /* rate idx of last data frame */ + u32 prev_data_rix; - /* map of ht rate ix -> negotiated rate set ix */ - u8 ht_rixmap[MAX_TX_RATE_TBL]; + /* ht capabilities */ + u8 ht_cap; - u8 ht_cap; /* ht capabilities */ - u8 ant_tx; /* current transmit antenna */ + /* When TRUE, only single stream Tx possible */ + u8 single_stream; - u8 single_stream; /* When TRUE, only single - stream Tx possible */ - struct ath_rateset neg_rates; /* Negotiated rates */ - struct ath_rateset neg_ht_rates; /* Negotiated HT rates */ - struct ath_rate_softc *asc; /* back pointer to atheros softc */ - struct ath_vap *avp; /* back pointer to vap */ + /* Negotiated rates */ + struct ath_rateset neg_rates; + + /* Negotiated HT rates */ + struct ath_rateset neg_ht_rates; + + struct ath_rate_softc *asc; + struct ath_vap *avp; }; /* Driver data of ieee80211_tx_info */ @@ -296,18 +313,11 @@ void ath_rate_detach(struct ath_rate_softc *asc); void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv); void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp); -/* - * Return the tx rate series. - */ -void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv, - int num_tries, int num_rates, - unsigned int rcflag, struct ath_rc_series[], - int *is_probe, int isretry); /* * Return rate index for given Dot11 Rate. */ u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11_rate); + u8 dot11_rate); /* Routines to register/unregister rate control algorithm */ int ath_rate_control_register(void); -- cgit v1.2.3 From de9cc7a4e6f975ca5e91cf8745b3e35a7e780bae Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 25 Aug 2008 14:06:32 -0700 Subject: libertas: use the common frame control functions Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/main.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 2c1d680d2c5..c948021bff6 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -477,9 +477,9 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) { struct ieee80211_rx_status stats; struct rxpd *prxpd; - bool is_qos, is_4addr, is_amsdu, need_padding; + int need_padding; unsigned int flags; - u16 fc, fc_le; + struct ieee80211_hdr *hdr; prxpd = (struct rxpd *) skb->data; @@ -497,19 +497,15 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) stats.rate_idx = prxpd->rx_rate; skb_pull(skb, sizeof(struct rxpd)); - fc_le = *((__le16 *) skb->data); - fc = le16_to_cpu(fc_le); + hdr = (struct ieee80211_hdr *)skb->data; flags = le32_to_cpu(*(__le32 *)(skb->data + 4)); - is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (fc & IEEE80211_STYPE_QOS_DATA); - is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); - is_amsdu = ((fc & 0x8C) == 0x88) && - (*(skb->data + ieee80211_hdrlen(fc_le) - QOS_CONTROL_LEN) - & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); + need_padding = ieee80211_is_data_qos(hdr->frame_control); + need_padding ^= ieee80211_has_a4(hdr->frame_control); + need_padding ^= ieee80211_is_data_qos(hdr->frame_control) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); - need_padding = is_qos ^ is_4addr ^ is_amsdu; if (need_padding) { memmove(skb->data + 2, skb->data, skb->len); skb_reserve(skb, 2); -- cgit v1.2.3 From 0262ab0df64a67d4c0ed7577a29b7d866819cc68 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:04:26 +0200 Subject: rt2x00: Fix race conditions in flag handling Some of the flags should be accessed atomically to prevent race conditions. The flags that are most important are those that can change often and indicate the actual state of the device, queue or queue entry. The big flag rename was done to move all state flags to the same naming type as the other rt2x00dev flags and made sure all places where the flags were used were changed. ;) Thanks to Stephen for most of the queue flags updates, which fixes some of the most obvious consequences of the race conditions. Among those the notorious: rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. Signed-off-by: Stephen Blackheath Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 16 ++++----- drivers/net/wireless/rt2x00/rt2x00config.c | 4 +-- drivers/net/wireless/rt2x00/rt2x00dev.c | 58 +++++++++++++++--------------- drivers/net/wireless/rt2x00/rt2x00mac.c | 26 +++++++------- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 ++-- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 6 ++-- drivers/net/wireless/rt2x00/rt2x00usb.c | 10 +++--- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- 11 files changed, 68 insertions(+), 66 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0107cec18b2..18b703c3fc2 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1241,7 +1241,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) if (!reg) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e0ff76ff490..5cc706a45e5 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1377,7 +1377,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) if (!reg) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3b90ed62214..c6be4dd81b1 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1297,7 +1297,7 @@ static void rt2500usb_beacondone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; - if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 3fa3d5b006a..08095bf3f8f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -629,14 +629,14 @@ enum rt2x00_flags { /* * Device state flags */ - DEVICE_PRESENT, - DEVICE_REGISTERED_HW, - DEVICE_INITIALIZED, - DEVICE_STARTED, - DEVICE_STARTED_SUSPEND, - DEVICE_ENABLED_RADIO, - DEVICE_DISABLED_RADIO_HW, - DEVICE_DIRTY_CONFIG, + DEVICE_STATE_PRESENT, + DEVICE_STATE_REGISTERED_HW, + DEVICE_STATE_INITIALIZED, + DEVICE_STATE_STARTED, + DEVICE_STATE_STARTED_SUSPEND, + DEVICE_STATE_ENABLED_RADIO, + DEVICE_STATE_DISABLED_RADIO_HW, + DEVICE_STATE_DIRTY_CONFIG, /* * Driver requirements diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index ea37c796204..ca051f50ef1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -121,7 +121,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * Antenna setup changes require the RX to be disabled, * else the changes will be ignored by the device. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); /* @@ -136,7 +136,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00dev->link.ant.active.rx = libconf.ant.rx; rt2x00dev->link.ant.active.tx = libconf.ant.tx; - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 328ff8bc4c1..330ab77902f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -34,7 +34,7 @@ */ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -94,8 +94,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * Don't enable the radio twice. * And check if the hardware button has been disabled. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || + test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags)) return 0; /* @@ -117,7 +117,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00leds_led_radio(rt2x00dev, true); rt2x00led_led_activity(rt2x00dev, true); - __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); + set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); /* * Enable RX. @@ -134,7 +134,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) { - if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -354,7 +354,7 @@ static void rt2x00lib_link_tuner(struct work_struct *work) * When the radio is shutting down we should * immediately cease all link tuning. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -431,7 +431,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, * note that in the spinlock protected area above the delayed_flags * have been cleared correctly. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; if (delayed_flags & DELAYED_UPDATE_BEACON) @@ -484,7 +484,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, @@ -572,7 +572,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); - __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* @@ -888,7 +888,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) { - if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) { @@ -906,6 +906,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) struct hw_mode_spec *spec = &rt2x00dev->spec; int status; + if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) + return 0; + /* * Initialize HW modes. */ @@ -927,7 +930,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); + set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags); return 0; } @@ -937,7 +940,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) */ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) { - if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) return; /* @@ -960,7 +963,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) { int status; - if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) return 0; /* @@ -979,7 +982,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); + set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags); /* * Register the extra components. @@ -993,7 +996,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) { int retval; - if (test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return 0; /* @@ -1024,15 +1027,15 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; - __set_bit(DEVICE_STARTED, &rt2x00dev->flags); - __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); + set_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); return 0; } void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return; /* @@ -1044,8 +1047,6 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; - - __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } /* @@ -1100,7 +1101,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); return 0; @@ -1113,7 +1114,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { - __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * Disable radio. @@ -1158,14 +1159,15 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); - __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Only continue if mac80211 has open interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) goto exit; - __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); + + set_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags); /* * Disable radio. @@ -1237,7 +1239,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Only continue if mac80211 had open interfaces. */ - if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags)) return 0; /* @@ -1264,7 +1266,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * We are ready again to receive requests from mac80211. */ - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * It is possible that during that mac80211 has attempted @@ -1284,7 +1286,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) return 0; exit: - rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_stop(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3af42733941..11be8957b5c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -117,7 +117,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * Note that we can only stop the TX queues inside the TX path * due to possible race conditions in mac80211. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) goto exit_fail; /* @@ -175,7 +175,7 @@ int rt2x00mac_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; return rt2x00lib_start(rt2x00dev); @@ -186,7 +186,7 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return; rt2x00lib_stop(rt2x00dev); @@ -206,8 +206,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * Don't allow interfaces to be added * the device has disappeared. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - !test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; switch (conf->type) { @@ -256,7 +256,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, */ for (i = 0; i < queue->limit; i++) { entry = &queue->entries[i]; - if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) + if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) break; } @@ -310,7 +310,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * either the device has disappeared or when * no interface is present. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) return; @@ -324,7 +324,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * Release beacon entry so it is available for * new interfaces again. */ - __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); + clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); /* * Make sure the bssid and mac address registers @@ -344,14 +344,14 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; /* * Check if we need to disable the radio, * if this is not the case, at least the RX must be disabled. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { if (!conf->radio_enabled) rt2x00lib_disable_radio(rt2x00dev); else @@ -366,14 +366,14 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * initialized. */ force_reconfig = - __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + test_and_clear_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); rt2x00lib_config(rt2x00dev, conf, force_reconfig); /* * Reenable RX only if the radio should be on. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); else if (conf->radio_enabled) return rt2x00lib_enable_radio(rt2x00dev); @@ -395,7 +395,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; spin_lock(&intf->lock); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index c0f97c53e5c..d10a8012f38 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -356,7 +356,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) if (unlikely(rt2x00queue_full(queue))) return -EINVAL; - if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", @@ -396,7 +396,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) * the frame to mac80211 because the skb->cb has now been tainted. */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { - __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); dev_kfree_skb_any(entry->skb); entry->skb = NULL; return 0; @@ -405,7 +405,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) rt2x00queue_map_txskb(queue->rt2x00dev, skb); - __set_bit(ENTRY_DATA_PENDING, &entry->flags); + set_bit(ENTRY_DATA_PENDING, &entry->flags); rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 04b29716d35..8a2fefb365b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -41,16 +41,16 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) /* * Only continue if there are enabled interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return 0; if (state == RFKILL_STATE_UNBLOCKED) { INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); - __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); } else if (state == RFKILL_STATE_SOFT_BLOCKED) { INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); - __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); + set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); } else { WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 2050227ea53..2dd7c830c12 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -163,7 +163,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct txdone_entry_desc txdesc; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; @@ -232,7 +232,7 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) { struct queue_entry_priv_usb *entry_priv = entry->priv_data; - if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } @@ -283,7 +283,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u8 rxd[32]; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; @@ -293,7 +293,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * a problem. */ if (urb->actual_length < entry->queue->desc_size || urb->status) { - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(urb, GFP_ATOMIC); return; } @@ -361,7 +361,7 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 23cf93dfda0..9d27ce0e54f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2121,7 +2121,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) if (!reg && !reg_mcu) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* -- cgit v1.2.3 From 3ee54a07d34fd9b5c34bb1488113fb32be58e38f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:04:50 +0200 Subject: rt2x00: Map extra_tx_headroom to DMA If a driver requests additional headroom it should be mapped to DMA as well because it will be send to the hardware as well (as form of extra descriptor). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index d10a8012f38..2822684c505 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -100,8 +100,21 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, - DMA_TO_DEVICE); + /* + * If device has requested headroom, we should make sure that + * is also mapped to the DMA so it can be used for transfering + * additional descriptor information to the hardware. + */ + skb_push(skb, rt2x00dev->hw->extra_tx_headroom); + + skbdesc->skb_dma = + dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); + + /* + * Restore data pointer to original location again. + */ + skb_pull(skb, rt2x00dev->hw->extra_tx_headroom); + skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; } EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); @@ -117,7 +130,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) } if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + /* + * Add headroom to the skb length, it has been removed + * by the driver, but it was actually mapped to DMA. + */ + dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, + skb->len + rt2x00dev->hw->extra_tx_headroom, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; } -- cgit v1.2.3 From 2575c11d6ee7266f0f035e55c5056b36597cd336 Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Fri, 29 Aug 2008 21:05:21 +0200 Subject: rt2x00: Only configure hardware when radio is enabled Some hardware configuration registers such as antenna and channel configuration can only be written when the radio is enabled. Previously, we didn't consider this, so some configuration items could be set inconsistently after reenabling the radio. This patch changes the config() handler to only reprogram the hardware when the radio is enabled. Configuration changes that are made while the radio is off are postponed until the radio is switched back on. We also leave the radio turned off during initialization and only enable it when requested by mac80211. This allows us to get rid of the DIRTY_CONFIG flag, because the device is now guaranteed to be completely initialized when brought up by mac80211. Signed-off-by: Mattias Nissler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 - drivers/net/wireless/rt2x00/rt2x00dev.c | 10 ------- drivers/net/wireless/rt2x00/rt2x00mac.c | 50 ++++++++++++++++----------------- 3 files changed, 25 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 08095bf3f8f..5e4f783345a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -636,7 +636,6 @@ enum rt2x00_flags { DEVICE_STATE_STARTED_SUSPEND, DEVICE_STATE_ENABLED_RADIO, DEVICE_STATE_DISABLED_RADIO_HW, - DEVICE_STATE_DIRTY_CONFIG, /* * Driver requirements diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 330ab77902f..5278ae2e374 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1014,21 +1014,11 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) if (retval) return retval; - /* - * Enable radio. - */ - retval = rt2x00lib_enable_radio(rt2x00dev); - if (retval) { - rt2x00lib_uninitialize(rt2x00dev); - return retval; - } - rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); - set_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 11be8957b5c..64292c227c9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -338,7 +338,8 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - int force_reconfig; + int radio_on; + int status; /* * Mac80211 might be calling this function while we are trying @@ -348,35 +349,34 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return 0; /* - * Check if we need to disable the radio, - * if this is not the case, at least the RX must be disabled. + * Only change device state when the radio is enabled. It does not + * matter what parameters we have configured when the radio is disabled + * because we won't be able to send or receive anyway. Also note that + * some configuration parameters (e.g. channel and antenna values) can + * only be set when the radio is enabled. */ - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { - if (!conf->radio_enabled) - rt2x00lib_disable_radio(rt2x00dev); - else - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - } + radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); + if (conf->radio_enabled) { + /* For programming the values, we have to turn RX off */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - /* - * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently - * been started and the configuration must be forced upon the hardware. - * Otherwise registers will not be intialized correctly and could - * result in non-working hardware because essential registers aren't - * initialized. - */ - force_reconfig = - test_and_clear_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); + /* Enable the radio */ + status = rt2x00lib_enable_radio(rt2x00dev); + if (unlikely(status)) + return status; - rt2x00lib_config(rt2x00dev, conf, force_reconfig); + /* + * When we've just turned on the radio, we want to reprogram + * everything to ensure a consistent state + */ + rt2x00lib_config(rt2x00dev, conf, !radio_on); - /* - * Reenable RX only if the radio should be on. - */ - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - else if (conf->radio_enabled) - return rt2x00lib_enable_radio(rt2x00dev); + } else { + /* Disable the radio */ + rt2x00lib_disable_radio(rt2x00dev); + } return 0; } -- cgit v1.2.3 From 2af0a570b45ec315f364ea2c8a6d072cfcaa9d32 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:05:45 +0200 Subject: rt2x00: Initialize txop during conf_tx() callback The txop parameter is supported by rt61pci and rt73usb, and thus should be written to the register instead of using the fixed value set during initialization. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 5 ++- drivers/net/wireless/rt2x00/rt2x00queue.c | 1 + drivers/net/wireless/rt2x00/rt2x00queue.h | 2 + drivers/net/wireless/rt2x00/rt61pci.c | 69 ++++++++++++++++++++++++++----- drivers/net/wireless/rt2x00/rt73usb.c | 69 ++++++++++++++++++++++++++----- 5 files changed, 122 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 64292c227c9..56829fad347 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -666,10 +666,11 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, queue->cw_max = 10; /* cw_min: 2^10 = 1024. */ queue->aifs = params->aifs; + queue->txop = params->txop; INFO(rt2x00dev, - "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", - queue_idx, queue->cw_min, queue->cw_max, queue->aifs); + "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", + queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2822684c505..a5e965068c8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -736,6 +736,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, queue->rt2x00dev = rt2x00dev; queue->qid = qid; + queue->txop = 0; queue->aifs = 2; queue->cw_min = 5; queue->cw_max = 10; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 37f3f98d58a..654fa0c624d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -368,6 +368,7 @@ enum queue_index { * @length: Number of frames in queue. * @index: Index pointers to entry positions in the queue, * use &enum queue_index to get a specific index field. + * @txop: maximum burst time. * @aifs: The aifs value for outgoing frames (field ignored in RX queue). * @cw_min: The cw min value for outgoing frames (field ignored in RX queue). * @cw_max: The cw max value for outgoing frames (field ignored in RX queue). @@ -387,6 +388,7 @@ struct data_queue { unsigned short length; unsigned short index[Q_INDEX_MAX]; + unsigned short txop; unsigned short aifs; unsigned short cw_min; unsigned short cw_max; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 9d27ce0e54f..52537101c90 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1478,16 +1478,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - /* * Clear all beacons * For the Beacon base registers we only need to clear @@ -2652,6 +2642,63 @@ static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + if (queue_idx < 2) { + field.bit_offset = queue_idx * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + } else if (queue_idx < 4) { + field.bit_offset = (queue_idx - 2) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2x00pci_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2x00pci_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2x00pci_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2679,7 +2726,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index f58fd059c9a..636b4e0d0ef 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1277,16 +1277,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -2246,6 +2236,63 @@ static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + if (queue_idx < 2) { + field.bit_offset = queue_idx * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + } else if (queue_idx < 4) { + field.bit_offset = (queue_idx - 2) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + #if 0 /* * Mac80211 demands get_tsf must be atomic. @@ -2283,7 +2330,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, }; -- cgit v1.2.3 From 6c6aa3c004e702532cb0f549a96eb2f75636bd3b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:07:16 +0200 Subject: rt2x00: Add Signal type flag Instead of using the PLCP flag to indicate if the signal value is plcp or the bitrate we should add a new flag to mark the bitrate type explicitely. This is usefull when new types are added later for rt2800. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500pci.c | 2 ++ drivers/net/wireless/rt2x00/rt2500usb.c | 2 ++ drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.h | 7 ++++--- drivers/net/wireless/rt2x00/rt61pci.c | 2 ++ drivers/net/wireless/rt2x00/rt73usb.c | 2 ++ 6 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 5cc706a45e5..2a96a011f2a 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1316,6 +1316,8 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c6be4dd81b1..c5f49e36559 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1280,6 +1280,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5278ae2e374..369b0b2d864 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -653,7 +653,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && (rate->plcp == rxdesc.signal)) || - (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && + ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) && (rate->bitrate == rxdesc.signal))) { idx = i; break; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 654fa0c624d..9dbf04f0f04 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -140,13 +140,14 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) /** * enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc * - * @RXDONE_SIGNAL_PLCP: Does the signal field contain the plcp value, - * or does it contain the bitrate itself. + * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. + * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, - RXDONE_MY_BSS = 1 << 1, + RXDONE_SIGNAL_BITRATE = 1 << 1, + RXDONE_MY_BSS = 1 << 2, }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 52537101c90..d740f560ccd 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1991,6 +1991,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 636b4e0d0ef..cf236ec533a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1766,6 +1766,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; -- cgit v1.2.3 From 1abc3656e961e62218257a85b3fe0a90ccd9036c Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Fri, 29 Aug 2008 21:07:20 +0200 Subject: rt2x00: skb->data pointer should not include TX descriptor Make sure the skb->data pointer points to the frame data, not the TX descriptor. The frame dumping code relies on that. Signed-off-by: Mattias Nissler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00usb.c | 11 ++++++----- drivers/net/wireless/rt2x00/rt73usb.c | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c5f49e36559..0e008b606f7 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1114,8 +1114,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 2dd7c830c12..b73a7e0aeed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -167,11 +167,6 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; - /* - * Remove the descriptor data from the buffer. - */ - skb_pull(entry->skb, entry->queue->desc_size); - /* * Obtain the status about this packet. * Note that when the status is 0 it does not mean the @@ -224,6 +219,12 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry) entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); + /* + * Make sure the skb->data pointer points to the frame, not the + * descriptor. + */ + skb_pull(entry->skb, entry->queue->desc_size); + return 0; } EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cf236ec533a..e698ae0efbc 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1556,8 +1556,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); -- cgit v1.2.3 From 35e032d82f3e2a9b0d92077b4fbc97166525ed53 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:07:22 +0200 Subject: rt2x00: Release rt2x00 2.2.1 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5e4f783345a..6f296cef76a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.2.0" +#define DRV_VERSION "2.2.1" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.2.3 From ef1a628d83fc0423c36e773281162be790503168 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 27 Aug 2008 18:53:02 +0200 Subject: b43: Implement dynamic PHY API This patch implements a dynamic "ops" based PHY API. This is needed in order to conveniently support future PHY types to avoid the "switch"-hell. This patch does not change any functionality. It just moves lots of code from one place to another and adjusts it for the changed data structures. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Makefile | 4 +- drivers/net/wireless/b43/b43.h | 127 +- drivers/net/wireless/b43/debugfs.c | 79 +- drivers/net/wireless/b43/lo.c | 120 +- drivers/net/wireless/b43/lo.h | 4 +- drivers/net/wireless/b43/main.c | 172 +- drivers/net/wireless/b43/nphy.c | 143 +- drivers/net/wireless/b43/nphy.h | 54 +- drivers/net/wireless/b43/phy.c | 3937 +++----------------------------- drivers/net/wireless/b43/phy.h | 340 --- drivers/net/wireless/b43/phy_a.c | 536 +++++ drivers/net/wireless/b43/phy_a.h | 124 + drivers/net/wireless/b43/phy_common.c | 276 +++ drivers/net/wireless/b43/phy_common.h | 312 +++ drivers/net/wireless/b43/phy_g.c | 3229 ++++++++++++++++++++++++++ drivers/net/wireless/b43/phy_g.h | 201 ++ drivers/net/wireless/b43/rfkill.c | 5 +- drivers/net/wireless/b43/sysfs.c | 23 +- drivers/net/wireless/b43/tables.c | 43 +- drivers/net/wireless/b43/tables_nphy.c | 2 +- drivers/net/wireless/b43/wa.c | 2 +- drivers/net/wireless/b43/xmit.c | 6 +- 22 files changed, 5256 insertions(+), 4483 deletions(-) delete mode 100644 drivers/net/wireless/b43/phy.h create mode 100644 drivers/net/wireless/b43/phy_a.c create mode 100644 drivers/net/wireless/b43/phy_a.h create mode 100644 drivers/net/wireless/b43/phy_common.c create mode 100644 drivers/net/wireless/b43/phy_common.h create mode 100644 drivers/net/wireless/b43/phy_g.c create mode 100644 drivers/net/wireless/b43/phy_g.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 8c52b0b9862..fb6ffce03f0 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,7 +1,9 @@ b43-y += main.o b43-y += tables.o b43-$(CONFIG_B43_NPHY) += tables_nphy.o -b43-y += phy.o +b43-y += phy_common.o +b43-y += phy_g.o +b43-y += phy_a.o b43-$(CONFIG_B43_NPHY) += nphy.o b43-y += sysfs.o b43-y += xmit.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index edcdfa36645..fc280157596 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -12,7 +12,7 @@ #include "leds.h" #include "rfkill.h" #include "lo.h" -#include "phy.h" +#include "phy_common.h" /* The unique identifier of the firmware that's officially supported by @@ -508,122 +508,6 @@ struct b43_iv { } __attribute__((__packed__)); -struct b43_phy { - /* Band support flags. */ - bool supports_2ghz; - bool supports_5ghz; - - /* GMODE bit enabled? */ - bool gmode; - - /* Analog Type */ - u8 analog; - /* B43_PHYTYPE_ */ - u8 type; - /* PHY revision number. */ - u8 rev; - - /* Radio versioning */ - u16 radio_manuf; /* Radio manufacturer */ - u16 radio_ver; /* Radio version */ - u8 radio_rev; /* Radio revision */ - - bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ - - /* ACI (adjacent channel interference) flags. */ - bool aci_enable; - bool aci_wlan_automatic; - bool aci_hw_rssi; - - /* Radio switched on/off */ - bool radio_on; - struct { - /* Values saved when turning the radio off. - * They are needed when turning it on again. */ - bool valid; - u16 rfover; - u16 rfoverval; - } radio_off_context; - - u16 minlowsig[2]; - u16 minlowsigpos[2]; - - /* TSSI to dBm table in use */ - const s8 *tssi2dbm; - /* Target idle TSSI */ - int tgt_idle_tssi; - /* Current idle TSSI */ - int cur_idle_tssi; - - /* LocalOscillator control values. */ - struct b43_txpower_lo_control *lo_control; - /* Values from b43_calc_loopback_gain() */ - s16 max_lb_gain; /* Maximum Loopback gain in hdB */ - s16 trsw_rx_gain; /* TRSW RX gain in hdB */ - s16 lna_lod_gain; /* LNA lod */ - s16 lna_gain; /* LNA */ - s16 pga_gain; /* PGA */ - - /* Desired TX power level (in dBm). - * This is set by the user and adjusted in b43_phy_xmitpower(). */ - u8 power_level; - /* A-PHY TX Power control value. */ - u16 txpwr_offset; - - /* Current TX power level attenuation control values */ - struct b43_bbatt bbatt; - struct b43_rfatt rfatt; - u8 tx_control; /* B43_TXCTL_XXX */ - - /* Hardware Power Control enabled? */ - bool hardware_power_control; - - /* Current Interference Mitigation mode */ - int interfmode; - /* Stack of saved values from the Interference Mitigation code. - * Each value in the stack is layed out as follows: - * bit 0-11: offset - * bit 12-15: register ID - * bit 16-32: value - * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT - */ -#define B43_INTERFSTACK_SIZE 26 - u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure - - /* Saved values from the NRSSI Slope calculation */ - s16 nrssi[2]; - s32 nrssislope; - /* In memory nrssi lookup table. */ - s8 nrssi_lt[64]; - - /* current channel */ - u8 channel; - - u16 lofcal; - - u16 initval; //FIXME rename? - - /* PHY TX errors counter. */ - atomic_t txerr_cnt; - - /* The device does address auto increment for the OFDM tables. - * We cache the previously used address here and omit the address - * write on the next table access, if possible. */ - u16 ofdmtab_addr; /* The address currently set in hardware. */ - enum { /* The last data flow direction. */ - B43_OFDMTAB_DIRECTION_UNKNOWN = 0, - B43_OFDMTAB_DIRECTION_READ, - B43_OFDMTAB_DIRECTION_WRITE, - } ofdmtab_addr_direction; - -#if B43_DEBUG - /* Manual TX-power control enabled? */ - bool manual_txpower_control; - /* PHY registers locked by b43_phy_lock()? */ - bool phy_locked; -#endif /* B43_DEBUG */ -}; - /* Data structures for DMA transmission, per 80211 core. */ struct b43_dma { struct b43_dmaring *tx_ring_AC_BK; /* Background */ @@ -908,6 +792,15 @@ static inline int b43_is_mode(struct b43_wl *wl, int type) return (wl->operating && wl->if_type == type); } +/** + * b43_current_band - Returns the currently used band. + * Returns one of IEEE80211_BAND_2GHZ and IEEE80211_BAND_5GHZ. + */ +static inline enum ieee80211_band b43_current_band(struct b43_wl *wl) +{ + return wl->hw->conf.channel->band; +} + static inline u16 b43_read16(struct b43_wldev *dev, u16 offset) { return ssb_read16(dev->dev, offset); diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 29851bc1101..06a01da8016 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -443,76 +443,6 @@ out_unlock: return count; } -static ssize_t txpower_g_read_file(struct b43_wldev *dev, - char *buf, size_t bufsize) -{ - ssize_t count = 0; - - if (dev->phy.type != B43_PHYTYPE_G) { - fappend("Device is not a G-PHY\n"); - goto out; - } - fappend("Control: %s\n", dev->phy.manual_txpower_control ? - "MANUAL" : "AUTOMATIC"); - fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); - fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); - fappend("TX Mixer Gain: %s\n", - (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF"); - fappend("PA Gain 2dB: %s\n", - (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF"); - fappend("PA Gain 3dB: %s\n", - (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF"); - fappend("\n\n"); - fappend("You can write to this file:\n"); - fappend("Writing \"auto\" enables automatic txpower control.\n"); - fappend - ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " - "enables manual txpower control.\n"); - fappend("Example: 5 4 0 0 1\n"); - fappend("Enables manual control with Baseband attenuation 5, " - "Radio attenuation 4, No TX Mixer Gain, " - "No PA Gain 2dB, With PA Gain 3dB.\n"); -out: - return count; -} - -static int txpower_g_write_file(struct b43_wldev *dev, - const char *buf, size_t count) -{ - if (dev->phy.type != B43_PHYTYPE_G) - return -ENODEV; - if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { - /* Automatic control */ - dev->phy.manual_txpower_control = 0; - b43_phy_xmitpower(dev); - } else { - int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; - /* Manual control */ - if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, - &txmix, &pa2db, &pa3db) != 5) - return -EINVAL; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - dev->phy.manual_txpower_control = 1; - dev->phy.bbatt.att = bbatt; - dev->phy.rfatt.att = rfatt; - dev->phy.tx_control = 0; - if (txmix) - dev->phy.tx_control |= B43_TXCTL_TXMIX; - if (pa2db) - dev->phy.tx_control |= B43_TXCTL_PA2DB; - if (pa3db) - dev->phy.tx_control |= B43_TXCTL_PA3DB; - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &dev->phy.bbatt, - &dev->phy.rfatt, dev->phy.tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - } - - return 0; -} - /* wl->irq_lock is locked */ static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) @@ -560,7 +490,7 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, err = -ENODEV; goto out; } - lo = phy->lo_control; + lo = phy->g->lo_control; fappend("-- Local Oscillator calibration data --\n\n"); fappend("HW-power-control enabled: %d\n", dev->phy.hardware_power_control); @@ -578,8 +508,8 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, list_for_each_entry(cal, &lo->calib_list, list) { bool active; - active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && - b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); + active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt)); fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " "(expires in %lu sec)%s\n", cal->bbatt.att, @@ -763,7 +693,6 @@ B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); -B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); @@ -877,7 +806,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) ADD_FILE(mmio32write, 0200); ADD_FILE(tsf, 0600); ADD_FILE(txstat, 0400); - ADD_FILE(txpower_g, 0600); ADD_FILE(restart, 0200); ADD_FILE(loctls, 0400); @@ -907,7 +835,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) debugfs_remove(e->file_mmio32write.dentry); debugfs_remove(e->file_tsf.dentry); debugfs_remove(e->file_txstat.dentry); - debugfs_remove(e->file_txpower_g.dentry); debugfs_remove(e->file_restart.dentry); debugfs_remove(e->file_loctls.dentry); diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 9c854d6aae3..6a18a147046 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -29,7 +29,7 @@ #include "b43.h" #include "lo.h" -#include "phy.h" +#include "phy_g.h" #include "main.h" #include @@ -174,7 +174,8 @@ static u16 lo_txctl_register_table(struct b43_wldev *dev, static void lo_measure_txctl_values(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 reg, mask; u16 trsw_rx, pga; u16 radio_pctl_reg; @@ -195,7 +196,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) int lb_gain; /* Loopback gain (in dB) */ trsw_rx = 0; - lb_gain = phy->max_lb_gain / 2; + lb_gain = gphy->max_lb_gain / 2; if (lb_gain > 10) { radio_pctl_reg = 0; pga = abs(10 - lb_gain) / 6; @@ -226,7 +227,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) } b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) & 0xFFF0) | radio_pctl_reg); - b43_phy_set_baseband_attenuation(dev, 2); + b43_gphy_set_baseband_attenuation(dev, 2); reg = lo_txctl_register_table(dev, &mask, NULL); mask = ~mask; @@ -277,7 +278,8 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) static void lo_read_power_vector(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; int i; u64 tmp; u64 power_vector = 0; @@ -298,6 +300,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, s16 max_rx_gain, int use_trsw_rx) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp; if (max_rx_gain < 0) @@ -308,7 +311,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, int trsw_rx_gain; if (use_trsw_rx) { - trsw_rx_gain = phy->trsw_rx_gain / 2; + trsw_rx_gain = gphy->trsw_rx_gain / 2; if (max_rx_gain >= trsw_rx_gain) { trsw_rx_gain = max_rx_gain - trsw_rx_gain; trsw_rx = 0x20; @@ -316,38 +319,38 @@ static void lo_measure_gain_values(struct b43_wldev *dev, } else trsw_rx_gain = max_rx_gain; if (trsw_rx_gain < 9) { - phy->lna_lod_gain = 0; + gphy->lna_lod_gain = 0; } else { - phy->lna_lod_gain = 1; + gphy->lna_lod_gain = 1; trsw_rx_gain -= 8; } trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); - phy->pga_gain = trsw_rx_gain / 3; - if (phy->pga_gain >= 5) { - phy->pga_gain -= 5; - phy->lna_gain = 2; + gphy->pga_gain = trsw_rx_gain / 3; + if (gphy->pga_gain >= 5) { + gphy->pga_gain -= 5; + gphy->lna_gain = 2; } else - phy->lna_gain = 0; + gphy->lna_gain = 0; } else { - phy->lna_gain = 0; - phy->trsw_rx_gain = 0x20; + gphy->lna_gain = 0; + gphy->trsw_rx_gain = 0x20; if (max_rx_gain >= 0x14) { - phy->lna_lod_gain = 1; - phy->pga_gain = 2; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 2; } else if (max_rx_gain >= 0x12) { - phy->lna_lod_gain = 1; - phy->pga_gain = 1; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 1; } else if (max_rx_gain >= 0xF) { - phy->lna_lod_gain = 1; - phy->pga_gain = 0; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 0; } else { - phy->lna_lod_gain = 0; - phy->pga_gain = 0; + gphy->lna_lod_gain = 0; + gphy->pga_gain = 0; } } tmp = b43_radio_read16(dev, 0x7A); - if (phy->lna_lod_gain == 0) + if (gphy->lna_lod_gain == 0) tmp &= ~0x0008; else tmp |= 0x0008; @@ -392,10 +395,11 @@ static void lo_measure_setup(struct b43_wldev *dev, { struct ssb_sprom *sprom = &dev->dev->bus->sprom; struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 tmp; - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); @@ -496,7 +500,7 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) b43_dummy_transmission(dev); - b43_radio_selectchannel(dev, 6, 0); + b43_gphy_channel_switch(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); @@ -520,18 +524,19 @@ static void lo_measure_restore(struct b43_wldev *dev, struct lo_g_saved_values *sav) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp; if (phy->rev >= 2) { b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); - tmp = (phy->pga_gain << 8); + tmp = (gphy->pga_gain << 8); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); udelay(5); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); udelay(2); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); } else { - tmp = (phy->pga_gain | 0xEFA0); + tmp = (gphy->pga_gain | 0xEFA0); b43_phy_write(dev, B43_PHY_PGACTL, tmp); } if (phy->type == B43_PHYTYPE_G) { @@ -572,7 +577,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); } - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { tmp = (sav->phy_lo_mask & 0xBFFF); b43_phy_write(dev, B43_PHY_LO_MASK, tmp); b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); @@ -580,7 +585,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); } - b43_radio_selectchannel(dev, sav->old_channel, 1); + b43_gphy_channel_switch(dev, sav->old_channel, 1); } struct b43_lo_g_statemachine { @@ -597,6 +602,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, struct b43_lo_g_statemachine *d) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_loctl test_loctl; struct b43_loctl orig_loctl; struct b43_loctl prev_loctl = { @@ -646,9 +652,9 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, test_loctl.q != prev_loctl.q) && (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { b43_lo_write(dev, &test_loctl); - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); if (feedth < d->lowest_feedth) { memcpy(probe_loctl, &test_loctl, sizeof(struct b43_loctl)); @@ -677,6 +683,7 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, int *max_rx_gain) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_lo_g_statemachine d; u16 feedth; int found_lower; @@ -693,17 +700,17 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, max_repeat = 4; do { b43_lo_write(dev, &d.min_loctl); - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); if (feedth < 0x258) { if (feedth >= 0x12C) *max_rx_gain += 6; else *max_rx_gain += 3; - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); } d.lowest_feedth = feedth; @@ -752,6 +759,7 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, const struct b43_rfatt *rfatt) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_loctl loctl = { .i = 0, .q = 0, @@ -782,11 +790,11 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, if (rfatt->with_padmix) max_rx_gain -= pad_mix_gain; if (has_loopback_gain(phy)) - max_rx_gain += phy->max_lb_gain; + max_rx_gain += gphy->max_lb_gain; lo_measure_gain_values(dev, max_rx_gain, has_loopback_gain(phy)); - b43_phy_set_baseband_attenuation(dev, bbatt->att); + b43_gphy_set_baseband_attenuation(dev, bbatt->att); lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); lo_measure_restore(dev, &saved_regs); @@ -820,7 +828,7 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, const struct b43_bbatt *bbatt, const struct b43_rfatt *rfatt) { - struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; struct b43_lo_calib *c; c = b43_find_lo_calib(lo, bbatt, rfatt); @@ -839,7 +847,8 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; int i; int rf_offset, bb_offset; const struct b43_rfatt *rfatt; @@ -917,14 +926,14 @@ static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) void b43_lo_g_adjust(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; struct b43_lo_calib *cal; struct b43_rfatt rf; - memcpy(&rf, &phy->rfatt, sizeof(rf)); + memcpy(&rf, &gphy->rfatt, sizeof(rf)); b43_lo_fixup_rfatt(&rf); - cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); + cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf); if (!cal) return; b43_lo_write(dev, &cal->ctl); @@ -952,7 +961,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, void b43_lo_g_maintanance_work(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; unsigned long now; unsigned long expire; struct b43_lo_calib *cal, *tmp; @@ -962,7 +972,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (!lo) return; now = jiffies; - hwpctl = b43_has_hardware_pctl(phy); + hwpctl = b43_has_hardware_pctl(dev); if (hwpctl) { /* Read the power vector and update it, if needed. */ @@ -983,8 +993,8 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (!time_before(cal->calib_time, expire)) continue; /* This item expired. */ - if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && - b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { + if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) { B43_WARN_ON(current_item_expired); current_item_expired = 1; } @@ -1002,7 +1012,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) /* Recalibrate currently used LO setting. */ if (b43_debug(dev, B43_DBG_LO)) b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); - cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); + cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt); if (cal) { list_add(&cal->list, &lo->calib_list); b43_lo_write(dev, &cal->ctl); @@ -1013,7 +1023,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) void b43_lo_g_cleanup(struct b43_wldev *dev) { - struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; struct b43_lo_calib *cal, *tmp; if (!lo) @@ -1027,9 +1037,7 @@ void b43_lo_g_cleanup(struct b43_wldev *dev) /* LO Initialization */ void b43_lo_g_init(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { lo_read_power_vector(dev); b43_gphy_dc_lt_init(dev, 1); } diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 1da321cabc1..3b27e20eff8 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -1,7 +1,9 @@ #ifndef B43_LO_H_ #define B43_LO_H_ -#include "phy.h" +/* G-PHY Local Oscillator */ + +#include "phy_g.h" struct b43_wldev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7205a936ec7..af43f03b318 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -44,7 +44,8 @@ #include "b43.h" #include "main.h" #include "debugfs.h" -#include "phy.h" +#include "phy_common.h" +#include "phy_g.h" #include "nphy.h" #include "dma.h" #include "pio.h" @@ -1174,6 +1175,8 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) { /* Top half of Link Quality calculation. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; if (dev->noisecalc.calculation_running) return; dev->noisecalc.calculation_running = 1; @@ -1184,7 +1187,7 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) static void handle_irq_noise(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *phy = dev->phy.g; u16 tmp; u8 noise[4]; u8 i, j; @@ -1192,6 +1195,9 @@ static void handle_irq_noise(struct b43_wldev *dev) /* Bottom half of Link Quality calculation. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; + /* Possible race condition: It might be possible that the user * changed to a different channel in the meantime since we * started the calculation. We ignore that fact, since it's @@ -2688,9 +2694,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { - b43_radio_turn_off(dev, 1); b43_gpio_cleanup(dev); - b43_lo_g_cleanup(dev); /* firmware is released later */ } @@ -2700,7 +2704,7 @@ static void b43_chip_exit(struct b43_wldev *dev) static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - int err, tmp; + int err; u32 value32, macctl; u16 value16; @@ -2725,19 +2729,19 @@ static int b43_chip_init(struct b43_wldev *dev) err = b43_upload_initvals(dev); if (err) goto err_gpio_clean; - b43_radio_turn_on(dev); b43_write16(dev, 0x03E6, 0x0000); err = b43_phy_init(dev); if (err) - goto err_radio_off; + goto err_gpio_clean; - /* Select initial Interference Mitigation. */ - tmp = phy->interfmode; - phy->interfmode = B43_INTERFMODE_NONE; - b43_radio_set_interference_mitigation(dev, tmp); + /* Disable Interference Mitigation. */ + if (phy->ops->interf_mitigation) + phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); - b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT); + /* Select the antennae */ + if (phy->ops->set_rx_antenna) + phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT); b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT); if (phy->type == B43_PHYTYPE_B) { @@ -2790,8 +2794,6 @@ static int b43_chip_init(struct b43_wldev *dev) out: return err; -err_radio_off: - b43_radio_turn_off(dev, 1); err_gpio_clean: b43_gpio_cleanup(dev); return err; @@ -2799,25 +2801,10 @@ err_gpio_clean: static void b43_periodic_every60sec(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + const struct b43_phy_operations *ops = dev->phy.ops; - if (phy->type != B43_PHYTYPE_G) - return; - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_mac_suspend(dev); - b43_calc_nrssi_slope(dev); - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { - u8 old_chan = phy->channel; - - /* VCO Calibration */ - if (old_chan >= 8) - b43_radio_selectchannel(dev, 1, 0); - else - b43_radio_selectchannel(dev, 13, 0); - b43_radio_selectchannel(dev, old_chan, 0); - } - b43_mac_enable(dev); - } + if (ops->pwork_60sec) + ops->pwork_60sec(dev); } static void b43_periodic_every30sec(struct b43_wldev *dev) @@ -2845,32 +2832,10 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } } - if (phy->type == B43_PHYTYPE_G) { - //TODO: update_aci_moving_average - if (phy->aci_enable && phy->aci_wlan_automatic) { - b43_mac_suspend(dev); - if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) { - if (0 /*TODO: bunch of conditions */ ) { - b43_radio_set_interference_mitigation - (dev, B43_INTERFMODE_MANUALWLAN); - } - } else if (1 /*TODO*/) { - /* - if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) { - b43_radio_set_interference_mitigation(dev, - B43_INTERFMODE_NONE); - } - */ - } - b43_mac_enable(dev); - } else if (phy->interfmode == B43_INTERFMODE_NONWLAN && - phy->rev == 1) { - //TODO: implement rev1 workaround - } - } - b43_phy_xmitpower(dev); //FIXME: unless scanning? - b43_lo_g_maintanance_work(dev); - //TODO for APHY (temperature?) + if (phy->ops->pwork_15sec) + phy->ops->pwork_15sec(dev); + + phy->ops->xmitpower(dev); atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); wmb(); @@ -3401,7 +3366,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ if (conf->channel->hw_value != phy->channel) - b43_radio_selectchannel(dev, conf->channel->hw_value, 0); + b43_switch_channel(dev, conf->channel->hw_value); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != @@ -3419,7 +3384,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { phy->power_level = conf->power_level; - b43_phy_xmitpower(dev); + phy->ops->xmitpower(dev); } } @@ -3427,7 +3392,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); b43_mgmtframe_txantenna(dev, antenna); antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); - b43_set_rx_antenna(dev, antenna); + if (phy->ops->set_rx_antenna) + phy->ops->set_rx_antenna(dev, antenna); /* Update templates for AP/mesh mode. */ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || @@ -3436,7 +3402,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { - b43_radio_turn_on(dev); + b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); b43info(dev->wl, "Radio turned on by software\n"); if (!dev->radio_hw_enable) { b43info(dev->wl, "The hardware RF-kill button " @@ -3444,7 +3410,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) "Press the button to turn it on.\n"); } } else { - b43_radio_turn_off(dev, 0); + b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3818,48 +3784,9 @@ static int b43_phy_versioning(struct b43_wldev *dev) static void setup_struct_phy_for_init(struct b43_wldev *dev, struct b43_phy *phy) { - struct b43_txpower_lo_control *lo; - int i; - - memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); - memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - - phy->aci_enable = 0; - phy->aci_wlan_automatic = 0; - phy->aci_hw_rssi = 0; - - phy->radio_off_context.valid = 0; - - lo = phy->lo_control; - if (lo) { - memset(lo, 0, sizeof(*(phy->lo_control))); - lo->tx_bias = 0xFF; - INIT_LIST_HEAD(&lo->calib_list); - } - phy->max_lb_gain = 0; - phy->trsw_rx_gain = 0; - phy->txpwr_offset = 0; - - /* NRSSI */ - phy->nrssislope = 0; - for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) - phy->nrssi[i] = -1000; - for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) - phy->nrssi_lt[i] = i; - - phy->lofcal = 0xFFFF; - phy->initval = 0xFFFF; - - phy->interfmode = B43_INTERFMODE_NONE; - phy->channel = 0xFF; - phy->hardware_power_control = !!modparam_hwpctl; - /* PHY TX errors counter. */ atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); - - /* OFDM-table address caching. */ - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; } static void setup_struct_wldev_for_init(struct b43_wldev *dev) @@ -3995,7 +3922,6 @@ static void b43_set_pretbtt(struct b43_wldev *dev) /* Locking: wl->mutex */ static void b43_wireless_core_exit(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; u32 macctl; B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); @@ -4016,16 +3942,12 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) b43_dma_free(dev); b43_pio_free(dev); b43_chip_exit(dev); - b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); - if (phy->dyn_tssi_tbl) - kfree(phy->tssi2dbm); - kfree(phy->lo_control); - phy->lo_control = NULL; if (dev->wl->current_beacon) { dev_kfree_skb_any(dev->wl->current_beacon); dev->wl->current_beacon = NULL; } + b43_phy_exit(dev); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(dev->dev->bus); @@ -4052,29 +3974,24 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_wireless_core_reset(dev, tmp); } - if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) { - phy->lo_control = - kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL); - if (!phy->lo_control) { - err = -ENOMEM; - goto err_busdown; - } - } setup_struct_wldev_for_init(dev); - - err = b43_phy_init_tssi2dbm_table(dev); + err = b43_phy_operations_setup(dev); if (err) - goto err_kfree_lo_control; + goto err_busdown; /* Enable IRQ routing to this device. */ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); b43_imcfglo_timeouts_workaround(dev); b43_bluetooth_coext_disable(dev); - b43_phy_early_init(dev); + if (phy->ops->prepare) { + err = phy->ops->prepare(dev); + if (err) + goto err_phy_exit; + } err = b43_chip_init(dev); if (err) - goto err_kfree_tssitbl; + goto err_phy_exit; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_WLCOREREV, dev->dev->id.revision); hf = b43_hf_read(dev); @@ -4140,15 +4057,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev) out: return err; - err_chip_exit: +err_chip_exit: b43_chip_exit(dev); - err_kfree_tssitbl: - if (phy->dyn_tssi_tbl) - kfree(phy->tssi2dbm); - err_kfree_lo_control: - kfree(phy->lo_control); - phy->lo_control = NULL; - err_busdown: +err_phy_exit: + b43_phy_exit(dev); +err_busdown: ssb_bus_may_powerdown(bus); B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); return err; @@ -4511,7 +4424,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 644eed993be..831986c459f 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -81,9 +81,8 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) //TODO } -/* Tune the hardware to a new channel. Don't call this directly. - * Use b43_radio_selectchannel() */ -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +/* Tune the hardware to a new channel. */ +static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel) { const struct b43_nphy_channeltab_entry *tabent; @@ -162,7 +161,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) msleep(1); b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); msleep(1); - b43_radio_selectchannel(dev, dev->phy.channel, 0); + nphy_channel_switch(dev, dev->phy.channel); b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); @@ -484,3 +483,139 @@ int b43_phy_initn(struct b43_wldev *dev) b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); return 0; } + +static int b43_nphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy; + + nphy = kzalloc(sizeof(*nphy), GFP_KERNEL); + if (!nphy) + return -ENOMEM; + dev->phy.n = nphy; + + //TODO init struct b43_phy_n + + return 0; +} + +static int b43_nphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + int err; + + err = b43_phy_initn(dev); + if (err) + return err; + nphy->initialised = 1; + + return 0; +} + +static void b43_nphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + if (nphy->initialised) { + //TODO + nphy->initialised = 0; + } + //TODO + kfree(nphy); + dev->phy.n = NULL; +} + +static inline void check_phyreg(struct b43_wldev *dev, u16 offset) +{ +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + /* OFDM registers are onnly available on A/G-PHYs */ + b43err(dev->wl, "Invalid OFDM PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ +} + +static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* N-PHY needs 0x100 for read access */ + reg |= 0x100; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{//TODO +} + +static int b43_nphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + } else { + if (new_channel > 200) + return -EINVAL; + } + + return nphy_channel_switch(dev, new_channel); +} + +static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + +static void b43_nphy_op_xmitpower(struct b43_wldev *dev) +{//TODO +} + +const struct b43_phy_operations b43_phyops_n = { + .allocate = b43_nphy_op_allocate, + .init = b43_nphy_op_init, + .exit = b43_nphy_op_exit, + .phy_read = b43_nphy_op_read, + .phy_write = b43_nphy_op_write, + .radio_read = b43_nphy_op_radio_read, + .radio_write = b43_nphy_op_radio_write, + .software_rfkill = b43_nphy_op_software_rfkill, + .switch_channel = b43_nphy_op_switch_channel, + .get_default_chan = b43_nphy_op_get_default_chan, + .xmitpower = b43_nphy_op_xmitpower, +}; diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h index faf46b9cbf1..3d1f65ed201 100644 --- a/drivers/net/wireless/b43/nphy.h +++ b/drivers/net/wireless/b43/nphy.h @@ -1,7 +1,7 @@ #ifndef B43_NPHY_H_ #define B43_NPHY_H_ -#include "phy.h" +#include "phy_common.h" /* N-PHY registers. */ @@ -919,54 +919,14 @@ struct b43_wldev; +struct b43_phy_n { + bool initialised; -#ifdef CONFIG_B43_NPHY -/* N-PHY support enabled */ + //TODO lots of missing stuff +}; -int b43_phy_initn(struct b43_wldev *dev); -void b43_nphy_radio_turn_on(struct b43_wldev *dev); -void b43_nphy_radio_turn_off(struct b43_wldev *dev); +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_n; -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel); - -void b43_nphy_xmitpower(struct b43_wldev *dev); -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); - - -#else /* CONFIG_B43_NPHY */ -/* N-PHY support disabled */ - - -static inline -int b43_phy_initn(struct b43_wldev *dev) -{ - return -EOPNOTSUPP; -} - -static inline -void b43_nphy_radio_turn_on(struct b43_wldev *dev) -{ -} -static inline -void b43_nphy_radio_turn_off(struct b43_wldev *dev) -{ -} - -static inline -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) -{ - return -ENOSYS; -} - -static inline -void b43_nphy_xmitpower(struct b43_wldev *dev) -{ -} -static inline -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) -{ -} - -#endif /* CONFIG_B43_NPHY */ #endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 305d4cd6fd0..02ae450beb0 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -39,160 +39,6 @@ #include "wa.h" -static const s8 b43_tssi2dbm_b_table[] = { - 0x4D, 0x4C, 0x4B, 0x4A, - 0x4A, 0x49, 0x48, 0x47, - 0x47, 0x46, 0x45, 0x45, - 0x44, 0x43, 0x42, 0x42, - 0x41, 0x40, 0x3F, 0x3E, - 0x3D, 0x3C, 0x3B, 0x3A, - 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x32, 0x31, - 0x30, 0x2F, 0x2D, 0x2C, - 0x2B, 0x29, 0x28, 0x26, - 0x25, 0x23, 0x21, 0x1F, - 0x1D, 0x1A, 0x17, 0x14, - 0x10, 0x0C, 0x06, 0x00, - -7, -7, -7, -7, - -7, -7, -7, -7, - -7, -7, -7, -7, -}; - -static const s8 b43_tssi2dbm_g_table[] = { - 77, 77, 77, 76, - 76, 76, 75, 75, - 74, 74, 73, 73, - 73, 72, 72, 71, - 71, 70, 70, 69, - 68, 68, 67, 67, - 66, 65, 65, 64, - 63, 63, 62, 61, - 60, 59, 58, 57, - 56, 55, 54, 53, - 52, 50, 49, 47, - 45, 43, 40, 37, - 33, 28, 22, 14, - 5, -7, -20, -20, - -20, -20, -20, -20, - -20, -20, -20, -20, -}; - -const u8 b43_radio_channel_codes_bg[] = { - 12, 17, 22, 27, - 32, 37, 42, 47, - 52, 57, 62, 67, - 72, 84, -}; - -#define bitrev4(tmp) (bitrev8(tmp) >> 4) -static void b43_phy_initg(struct b43_wldev *dev); - -static void generate_rfatt_list(struct b43_wldev *dev, - struct b43_rfatt_list *list) -{ - struct b43_phy *phy = &dev->phy; - - /* APHY.rev < 5 || GPHY.rev < 6 */ - static const struct b43_rfatt rfatt_0[] = { - {.att = 3,.with_padmix = 0,}, - {.att = 1,.with_padmix = 0,}, - {.att = 5,.with_padmix = 0,}, - {.att = 7,.with_padmix = 0,}, - {.att = 9,.with_padmix = 0,}, - {.att = 2,.with_padmix = 0,}, - {.att = 0,.with_padmix = 0,}, - {.att = 4,.with_padmix = 0,}, - {.att = 6,.with_padmix = 0,}, - {.att = 8,.with_padmix = 0,}, - {.att = 1,.with_padmix = 1,}, - {.att = 2,.with_padmix = 1,}, - {.att = 3,.with_padmix = 1,}, - {.att = 4,.with_padmix = 1,}, - }; - /* Radio.rev == 8 && Radio.version == 0x2050 */ - static const struct b43_rfatt rfatt_1[] = { - {.att = 2,.with_padmix = 1,}, - {.att = 4,.with_padmix = 1,}, - {.att = 6,.with_padmix = 1,}, - {.att = 8,.with_padmix = 1,}, - {.att = 10,.with_padmix = 1,}, - {.att = 12,.with_padmix = 1,}, - {.att = 14,.with_padmix = 1,}, - }; - /* Otherwise */ - static const struct b43_rfatt rfatt_2[] = { - {.att = 0,.with_padmix = 1,}, - {.att = 2,.with_padmix = 1,}, - {.att = 4,.with_padmix = 1,}, - {.att = 6,.with_padmix = 1,}, - {.att = 8,.with_padmix = 1,}, - {.att = 9,.with_padmix = 1,}, - {.att = 9,.with_padmix = 1,}, - }; - - if (!b43_has_hardware_pctl(phy)) { - /* Software pctl */ - list->list = rfatt_0; - list->len = ARRAY_SIZE(rfatt_0); - list->min_val = 0; - list->max_val = 9; - return; - } - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - /* Hardware pctl */ - list->list = rfatt_1; - list->len = ARRAY_SIZE(rfatt_1); - list->min_val = 0; - list->max_val = 14; - return; - } - /* Hardware pctl */ - list->list = rfatt_2; - list->len = ARRAY_SIZE(rfatt_2); - list->min_val = 0; - list->max_val = 9; -} - -static void generate_bbatt_list(struct b43_wldev *dev, - struct b43_bbatt_list *list) -{ - static const struct b43_bbatt bbatt_0[] = { - {.att = 0,}, - {.att = 1,}, - {.att = 2,}, - {.att = 3,}, - {.att = 4,}, - {.att = 5,}, - {.att = 6,}, - {.att = 7,}, - {.att = 8,}, - }; - - list->list = bbatt_0; - list->len = ARRAY_SIZE(bbatt_0); - list->min_val = 0; - list->max_val = 8; -} - -bool b43_has_hardware_pctl(struct b43_phy *phy) -{ - if (!phy->hardware_power_control) - return 0; - switch (phy->type) { - case B43_PHYTYPE_A: - if (phy->rev >= 5) - return 1; - break; - case B43_PHYTYPE_G: - if (phy->rev >= 6) - return 1; - break; - default: - B43_WARN_ON(1); - } - return 0; -} - static void b43_shm_clear_tssi(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -212,1345 +58,109 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev) } } -/* Lock the PHY registers against concurrent access from the microcode. - * This lock is nonrecursive. */ -void b43_phy_lock(struct b43_wldev *dev) -{ -#if B43_DEBUG - B43_WARN_ON(dev->phy.phy_locked); - dev->phy.phy_locked = 1; -#endif - B43_WARN_ON(dev->dev->id.revision < 3); - - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); -} - -void b43_phy_unlock(struct b43_wldev *dev) -{ -#if B43_DEBUG - B43_WARN_ON(!dev->phy.phy_locked); - dev->phy.phy_locked = 0; -#endif - B43_WARN_ON(dev->dev->id.revision < 3); - - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, 0); -} - -/* Different PHYs require different register routing flags. - * This adjusts (and does sanity checks on) the routing flags. +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 */ -static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, - u16 offset, struct b43_wldev *dev) -{ - if (phy->type == B43_PHYTYPE_A) { - /* OFDM registers are base-registers for the A-PHY. */ - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { - offset &= ~B43_PHYROUTE; - offset |= B43_PHYROUTE_BASE; - } - } - -#if B43_DEBUG - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { - /* Ext-G registers are only available on G-PHYs */ - if (phy->type != B43_PHYTYPE_G) { - b43err(dev->wl, "Invalid EXT-G PHY access at " - "0x%04X on PHY type %u\n", offset, phy->type); - dump_stack(); - } - } - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { - /* N-BMODE registers are only available on N-PHYs */ - if (phy->type != B43_PHYTYPE_N) { - b43err(dev->wl, "Invalid N-BMODE PHY access at " - "0x%04X on PHY type %u\n", offset, phy->type); - dump_stack(); - } - } -#endif /* B43_DEBUG */ - - return offset; -} - -u16 b43_phy_read(struct b43_wldev * dev, u16 offset) -{ - struct b43_phy *phy = &dev->phy; - - offset = adjust_phyreg_for_phytype(phy, offset, dev); - b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) -{ - struct b43_phy *phy = &dev->phy; - - offset = adjust_phyreg_for_phytype(phy, offset, dev); - b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - b43_write16(dev, B43_MMIO_PHY_DATA, val); -} - -void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) -{ - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) & mask); -} - -void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) -{ - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) | set); -} - -void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) -{ - b43_phy_write(dev, offset, - (b43_phy_read(dev, offset) & mask) | set); -} - -/* Adjust the transmission power output (G-PHY) */ -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control) +static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - u16 bb, rf; - u16 tx_bias, tx_magn; - - bb = bbatt->att; - rf = rfatt->att; - tx_bias = lo->tx_bias; - tx_magn = lo->tx_magn; - if (unlikely(tx_bias == 0xFF)) - tx_bias = 0; + s8 dbm = 0; + s32 tmp; - /* Save the values for later */ - phy->tx_control = tx_control; - memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); - phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); - memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); + tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " - "rfatt(%u), tx_control(0x%02X), " - "tx_bias(0x%02X), tx_magn(0x%02X)\n", - bb, rf, tx_control, tx_bias, tx_magn); + switch (phy->type) { + case B43_PHYTYPE_A: + tmp += 0x80; + tmp = clamp_val(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + //TODO: There's a FIXME on the specs + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + tmp = clamp_val(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + B43_WARN_ON(1); } - b43_phy_set_baseband_attenuation(dev, bb); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, - (rf & 0x000F) | (tx_control & 0x0070)); - } else { - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | (rf & 0x000F)); - b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) - & ~0x0070) | (tx_control & - 0x0070)); - } - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, tx_magn | tx_bias); - } else { - b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) - & 0xFFF0) | (tx_bias & 0x000F)); - } - if (phy->type == B43_PHYTYPE_G) - b43_lo_g_adjust(dev); + return dbm; } -static void default_baseband_attenuation(struct b43_wldev *dev, - struct b43_bbatt *bb) +void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) { - struct b43_phy *phy = &dev->phy; + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; - if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) - bb->att = 0; - else - bb->att = 2; -} + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ -static void default_radio_attenuation(struct b43_wldev *dev, - struct b43_rfatt *rf) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; - rf->with_padmix = 0; + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && - bus->boardinfo.type == SSB_BOARD_BCM4309G) { - if (bus->boardinfo.rev < 0x43) { - rf->att = 2; - return; - } else if (bus->boardinfo.rev < 0x51) { - rf->att = 3; - return; + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; } - } - - if (phy->type == B43_PHYTYPE_A) { - rf->att = 0x60; - return; - } - - switch (phy->radio_ver) { - case 0x2053: - switch (phy->radio_rev) { - case 1: - rf->att = 6; - return; + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; } - break; - case 0x2050: - switch (phy->radio_rev) { - case 0: - rf->att = 5; - return; - case 1: - if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 3; - else if (bus->boardinfo.vendor == - SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == - SSB_BOARD_BU4306) - rf->att = 3; - else - rf->att = 1; - } else { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 7; - else - rf->att = 6; - } - return; - case 2: - if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 3; - else if (bus->boardinfo.vendor == - SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == - SSB_BOARD_BU4306) - rf->att = 5; - else if (bus->chip_id == 0x4320) - rf->att = 4; - else - rf->att = 3; - } else - rf->att = 6; - return; - case 3: - rf->att = 5; - return; - case 4: - case 5: - rf->att = 1; - return; - case 6: - case 7: - rf->att = 5; - return; - case 8: - rf->att = 0xA; - rf->with_padmix = 1; - return; - case 9: - default: - rf->att = 5; - return; + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; } - } - rf->att = 5; -} - -static u16 default_tx_control(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->radio_ver != 0x2050) - return 0; - if (phy->radio_rev == 1) - return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; - if (phy->radio_rev < 6) - return B43_TXCTL_PA2DB; - if (phy->radio_rev == 8) - return B43_TXCTL_TXMIX; - return 0; -} - -/* This func is called "PHY calibrate" in the specs... */ -void b43_phy_early_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - default_baseband_attenuation(dev, &phy->bbatt); - default_radio_attenuation(dev, &phy->rfatt); - phy->tx_control = (default_tx_control(dev) << 4); - - /* Commit previous writes */ - b43_read32(dev, B43_MMIO_MACCTL); - - if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) { - generate_rfatt_list(dev, &lo->rfatt_list); - generate_bbatt_list(dev, &lo->bbatt_list); - } - if (phy->type == B43_PHYTYPE_G && phy->rev == 1) { - /* Workaround: Temporarly disable gmode through the early init - * phase, as the gmode stuff is not needed for phy rev 1 */ - phy->gmode = 0; - b43_wireless_core_reset(dev, 0); - b43_phy_initg(dev); - phy->gmode = 1; - b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); - } -} - -/* GPHY_TSSI_Power_Lookup_Table_Init */ -static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - int i; - u16 value; - - for (i = 0; i < 32; i++) - b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]); - for (i = 32; i < 64; i++) - b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]); - for (i = 0; i < 64; i += 2) { - value = (u16) phy->tssi2dbm[i]; - value |= ((u16) phy->tssi2dbm[i + 1]) << 8; - b43_phy_write(dev, 0x380 + (i / 2), value); - } -} - -/* GPHY_Gain_Lookup_Table_Init */ -static void b43_gphy_gain_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - u16 nr_written = 0; - u16 tmp; - u8 rf, bb; - - for (rf = 0; rf < lo->rfatt_list.len; rf++) { - for (bb = 0; bb < lo->bbatt_list.len; bb++) { - if (nr_written >= 0x40) - return; - tmp = lo->bbatt_list.list[bb].att; - tmp <<= 8; - if (phy->radio_rev == 8) - tmp |= 0x50; - else - tmp |= 0x40; - tmp |= lo->rfatt_list.list[rf].att; - b43_phy_write(dev, 0x3C0 + nr_written, tmp); - nr_written++; + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; } - } -} - -static void hardware_pctl_init_aphy(struct b43_wldev *dev) -{ - //TODO -} - -static void hardware_pctl_init_gphy(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) - | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); - b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) - | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); - b43_gphy_tssi_power_lt_init(dev); - b43_gphy_gain_lt_init(dev); - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); - b43_phy_write(dev, 0x0014, 0x0000); - - B43_WARN_ON(phy->rev < 6); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) - | 0x0800); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) - & 0xFEFF); - b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) - & 0xFFBF); - - b43_gphy_dc_lt_init(dev, 1); -} - -/* HardwarePowerControl init for A and G PHY */ -static void b43_hardware_pctl_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (!b43_has_hardware_pctl(phy)) { - /* No hardware power control */ - b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); - return; - } - /* Init the hwpctl related hardware */ - switch (phy->type) { - case B43_PHYTYPE_A: - hardware_pctl_init_aphy(dev); - break; - case B43_PHYTYPE_G: - hardware_pctl_init_gphy(dev); break; - default: - B43_WARN_ON(1); - } - /* Enable hardware pctl in firmware. */ - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); -} - -static void b43_hardware_pctl_early_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (!b43_has_hardware_pctl(phy)) { - b43_phy_write(dev, 0x047A, 0xC111); - return; } - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); - b43_phy_write(dev, 0x002F, 0x0202); - b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); - b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) - & 0xFF0F) | 0x0010); - b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) - | 0x8000); - b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) - & 0xFFC0) | 0x0010); - b43_phy_write(dev, 0x002E, 0xC07F); - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0400); - } else { - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0200); - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0400); - b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) - & 0x7FFF); - b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) - & 0xFFFE); - b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) - & 0xFFC0) | 0x0010); - b43_phy_write(dev, 0x002E, 0xC07F); - b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) - & 0xFF0F) | 0x0010); - } + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); } -/* Intialize B/G PHY power control - * as described in http://bcm-specs.sipsolutions.net/InitPowerControl - */ -static void b43_phy_init_pctl(struct b43_wldev *dev) +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void b43_phy_xmitpower(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; - struct b43_rfatt old_rfatt; - struct b43_bbatt old_bbatt; - u8 old_tx_control = 0; + if (phy->cur_idle_tssi == 0) + return; if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && (bus->boardinfo.type == SSB_BOARD_BU4306)) return; - - b43_phy_write(dev, 0x0028, 0x8018); - - /* This does something with the Analog... */ - b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) - & 0xFFDF); - - if (phy->type == B43_PHYTYPE_G && !phy->gmode) +#ifdef CONFIG_B43_DEBUG + if (phy->manual_txpower_control) return; - b43_hardware_pctl_early_init(dev); - if (phy->cur_idle_tssi == 0) { - if (phy->radio_ver == 0x2050 && phy->analog == 0) { - b43_radio_write16(dev, 0x0076, - (b43_radio_read16(dev, 0x0076) - & 0x00F7) | 0x0084); - } else { - struct b43_rfatt rfatt; - struct b43_bbatt bbatt; - - memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt)); - memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt)); - old_tx_control = phy->tx_control; - - bbatt.att = 11; - if (phy->radio_rev == 8) { - rfatt.att = 15; - rfatt.with_padmix = 1; - } else { - rfatt.att = 9; - rfatt.with_padmix = 0; - } - b43_set_txpower_g(dev, &bbatt, &rfatt, 0); - } - b43_dummy_transmission(dev); - phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); - if (B43_DEBUG) { - /* Current-Idle-TSSI sanity check. */ - if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) { - b43dbg(dev->wl, - "!WARNING! Idle-TSSI phy->cur_idle_tssi " - "measuring failed. (cur=%d, tgt=%d). Disabling TX power " - "adjustment.\n", phy->cur_idle_tssi, - phy->tgt_idle_tssi); - phy->cur_idle_tssi = 0; - } - } - if (phy->radio_ver == 0x2050 && phy->analog == 0) { - b43_radio_write16(dev, 0x0076, - b43_radio_read16(dev, 0x0076) - & 0xFF7B); - } else { - b43_set_txpower_g(dev, &old_bbatt, - &old_rfatt, old_tx_control); - } - } - b43_hardware_pctl_init(dev); - b43_shm_clear_tssi(dev); -} - -static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) -{ - int i; +#endif - if (dev->phy.rev < 3) { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0xFFF8); - } - else - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); - } - } else { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0x0820); - else - for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); - } -} + switch (phy->type) { + case B43_PHYTYPE_A:{ -static void b43_phy_ww(struct b43_wldev *dev) -{ - u16 b, curr_s, best_s = 0xFFFF; - int i; - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); - b43_phy_write(dev, B43_PHY_OFDM(0x1B), - b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); - b43_phy_write(dev, B43_PHY_OFDM(0x82), - (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); - b43_radio_write16(dev, 0x0009, - b43_radio_read16(dev, 0x0009) | 0x0080); - b43_radio_write16(dev, 0x0012, - (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); - b43_wa_initgains(dev); - b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); - b = b43_phy_read(dev, B43_PHY_PWRDOWN); - b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); - b43_radio_write16(dev, 0x0004, - b43_radio_read16(dev, 0x0004) | 0x0004); - for (i = 0x10; i <= 0x20; i++) { - b43_radio_write16(dev, 0x0013, i); - curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; - if (!curr_s) { - best_s = 0x0000; - break; - } else if (curr_s >= 0x0080) - curr_s = 0x0100 - curr_s; - if (curr_s < best_s) - best_s = curr_s; - } - b43_phy_write(dev, B43_PHY_PWRDOWN, b); - b43_radio_write16(dev, 0x0004, - b43_radio_read16(dev, 0x0004) & 0xFFFB); - b43_radio_write16(dev, 0x0013, best_s); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); - b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); - b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); - b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); - b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); - b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); - b43_phy_write(dev, B43_PHY_OFDM(0xBB), - (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); - b43_phy_write(dev, B43_PHY_OFDM61, - (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); - b43_phy_write(dev, B43_PHY_OFDM(0x13), - (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); - b43_phy_write(dev, B43_PHY_OFDM(0x14), - (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); - for (i = 0; i < 6; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); - b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); -} - -/* Initialize APHY. This is also called for the GPHY in some cases. */ -static void b43_phy_inita(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - might_sleep(); - - if (phy->rev >= 6) { - if (phy->type == B43_PHYTYPE_A) - b43_phy_write(dev, B43_PHY_OFDM(0x1B), - b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); - if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) - b43_phy_write(dev, B43_PHY_ENCORE, - b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); - else - b43_phy_write(dev, B43_PHY_ENCORE, - b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); - } - - b43_wa_all(dev); - - if (phy->type == B43_PHYTYPE_A) { - if (phy->gmode && (phy->rev < 3)) - b43_phy_write(dev, 0x0034, - b43_phy_read(dev, 0x0034) | 0x0001); - b43_phy_rssiagc(dev, 0); - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); - - b43_radio_init2060(dev); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - ((bus->boardinfo.type == SSB_BOARD_BU4306) || - (bus->boardinfo.type == SSB_BOARD_BU4309))) { - ; //TODO: A PHY LO - } - - if (phy->rev >= 3) - b43_phy_ww(dev); - - hardware_pctl_init_aphy(dev); - - //TODO: radar detection - } - - if ((phy->type == B43_PHYTYPE_G) && - (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { - b43_phy_write(dev, B43_PHY_OFDM(0x6E), - (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) - & 0xE000) | 0x3CF); - } -} - -static void b43_phy_initb5(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - u16 offset, value; - u8 old_channel; - - if (phy->analog == 1) { - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) - | 0x0050); - } - if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type != SSB_BOARD_BU4306)) { - value = 0x2120; - for (offset = 0x00A8; offset < 0x00C7; offset++) { - b43_phy_write(dev, offset, value); - value += 0x202; - } - } - b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) - | 0x0700); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0038, 0x0667); - - if (phy->gmode || phy->rev >= 2) { - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) - | 0x0020); - b43_radio_write16(dev, 0x0051, - b43_radio_read16(dev, 0x0051) - | 0x0004); - } - b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); - - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); - - b43_phy_write(dev, 0x001C, 0x186A); - - b43_phy_write(dev, 0x0013, - (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); - b43_phy_write(dev, 0x0035, - (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); - b43_phy_write(dev, 0x005D, - (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); - } - - if (dev->bad_frames_preempt) { - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, - B43_PHY_RADIO_BITFIELD) | (1 << 11)); - } - - if (phy->analog == 1) { - b43_phy_write(dev, 0x0026, 0xCE00); - b43_phy_write(dev, 0x0021, 0x3763); - b43_phy_write(dev, 0x0022, 0x1BC3); - b43_phy_write(dev, 0x0023, 0x06F9); - b43_phy_write(dev, 0x0024, 0x037E); - } else - b43_phy_write(dev, 0x0026, 0xCC00); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_write16(dev, 0x03EC, 0x3F22); - - if (phy->analog == 1) - b43_phy_write(dev, 0x0020, 0x3E1C); - else - b43_phy_write(dev, 0x0020, 0x301C); - - if (phy->analog == 0) - b43_write16(dev, 0x03E4, 0x3000); - - old_channel = phy->channel; - /* Force to channel 7, even if not supported. */ - b43_radio_selectchannel(dev, 7, 0); - - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - } - - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); - - b43_radio_selectchannel(dev, old_channel, 0); - - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - b43_phy_write(dev, 0x002A, 0x88A3); - - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - - if (phy->radio_ver == 0x2050) - b43_radio_write16(dev, 0x005D, 0x000D); - - b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); -} - -static void b43_phy_initb6(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - u8 old_channel; - - b43_phy_write(dev, 0x003E, 0x817A); - b43_radio_write16(dev, 0x007A, - (b43_radio_read16(dev, 0x007A) | 0x0058)); - if (phy->radio_rev == 4 || phy->radio_rev == 5) { - b43_radio_write16(dev, 0x51, 0x37); - b43_radio_write16(dev, 0x52, 0x70); - b43_radio_write16(dev, 0x53, 0xB3); - b43_radio_write16(dev, 0x54, 0x9B); - b43_radio_write16(dev, 0x5A, 0x88); - b43_radio_write16(dev, 0x5B, 0x88); - b43_radio_write16(dev, 0x5D, 0x88); - b43_radio_write16(dev, 0x5E, 0x88); - b43_radio_write16(dev, 0x7D, 0x88); - b43_hf_write(dev, b43_hf_read(dev) - | B43_HF_TSSIRPSMW); - } - B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x51, 0); - b43_radio_write16(dev, 0x52, 0x40); - b43_radio_write16(dev, 0x53, 0xB7); - b43_radio_write16(dev, 0x54, 0x98); - b43_radio_write16(dev, 0x5A, 0x88); - b43_radio_write16(dev, 0x5B, 0x6B); - b43_radio_write16(dev, 0x5C, 0x0F); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { - b43_radio_write16(dev, 0x5D, 0xFA); - b43_radio_write16(dev, 0x5E, 0xD8); - } else { - b43_radio_write16(dev, 0x5D, 0xF5); - b43_radio_write16(dev, 0x5E, 0xB8); - } - b43_radio_write16(dev, 0x0073, 0x0003); - b43_radio_write16(dev, 0x007D, 0x00A8); - b43_radio_write16(dev, 0x007C, 0x0001); - b43_radio_write16(dev, 0x007E, 0x0008); - } - val = 0x1E1F; - for (offset = 0x0088; offset < 0x0098; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - val = 0x3E3F; - for (offset = 0x0098; offset < 0x00A8; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - val = 0x2120; - for (offset = 0x00A8; offset < 0x00C8; offset++) { - b43_phy_write(dev, offset, (val & 0x3F3F)); - val += 0x0202; - } - if (phy->type == B43_PHYTYPE_G) { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0020); - b43_radio_write16(dev, 0x0051, - b43_radio_read16(dev, 0x0051) | 0x0004); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); - b43_phy_write(dev, 0x5B, 0); - b43_phy_write(dev, 0x5C, 0); - } - - old_channel = phy->channel; - if (old_channel >= 8) - b43_radio_selectchannel(dev, 1, 0); - else - b43_radio_selectchannel(dev, 13, 0); - - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - udelay(40); - if (phy->radio_rev < 6 || phy->radio_rev == 8) { - b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) - | 0x0002)); - b43_radio_write16(dev, 0x50, 0x20); - } - if (phy->radio_rev <= 2) { - b43_radio_write16(dev, 0x7C, 0x20); - b43_radio_write16(dev, 0x5A, 0x70); - b43_radio_write16(dev, 0x5B, 0x7B); - b43_radio_write16(dev, 0x5C, 0xB0); - } - b43_radio_write16(dev, 0x007A, - (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); - - b43_radio_selectchannel(dev, old_channel, 0); - - b43_phy_write(dev, 0x0014, 0x0200); - if (phy->radio_rev >= 6) - b43_phy_write(dev, 0x2A, 0x88C2); - else - b43_phy_write(dev, 0x2A, 0x8AC0); - b43_phy_write(dev, 0x0038, 0x0668); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (phy->radio_rev <= 5) { - b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) - & 0xFF80) | 0x0003); - } - if (phy->radio_rev <= 2) - b43_radio_write16(dev, 0x005D, 0x000D); - - if (phy->analog == 4) { - b43_write16(dev, 0x3E4, 9); - b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) - & 0x0FFF); - } else { - b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) - | 0x0004); - } - if (phy->type == B43_PHYTYPE_B) - B43_WARN_ON(1); - else if (phy->type == B43_PHYTYPE_G) - b43_write16(dev, 0x03E6, 0x0); -} - -static void b43_calc_loopback_gain(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup_phy[16] = { 0 }; - u16 backup_radio[3]; - u16 backup_bband; - u16 i, j, loop_i_max; - u16 trsw_rx; - u16 loop1_outer_done, loop1_inner_done; - - backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); - backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); - backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); - backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); - backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); - } - backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); - backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); - backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); - backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); - backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); - backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); - backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); - backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); - backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); - backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - backup_bband = phy->bbatt.att; - backup_radio[0] = b43_radio_read16(dev, 0x52); - backup_radio[1] = b43_radio_read16(dev, 0x43); - backup_radio[2] = b43_radio_read16(dev, 0x7A); - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, - b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFE); - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFD); - } - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xFFCF) | 0x10); - - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - - b43_phy_write(dev, B43_PHY_CCK(0x0A), - b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFB); - } - b43_phy_write(dev, B43_PHY_CCK(0x03), - (b43_phy_read(dev, B43_PHY_CCK(0x03)) - & 0xFF9F) | 0x40); - - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, 0x000F); - } else { - b43_radio_write16(dev, 0x52, 0); - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | 0x9); - } - b43_phy_set_baseband_attenuation(dev, 11); - - if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); - else - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); - b43_phy_write(dev, B43_PHY_LO_CTL, 0); - - b43_phy_write(dev, B43_PHY_CCK(0x2B), - (b43_phy_read(dev, B43_PHY_CCK(0x2B)) - & 0xFFC0) | 0x01); - b43_phy_write(dev, B43_PHY_CCK(0x2B), - (b43_phy_read(dev, B43_PHY_CCK(0x2B)) - & 0xC0FF) | 0x800); - - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); - - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { - if (phy->rev >= 7) { - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) - | 0x0800); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) - | 0x8000); - } - } - b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) - & 0x00F7); - - j = 0; - loop_i_max = (phy->radio_rev == 8) ? 15 : 9; - for (i = 0; i < loop_i_max; i++) { - for (j = 0; j < 16; j++) { - b43_radio_write16(dev, 0x43, i); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xF0FF) | (j << 8)); - b43_phy_write(dev, B43_PHY_PGACTL, - (b43_phy_read(dev, B43_PHY_PGACTL) - & 0x0FFF) | 0xA000); - b43_phy_write(dev, B43_PHY_PGACTL, - b43_phy_read(dev, B43_PHY_PGACTL) - | 0xF000); - udelay(20); - if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) - goto exit_loop1; - } - } - exit_loop1: - loop1_outer_done = i; - loop1_inner_done = j; - if (j >= 8) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) - | 0x30); - trsw_rx = 0x1B; - for (j = j - 8; j < 16; j++) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xF0FF) | (j << 8)); - b43_phy_write(dev, B43_PHY_PGACTL, - (b43_phy_read(dev, B43_PHY_PGACTL) - & 0x0FFF) | 0xA000); - b43_phy_write(dev, B43_PHY_PGACTL, - b43_phy_read(dev, B43_PHY_PGACTL) - | 0xF000); - udelay(20); - trsw_rx -= 3; - if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) - goto exit_loop2; - } - } else - trsw_rx = 0x18; - exit_loop2: - - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); - } - b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); - b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); - b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); - b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); - b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); - b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); - b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); - b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); - b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); - - b43_phy_set_baseband_attenuation(dev, backup_bband); - - b43_radio_write16(dev, 0x52, backup_radio[0]); - b43_radio_write16(dev, 0x43, backup_radio[1]); - b43_radio_write16(dev, 0x7A, backup_radio[2]); - - b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); - udelay(10); - b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); - b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); - b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); - - phy->max_lb_gain = - ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; - phy->trsw_rx_gain = trsw_rx * 2; -} - -static void b43_phy_initg(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 tmp; - - if (phy->rev == 1) - b43_phy_initb5(dev); - else - b43_phy_initb6(dev); - - if (phy->rev >= 2 || phy->gmode) - b43_phy_inita(dev); - - if (phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); - } - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_RFOVER, 0); - b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); - } - if (phy->rev > 5) { - b43_phy_write(dev, B43_PHY_RFOVER, 0x400); - b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); - } - if (phy->gmode || phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); - tmp &= B43_PHYVER_VERSION; - if (tmp == 3 || tmp == 5) { - b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); - b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); - } - if (tmp == 5) { - b43_phy_write(dev, B43_PHY_OFDM(0xCC), - (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) - & 0x00FF) | 0x1F00); - } - } - if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) - b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); - if (phy->radio_rev == 8) { - b43_phy_write(dev, B43_PHY_EXTG(0x01), - b43_phy_read(dev, B43_PHY_EXTG(0x01)) - | 0x80); - b43_phy_write(dev, B43_PHY_OFDM(0x3E), - b43_phy_read(dev, B43_PHY_OFDM(0x3E)) - | 0x4); - } - if (has_loopback_gain(phy)) - b43_calc_loopback_gain(dev); - - if (phy->radio_rev != 8) { - if (phy->initval == 0xFFFF) - phy->initval = b43_radio_init2050(dev); - else - b43_radio_write16(dev, 0x0078, phy->initval); - } - b43_lo_g_init(dev); - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFF00) - | phy->lo_control->tx_bias | phy-> - lo_control->tx_magn); - } else { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFFF0) - | phy->lo_control->tx_bias); - } - if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_CCK(0x36), - (b43_phy_read(dev, B43_PHY_CCK(0x36)) - & 0x0FFF) | (phy->lo_control-> - tx_bias << 12)); - } - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); - else - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); - if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); - else - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); - if (phy->gmode || phy->rev >= 2) { - b43_lo_g_adjust(dev); - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); - } - - if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { - /* The specs state to update the NRSSI LT with - * the value 0x7FFFFFFF here. I think that is some weird - * compiler optimization in the original driver. - * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the clamp_val() in nrssi_hw_update()) - */ - b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? - b43_calc_nrssi_threshold(dev); - } else if (phy->gmode || phy->rev >= 2) { - if (phy->nrssi[0] == -1000) { - B43_WARN_ON(phy->nrssi[1] != -1000); - b43_calc_nrssi_slope(dev); - } else - b43_calc_nrssi_threshold(dev); - } - if (phy->radio_rev == 8) - b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); - b43_phy_init_pctl(dev); - /* FIXME: The spec says in the following if, the 0 should be replaced - 'if OFDM may not be used in the current locale' - but OFDM is legal everywhere */ - if ((dev->dev->bus->chip_id == 0x4306 - && dev->dev->bus->chip_package == 2) || 0) { - b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) - & 0xBFFF); - b43_phy_write(dev, B43_PHY_OFDM(0xC3), - b43_phy_read(dev, B43_PHY_OFDM(0xC3)) - & 0x7FFF); - } -} - -/* Set the baseband attenuation value on chip. */ -void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, - u16 baseband_attenuation) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->analog == 0) { - b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) - & 0xFFF0) | - baseband_attenuation); - } else if (phy->analog > 1) { - b43_phy_write(dev, B43_PHY_DACCTL, - (b43_phy_read(dev, B43_PHY_DACCTL) - & 0xFFC3) | (baseband_attenuation << 2)); - } else { - b43_phy_write(dev, B43_PHY_DACCTL, - (b43_phy_read(dev, B43_PHY_DACCTL) - & 0xFF87) | (baseband_attenuation << 3)); - } -} - -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut - * This function converts a TSSI value to dBm in Q5.2 - */ -static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) -{ - struct b43_phy *phy = &dev->phy; - s8 dbm = 0; - s32 tmp; - - tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); - - switch (phy->type) { - case B43_PHYTYPE_A: - tmp += 0x80; - tmp = clamp_val(tmp, 0x00, 0xFF); - dbm = phy->tssi2dbm[tmp]; - //TODO: There's a FIXME on the specs - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - tmp = clamp_val(tmp, 0x00, 0x3F); - dbm = phy->tssi2dbm[tmp]; - break; - default: - B43_WARN_ON(1); - } - - return dbm; -} - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt) -{ - int rfatt = *_rfatt; - int bbatt = *_bbatt; - struct b43_txpower_lo_control *lo = dev->phy.lo_control; - - /* Get baseband and radio attenuation values into their permitted ranges. - * Radio attenuation affects power level 4 times as much as baseband. */ - - /* Range constants */ - const int rf_min = lo->rfatt_list.min_val; - const int rf_max = lo->rfatt_list.max_val; - const int bb_min = lo->bbatt_list.min_val; - const int bb_max = lo->bbatt_list.max_val; - - while (1) { - if (rfatt > rf_max && bbatt > bb_max - 4) - break; /* Can not get it into ranges */ - if (rfatt < rf_min && bbatt < bb_min + 4) - break; /* Can not get it into ranges */ - if (bbatt > bb_max && rfatt > rf_max - 1) - break; /* Can not get it into ranges */ - if (bbatt < bb_min && rfatt < rf_min + 1) - break; /* Can not get it into ranges */ - - if (bbatt > bb_max) { - bbatt -= 4; - rfatt += 1; - continue; - } - if (bbatt < bb_min) { - bbatt += 4; - rfatt -= 1; - continue; - } - if (rfatt > rf_max) { - rfatt -= 1; - bbatt += 4; - continue; - } - if (rfatt < rf_min) { - rfatt += 1; - bbatt -= 4; - continue; - } - break; - } - - *_rfatt = clamp_val(rfatt, rf_min, rf_max); - *_bbatt = clamp_val(bbatt, bb_min, bb_max); -} - -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ -void b43_phy_xmitpower(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - if (phy->cur_idle_tssi == 0) - return; - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; -#ifdef CONFIG_B43_DEBUG - if (phy->manual_txpower_control) - return; -#endif - - switch (phy->type) { - case B43_PHYTYPE_A:{ - - //TODO: Nothing for A PHYs yet :-/ + //TODO: Nothing for A PHYs yet :-/ break; } @@ -1591,2235 +201,232 @@ void b43_phy_xmitpower(struct b43_wldev *dev) v2 = (v2 + 0x20) & 0x3F; v3 = (v3 + 0x20) & 0x3F; tmp = 1; - } - b43_shm_clear_tssi(dev); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp - && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & - 0x8)) - average -= 13; - - estimated_pwr = - b43_phy_estimate_power_out(dev, average); - - max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.boardflags_lo - & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) - max_pwr -= 0x3; - if (unlikely(max_pwr <= 0)) { - b43warn(dev->wl, - "Invalid max-TX-power value in SPROM.\n"); - max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.maxpwr_bg = max_pwr; - } - - /*TODO: - max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - /* Get desired power (in Q5.2) */ - desired_pwr = INT_TO_Q52(phy->power_level); - /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = clamp_val(desired_pwr, 0, max_pwr); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, - "Current TX power output: " Q52_FMT - " dBm, " "Desired TX power output: " - Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), - Q52_ARG(desired_pwr)); - } - - /* Calculate the adjustment delta. */ - pwr_adjust = desired_pwr - estimated_pwr; - - /* RF attenuation delta. */ - rfatt_delta = ((pwr_adjust + 7) / 8); - /* Lower attenuation => Bigger power output. Negate it. */ - rfatt_delta = -rfatt_delta; - - /* Baseband attenuation delta. */ - bbatt_delta = pwr_adjust / 2; - /* Lower attenuation => Bigger power output. Negate it. */ - bbatt_delta = -bbatt_delta; - /* RF att affects power level 4 times as much as - * Baseband attennuation. Subtract it. */ - bbatt_delta -= 4 * rfatt_delta; - - /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) - return; - - /* Calculate the new attenuation values. */ - bbatt = phy->bbatt.att; - bbatt += bbatt_delta; - rfatt = phy->rfatt.att; - rfatt += rfatt_delta; - - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - tx_control = phy->tx_control; - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { - if (rfatt <= 1) { - if (tx_control == 0) { - tx_control = - B43_TXCTL_PA2DB | - B43_TXCTL_TXMIX; - rfatt += 2; - bbatt += 2; - } else if (dev->dev->bus->sprom. - boardflags_lo & - B43_BFL_PACTRL) { - bbatt += 4 * (rfatt - 2); - rfatt = 2; - } - } else if (rfatt > 4 && tx_control) { - tx_control = 0; - if (bbatt < 3) { - rfatt -= 3; - bbatt += 2; - } else { - rfatt -= 2; - bbatt -= 2; - } - } - } - /* Save the control values */ - phy->tx_control = tx_control; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - phy->rfatt.att = rfatt; - phy->bbatt.att = bbatt; - - /* Adjust the hardware */ - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, - phy->tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - break; - } - case B43_PHYTYPE_N: - b43_nphy_xmitpower(dev); - break; - default: - B43_WARN_ON(1); - } -} - -static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) -{ - if (num < 0) - return num / den; - else - return (num + den / 2) / den; -} - -static inline - s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) -{ - s32 m1, m2, f = 256, q, delta; - s8 i = 0; - - m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); - m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); - do { - if (i > 15) - return -EINVAL; - q = b43_tssi2dbm_ad(f * 4096 - - b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); - delta = abs(q - f); - f = q; - i++; - } while (delta >= 2); - entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s16 pab0, pab1, pab2; - u8 idx; - s8 *dyn_tssi2dbm; - - if (phy->type == B43_PHYTYPE_A) { - pab0 = (s16) (dev->dev->bus->sprom.pa1b0); - pab1 = (s16) (dev->dev->bus->sprom.pa1b1); - pab2 = (s16) (dev->dev->bus->sprom.pa1b2); - } else { - pab0 = (s16) (dev->dev->bus->sprom.pa0b0); - pab1 = (s16) (dev->dev->bus->sprom.pa0b1); - pab2 = (s16) (dev->dev->bus->sprom.pa0b2); - } - - if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - return 0; - } - - if (pab0 != 0 && pab1 != 0 && pab2 != 0 && - pab0 != -1 && pab1 != -1 && pab2 != -1) { - /* The pabX values are set in SPROM. Use them. */ - if (phy->type == B43_PHYTYPE_A) { - if ((s8) dev->dev->bus->sprom.itssi_a != 0 && - (s8) dev->dev->bus->sprom.itssi_a != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_a); - else - phy->tgt_idle_tssi = 62; - } else { - if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && - (s8) dev->dev->bus->sprom.itssi_bg != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_bg); - else - phy->tgt_idle_tssi = 62; - } - dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); - if (dyn_tssi2dbm == NULL) { - b43err(dev->wl, "Could not allocate memory " - "for tssi2dbm table\n"); - return -ENOMEM; - } - for (idx = 0; idx < 64; idx++) - if (b43_tssi2dbm_entry - (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate " - "tssi2dBm table\n"); - kfree(dyn_tssi2dbm); - return -ENODEV; - } - phy->tssi2dbm = dyn_tssi2dbm; - phy->dyn_tssi_tbl = 1; - } else { - /* pabX values not set in SPROM. */ - switch (phy->type) { - case B43_PHYTYPE_A: - /* APHY needs a generated table. */ - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate tssi2dBm " - "table (wrong SPROM info)!\n"); - return -ENODEV; - case B43_PHYTYPE_B: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - break; - case B43_PHYTYPE_G: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_g_table; - break; - } - } - - return 0; -} - -int b43_phy_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - bool unsupported = 0; - int err = 0; - - switch (phy->type) { - case B43_PHYTYPE_A: - if (phy->rev == 2 || phy->rev == 3) - b43_phy_inita(dev); - else - unsupported = 1; - break; - case B43_PHYTYPE_G: - b43_phy_initg(dev); - break; - case B43_PHYTYPE_N: - err = b43_phy_initn(dev); - break; - default: - unsupported = 1; - } - if (unsupported) - b43err(dev->wl, "Unknown PHYTYPE found\n"); - - return err; -} - -void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) -{ - struct b43_phy *phy = &dev->phy; - u64 hf; - u16 tmp; - int autodiv = 0; - - if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) - autodiv = 1; - - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); - - switch (phy->type) { - case B43_PHYTYPE_A: - case B43_PHYTYPE_G: - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); - - if (autodiv) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) - tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; - else - tmp |= B43_PHY_ANTDWELL_AUTODIV1; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } - if (phy->type == B43_PHYTYPE_G) { - tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); - if (autodiv) - tmp |= B43_PHY_ANTWRSETT_ARXDIV; - else - tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; - b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); - if (phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= B43_PHY_OFDM61_10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - - tmp = - b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); - tmp = (tmp & 0xFF00) | 0x15; - b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, - tmp); - - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } - } - if (phy->rev >= 6) - b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); - } else { - if (phy->rev < 3) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - tmp = (tmp & 0xFF00) | 0x24; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } else { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= 0x10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - if (phy->analog == 3) { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x1D); - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x3A); - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } - } - } - break; - case B43_PHYTYPE_B: - tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); - break; - case B43_PHYTYPE_N: - b43_nphy_set_rxantenna(dev, antenna); - break; - default: - B43_WARN_ON(1); - } - - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); -} - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_bg(u8 channel) -{ - B43_WARN_ON(!(channel >= 1 && channel <= 14)); - - return b43_radio_channel_codes_bg[channel - 1]; -} - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_a(u8 channel) -{ - B43_WARN_ON(channel > 200); - - return (5000 + 5 * channel); -} - -void b43_radio_lock(struct b43_wldev *dev) -{ - u32 macctl; - - macctl = b43_read32(dev, B43_MMIO_MACCTL); - B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); - macctl |= B43_MACCTL_RADIOLOCK; - b43_write32(dev, B43_MMIO_MACCTL, macctl); - /* Commit the write and wait for the device - * to exit any radio register access. */ - b43_read32(dev, B43_MMIO_MACCTL); - udelay(10); -} - -void b43_radio_unlock(struct b43_wldev *dev) -{ - u32 macctl; - - /* Commit any write */ - b43_read16(dev, B43_MMIO_PHY_VER); - /* unlock */ - macctl = b43_read32(dev, B43_MMIO_MACCTL); - B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); - macctl &= ~B43_MACCTL_RADIOLOCK; - b43_write32(dev, B43_MMIO_MACCTL, macctl); -} - -u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) -{ - struct b43_phy *phy = &dev->phy; - - /* Offset 1 is a 32-bit register. */ - B43_WARN_ON(offset == 1); - - switch (phy->type) { - case B43_PHYTYPE_A: - offset |= 0x40; - break; - case B43_PHYTYPE_B: - if (phy->radio_ver == 0x2053) { - if (offset < 0x70) - offset += 0x80; - else if (offset < 0x80) - offset += 0x70; - } else if (phy->radio_ver == 0x2050) { - offset |= 0x80; - } else - B43_WARN_ON(1); - break; - case B43_PHYTYPE_G: - offset |= 0x80; - break; - case B43_PHYTYPE_N: - offset |= 0x100; - break; - case B43_PHYTYPE_LP: - /* No adjustment required. */ - break; - default: - B43_WARN_ON(1); - } - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); -} - -void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) -{ - /* Offset 1 is a 32-bit register. */ - B43_WARN_ON(offset == 1); - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); -} - -void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) -{ - b43_radio_write16(dev, offset, - b43_radio_read16(dev, offset) & mask); -} - -void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) -{ - b43_radio_write16(dev, offset, - b43_radio_read16(dev, offset) | set); -} - -void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) -{ - b43_radio_write16(dev, offset, - (b43_radio_read16(dev, offset) & mask) | set); -} - -static void b43_set_all_gains(struct b43_wldev *dev, - s16 first, s16 second, s16 third) -{ - struct b43_phy *phy = &dev->phy; - u16 i; - u16 start = 0x08, end = 0x18; - u16 tmp; - u16 table; - - if (phy->rev <= 1) { - start = 0x10; - end = 0x20; - } - - table = B43_OFDMTAB_GAINX; - if (phy->rev <= 1) - table = B43_OFDMTAB_GAINX_R1; - for (i = 0; i < 4; i++) - b43_ofdmtab_write16(dev, table, i, first); - - for (i = start; i < end; i++) - b43_ofdmtab_write16(dev, table, i, second); - - if (third != -1) { - tmp = ((u16) third << 14) | ((u16) third << 6); - b43_phy_write(dev, 0x04A0, - (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); - b43_phy_write(dev, 0x04A1, - (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); - b43_phy_write(dev, 0x04A2, - (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); - } - b43_dummy_transmission(dev); -} - -static void b43_set_original_gains(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 i, tmp; - u16 table; - u16 start = 0x0008, end = 0x0018; - - if (phy->rev <= 1) { - start = 0x0010; - end = 0x0020; - } - - table = B43_OFDMTAB_GAINX; - if (phy->rev <= 1) - table = B43_OFDMTAB_GAINX_R1; - for (i = 0; i < 4; i++) { - tmp = (i & 0xFFFC); - tmp |= (i & 0x0001) << 1; - tmp |= (i & 0x0002) >> 1; - - b43_ofdmtab_write16(dev, table, i, tmp); - } - - for (i = start; i < end; i++) - b43_ofdmtab_write16(dev, table, i, i - start); - - b43_phy_write(dev, 0x04A0, - (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); - b43_phy_write(dev, 0x04A1, - (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); - b43_phy_write(dev, 0x04A2, - (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); - b43_dummy_transmission(dev); -} - -/* Synthetic PU workaround */ -static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) -{ - struct b43_phy *phy = &dev->phy; - - might_sleep(); - - if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { - /* We do not need the workaround. */ - return; - } - - if (channel <= 10) { - b43_write16(dev, B43_MMIO_CHANNEL, - channel2freq_bg(channel + 4)); - } else { - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); - } - msleep(1); - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); -} - -u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel) -{ - struct b43_phy *phy = &dev->phy; - u8 ret = 0; - u16 saved, rssi, temp; - int i, j = 0; - - saved = b43_phy_read(dev, 0x0403); - b43_radio_selectchannel(dev, channel, 0); - b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); - if (phy->aci_hw_rssi) - rssi = b43_phy_read(dev, 0x048A) & 0x3F; - else - rssi = saved & 0x3F; - /* clamp temp to signed 5bit */ - if (rssi > 32) - rssi -= 64; - for (i = 0; i < 100; i++) { - temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; - if (temp > 32) - temp -= 64; - if (temp < rssi) - j++; - if (j >= 20) - ret = 1; - } - b43_phy_write(dev, 0x0403, saved); - - return ret; -} - -u8 b43_radio_aci_scan(struct b43_wldev * dev) -{ - struct b43_phy *phy = &dev->phy; - u8 ret[13]; - unsigned int channel = phy->channel; - unsigned int i, j, start, end; - - if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) - return 0; - - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); - b43_set_all_gains(dev, 3, 8, 1); - - start = (channel - 5 > 0) ? channel - 5 : 1; - end = (channel + 5 < 14) ? channel + 5 : 13; - - for (i = start; i <= end; i++) { - if (abs(channel - i) > 2) - ret[i - 1] = b43_radio_aci_detect(dev, i); - } - b43_radio_selectchannel(dev, channel, 0); - b43_phy_write(dev, 0x0802, - (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); - b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); - b43_set_original_gains(dev); - for (i = 0; i < 13; i++) { - if (!ret[i]) - continue; - end = (i + 5 < 13) ? i + 5 : 13; - for (j = i; j < end; j++) - ret[j] = 1; - } - b43_radio_unlock(dev); - b43_phy_unlock(dev); - - return ret[channel - 1]; -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) -{ - b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); - mmiowb(); - b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) -{ - u16 val; - - b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); - val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA); - - return (s16) val; -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) -{ - u16 i; - s16 tmp; - - for (i = 0; i < 64; i++) { - tmp = b43_nrssi_hw_read(dev, i); - tmp -= val; - tmp = clamp_val(tmp, -32, 31); - b43_nrssi_hw_write(dev, i, tmp); - } -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_mem_update(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s16 i, delta; - s32 tmp; - - delta = 0x1F - phy->nrssi[0]; - for (i = 0; i < 64; i++) { - tmp = (i - delta) * phy->nrssislope; - tmp /= 0x10000; - tmp += 0x3A; - tmp = clamp_val(tmp, 0, 0x3F); - phy->nrssi_lt[i] = tmp; - } -} - -static void b43_calc_nrssi_offset(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup[20] = { 0 }; - s16 v47F; - u16 i; - u16 saved = 0xFFFF; - - backup[0] = b43_phy_read(dev, 0x0001); - backup[1] = b43_phy_read(dev, 0x0811); - backup[2] = b43_phy_read(dev, 0x0812); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - backup[3] = b43_phy_read(dev, 0x0814); - backup[4] = b43_phy_read(dev, 0x0815); - } - backup[5] = b43_phy_read(dev, 0x005A); - backup[6] = b43_phy_read(dev, 0x0059); - backup[7] = b43_phy_read(dev, 0x0058); - backup[8] = b43_phy_read(dev, 0x000A); - backup[9] = b43_phy_read(dev, 0x0003); - backup[10] = b43_radio_read16(dev, 0x007A); - backup[11] = b43_radio_read16(dev, 0x0043); - - b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); - b43_phy_write(dev, 0x0001, - (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); - if (phy->rev >= 6) { - backup[12] = b43_phy_read(dev, 0x002E); - backup[13] = b43_phy_read(dev, 0x002F); - backup[14] = b43_phy_read(dev, 0x080F); - backup[15] = b43_phy_read(dev, 0x0810); - backup[16] = b43_phy_read(dev, 0x0801); - backup[17] = b43_phy_read(dev, 0x0060); - backup[18] = b43_phy_read(dev, 0x0014); - backup[19] = b43_phy_read(dev, 0x0478); - - b43_phy_write(dev, 0x002E, 0); - b43_phy_write(dev, 0x002F, 0); - b43_phy_write(dev, 0x080F, 0); - b43_phy_write(dev, 0x0810, 0); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); - b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); - b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); - } - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); - udelay(30); - - v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F == 31) { - for (i = 7; i >= 4; i--) { - b43_radio_write16(dev, 0x007B, i); - udelay(20); - v47F = - (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F < 31 && saved == 0xFFFF) - saved = i; - } - if (saved == 0xFFFF) - saved = 4; - } else { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, 0x0814, - b43_phy_read(dev, 0x0814) | 0x0001); - b43_phy_write(dev, 0x0815, - b43_phy_read(dev, 0x0815) & 0xFFFE); - } - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); - b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); - b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - if (phy->rev == 0) { - b43_phy_write(dev, 0x0003, 0x0122); - } else { - b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) - | 0x2000); - } - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, 0x0814, - b43_phy_read(dev, 0x0814) | 0x0004); - b43_phy_write(dev, 0x0815, - b43_phy_read(dev, 0x0815) & 0xFFFB); - } - b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) - | 0x0040); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x000F); - b43_set_all_gains(dev, 3, 0, 1); - b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) - & 0x00F0) | 0x000F); - udelay(30); - v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F == -32) { - for (i = 0; i < 4; i++) { - b43_radio_write16(dev, 0x007B, i); - udelay(20); - v47F = - (s16) ((b43_phy_read(dev, 0x047F) >> 8) & - 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F > -31 && saved == 0xFFFF) - saved = i; - } - if (saved == 0xFFFF) - saved = 3; - } else - saved = 0; - } - b43_radio_write16(dev, 0x007B, saved); - - if (phy->rev >= 6) { - b43_phy_write(dev, 0x002E, backup[12]); - b43_phy_write(dev, 0x002F, backup[13]); - b43_phy_write(dev, 0x080F, backup[14]); - b43_phy_write(dev, 0x0810, backup[15]); - } - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, 0x0814, backup[3]); - b43_phy_write(dev, 0x0815, backup[4]); - } - b43_phy_write(dev, 0x005A, backup[5]); - b43_phy_write(dev, 0x0059, backup[6]); - b43_phy_write(dev, 0x0058, backup[7]); - b43_phy_write(dev, 0x000A, backup[8]); - b43_phy_write(dev, 0x0003, backup[9]); - b43_radio_write16(dev, 0x0043, backup[11]); - b43_radio_write16(dev, 0x007A, backup[10]); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); - b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); - b43_set_original_gains(dev); - if (phy->rev >= 6) { - b43_phy_write(dev, 0x0801, backup[16]); - b43_phy_write(dev, 0x0060, backup[17]); - b43_phy_write(dev, 0x0014, backup[18]); - b43_phy_write(dev, 0x0478, backup[19]); - } - b43_phy_write(dev, 0x0001, backup[0]); - b43_phy_write(dev, 0x0812, backup[2]); - b43_phy_write(dev, 0x0811, backup[1]); -} - -void b43_calc_nrssi_slope(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup[18] = { 0 }; - u16 tmp; - s16 nrssi0, nrssi1; - - switch (phy->type) { - case B43_PHYTYPE_B: - backup[0] = b43_radio_read16(dev, 0x007A); - backup[1] = b43_radio_read16(dev, 0x0052); - backup[2] = b43_radio_read16(dev, 0x0043); - backup[3] = b43_phy_read(dev, 0x0030); - backup[4] = b43_phy_read(dev, 0x0026); - backup[5] = b43_phy_read(dev, 0x0015); - backup[6] = b43_phy_read(dev, 0x002A); - backup[7] = b43_phy_read(dev, 0x0020); - backup[8] = b43_phy_read(dev, 0x005A); - backup[9] = b43_phy_read(dev, 0x0059); - backup[10] = b43_phy_read(dev, 0x0058); - backup[11] = b43_read16(dev, 0x03E2); - backup[12] = b43_read16(dev, 0x03E6); - backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); - - tmp = b43_radio_read16(dev, 0x007A); - tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; - b43_radio_write16(dev, 0x007A, tmp); - b43_phy_write(dev, 0x0030, 0x00FF); - b43_write16(dev, 0x03EC, 0x7F7F); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020); - b43_phy_write(dev, 0x002A, 0x08A3); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0080); - - nrssi0 = (s16) b43_phy_read(dev, 0x0027); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev >= 2) { - b43_write16(dev, 0x03E6, 0x0040); - } else if (phy->rev == 0) { - b43_write16(dev, 0x03E6, 0x0122); - } else { - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, - B43_MMIO_CHANNEL_EXT) & 0x2000); - } - b43_phy_write(dev, 0x0020, 0x3F3F); - b43_phy_write(dev, 0x0015, 0xF330); - b43_radio_write16(dev, 0x005A, 0x0060); - b43_radio_write16(dev, 0x0043, - b43_radio_read16(dev, 0x0043) & 0x00F0); - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - udelay(20); - - nrssi1 = (s16) b43_phy_read(dev, 0x0027); - b43_phy_write(dev, 0x0030, backup[3]); - b43_radio_write16(dev, 0x007A, backup[0]); - b43_write16(dev, 0x03E2, backup[11]); - b43_phy_write(dev, 0x0026, backup[4]); - b43_phy_write(dev, 0x0015, backup[5]); - b43_phy_write(dev, 0x002A, backup[6]); - b43_synth_pu_workaround(dev, phy->channel); - if (phy->rev != 0) - b43_write16(dev, 0x03F4, backup[13]); - - b43_phy_write(dev, 0x0020, backup[7]); - b43_phy_write(dev, 0x005A, backup[8]); - b43_phy_write(dev, 0x0059, backup[9]); - b43_phy_write(dev, 0x0058, backup[10]); - b43_radio_write16(dev, 0x0052, backup[1]); - b43_radio_write16(dev, 0x0043, backup[2]); - - if (nrssi0 == nrssi1) - phy->nrssislope = 0x00010000; - else - phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - - if (nrssi0 <= -4) { - phy->nrssi[0] = nrssi0; - phy->nrssi[1] = nrssi1; - } - break; - case B43_PHYTYPE_G: - if (phy->radio_rev >= 9) - return; - if (phy->radio_rev == 8) - b43_calc_nrssi_offset(dev); - - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); - backup[7] = b43_read16(dev, 0x03E2); - b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); - backup[0] = b43_radio_read16(dev, 0x007A); - backup[1] = b43_radio_read16(dev, 0x0052); - backup[2] = b43_radio_read16(dev, 0x0043); - backup[3] = b43_phy_read(dev, 0x0015); - backup[4] = b43_phy_read(dev, 0x005A); - backup[5] = b43_phy_read(dev, 0x0059); - backup[6] = b43_phy_read(dev, 0x0058); - backup[8] = b43_read16(dev, 0x03E6); - backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); - if (phy->rev >= 3) { - backup[10] = b43_phy_read(dev, 0x002E); - backup[11] = b43_phy_read(dev, 0x002F); - backup[12] = b43_phy_read(dev, 0x080F); - backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); - backup[14] = b43_phy_read(dev, 0x0801); - backup[15] = b43_phy_read(dev, 0x0060); - backup[16] = b43_phy_read(dev, 0x0014); - backup[17] = b43_phy_read(dev, 0x0478); - b43_phy_write(dev, 0x002E, 0); - b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); - switch (phy->rev) { - case 4: - case 6: - case 7: - b43_phy_write(dev, 0x0478, - b43_phy_read(dev, 0x0478) - | 0x0100); - b43_phy_write(dev, 0x0801, - b43_phy_read(dev, 0x0801) - | 0x0040); - break; - case 3: - case 5: - b43_phy_write(dev, 0x0801, - b43_phy_read(dev, 0x0801) - & 0xFFBF); - break; - } - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) - | 0x0040); - b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) - | 0x0200); - } - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0070); - b43_set_all_gains(dev, 0, 8, 0); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x00F7); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0811, - (b43_phy_read(dev, 0x0811) & 0xFFCF) | - 0x0030); - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFCF) | - 0x0010); - } - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0080); - udelay(20); - - nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (nrssi0 >= 0x0020) - nrssi0 -= 0x0040; - - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) - & 0xFF9F) | 0x0040); - } - - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - | 0x2000); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x000F); - b43_phy_write(dev, 0x0015, 0xF330); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFCF) | - 0x0020); - b43_phy_write(dev, 0x0811, - (b43_phy_read(dev, 0x0811) & 0xFFCF) | - 0x0020); - } - - b43_set_all_gains(dev, 3, 0, 1); - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x0043, 0x001F); - } else { - tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; - b43_radio_write16(dev, 0x0052, tmp | 0x0060); - tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; - b43_radio_write16(dev, 0x0043, tmp | 0x0009); - } - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - udelay(20); - nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (nrssi1 >= 0x0020) - nrssi1 -= 0x0040; - if (nrssi0 == nrssi1) - phy->nrssislope = 0x00010000; - else - phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - if (nrssi0 >= -4) { - phy->nrssi[0] = nrssi1; - phy->nrssi[1] = nrssi0; - } - if (phy->rev >= 3) { - b43_phy_write(dev, 0x002E, backup[10]); - b43_phy_write(dev, 0x002F, backup[11]); - b43_phy_write(dev, 0x080F, backup[12]); - b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); - } - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0812, - b43_phy_read(dev, 0x0812) & 0xFFCF); - b43_phy_write(dev, 0x0811, - b43_phy_read(dev, 0x0811) & 0xFFCF); - } - - b43_radio_write16(dev, 0x007A, backup[0]); - b43_radio_write16(dev, 0x0052, backup[1]); - b43_radio_write16(dev, 0x0043, backup[2]); - b43_write16(dev, 0x03E2, backup[7]); - b43_write16(dev, 0x03E6, backup[8]); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); - b43_phy_write(dev, 0x0015, backup[3]); - b43_phy_write(dev, 0x005A, backup[4]); - b43_phy_write(dev, 0x0059, backup[5]); - b43_phy_write(dev, 0x0058, backup[6]); - b43_synth_pu_workaround(dev, phy->channel); - b43_phy_write(dev, 0x0802, - b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); - b43_set_original_gains(dev); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); - if (phy->rev >= 3) { - b43_phy_write(dev, 0x0801, backup[14]); - b43_phy_write(dev, 0x0060, backup[15]); - b43_phy_write(dev, 0x0014, backup[16]); - b43_phy_write(dev, 0x0478, backup[17]); - } - b43_nrssi_mem_update(dev); - b43_calc_nrssi_threshold(dev); - break; - default: - B43_WARN_ON(1); - } -} - -void b43_calc_nrssi_threshold(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s32 threshold; - s32 a, b; - s16 tmp16; - u16 tmp_u16; - - switch (phy->type) { - case B43_PHYTYPE_B:{ - if (phy->radio_ver != 0x2050) - return; - if (! - (dev->dev->bus->sprom. - boardflags_lo & B43_BFL_RSSI)) - return; - - if (phy->radio_rev >= 6) { - threshold = - (phy->nrssi[1] - phy->nrssi[0]) * 32; - threshold += 20 * (phy->nrssi[0] + 1); - threshold /= 40; - } else - threshold = phy->nrssi[1] - 5; - - threshold = clamp_val(threshold, 0, 0x3E); - b43_phy_read(dev, 0x0020); /* dummy read */ - b43_phy_write(dev, 0x0020, - (((u16) threshold) << 8) | 0x001C); - - if (phy->radio_rev >= 6) { - b43_phy_write(dev, 0x0087, 0x0E0D); - b43_phy_write(dev, 0x0086, 0x0C0B); - b43_phy_write(dev, 0x0085, 0x0A09); - b43_phy_write(dev, 0x0084, 0x0808); - b43_phy_write(dev, 0x0083, 0x0808); - b43_phy_write(dev, 0x0082, 0x0604); - b43_phy_write(dev, 0x0081, 0x0302); - b43_phy_write(dev, 0x0080, 0x0100); - } - break; - } - case B43_PHYTYPE_G: - if (!phy->gmode || - !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { - tmp16 = b43_nrssi_hw_read(dev, 0x20); - if (tmp16 >= 0x20) - tmp16 -= 0x40; - if (tmp16 < 3) { - b43_phy_write(dev, 0x048A, - (b43_phy_read(dev, 0x048A) - & 0xF000) | 0x09EB); - } else { - b43_phy_write(dev, 0x048A, - (b43_phy_read(dev, 0x048A) - & 0xF000) | 0x0AED); - } - } else { - if (phy->interfmode == B43_INTERFMODE_NONWLAN) { - a = 0xE; - b = 0xA; - } else if (!phy->aci_wlan_automatic && phy->aci_enable) { - a = 0x13; - b = 0x12; - } else { - a = 0xE; - b = 0x11; - } - - a = a * (phy->nrssi[1] - phy->nrssi[0]); - a += (phy->nrssi[0] << 6); - if (a < 32) - a += 31; - else - a += 32; - a = a >> 6; - a = clamp_val(a, -31, 31); - - b = b * (phy->nrssi[1] - phy->nrssi[0]); - b += (phy->nrssi[0] << 6); - if (b < 32) - b += 31; - else - b += 32; - b = b >> 6; - b = clamp_val(b, -31, 31); - - tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; - tmp_u16 |= ((u32) b & 0x0000003F); - tmp_u16 |= (((u32) a & 0x0000003F) << 6); - b43_phy_write(dev, 0x048A, tmp_u16); - } - break; - default: - B43_WARN_ON(1); - } -} - -/* Stack implementation to save/restore values from the - * interference mitigation code. - * It is save to restore values in random order. - */ -static void _stack_save(u32 * _stackptr, size_t * stackidx, - u8 id, u16 offset, u16 value) -{ - u32 *stackptr = &(_stackptr[*stackidx]); - - B43_WARN_ON(offset & 0xF000); - B43_WARN_ON(id & 0xF0); - *stackptr = offset; - *stackptr |= ((u32) id) << 12; - *stackptr |= ((u32) value) << 16; - (*stackidx)++; - B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); -} - -static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) -{ - size_t i; - - B43_WARN_ON(offset & 0xF000); - B43_WARN_ON(id & 0xF0); - for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) { - if ((*stackptr & 0x00000FFF) != offset) - continue; - if (((*stackptr & 0x0000F000) >> 12) != id) - continue; - return ((*stackptr & 0xFFFF0000) >> 16); - } - B43_WARN_ON(1); - - return 0; -} - -#define phy_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x1, (offset), \ - b43_phy_read(dev, (offset))); \ - } while (0) -#define phy_stackrestore(offset) \ - do { \ - b43_phy_write(dev, (offset), \ - _stack_restore(stack, 0x1, \ - (offset))); \ - } while (0) -#define radio_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x2, (offset), \ - b43_radio_read16(dev, (offset))); \ - } while (0) -#define radio_stackrestore(offset) \ - do { \ - b43_radio_write16(dev, (offset), \ - _stack_restore(stack, 0x2, \ - (offset))); \ - } while (0) -#define ofdmtab_stacksave(table, offset) \ - do { \ - _stack_save(stack, &stackidx, 0x3, (offset)|(table), \ - b43_ofdmtab_read16(dev, (table), (offset))); \ - } while (0) -#define ofdmtab_stackrestore(table, offset) \ - do { \ - b43_ofdmtab_write16(dev, (table), (offset), \ - _stack_restore(stack, 0x3, \ - (offset)|(table))); \ - } while (0) - -static void -b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - u16 tmp, flipped; - size_t stackidx = 0; - u32 *stack = phy->interfstack; - - switch (mode) { - case B43_INTERFMODE_NONWLAN: - if (phy->rev != 1) { - b43_phy_write(dev, 0x042B, - b43_phy_read(dev, 0x042B) | 0x0800); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, - B43_PHY_G_CRS) & ~0x4000); - break; - } - radio_stacksave(0x0078); - tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); - B43_WARN_ON(tmp > 15); - flipped = bitrev4(tmp); - if (flipped < 10 && flipped >= 8) - flipped = 7; - else if (flipped >= 10) - flipped -= 3; - flipped = (bitrev4(flipped) << 1) | 0x0020; - b43_radio_write16(dev, 0x0078, flipped); - - b43_calc_nrssi_threshold(dev); - - phy_stacksave(0x0406); - b43_phy_write(dev, 0x0406, 0x7E28); - - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, - B43_PHY_RADIO_BITFIELD) | 0x1000); - - phy_stacksave(0x04A0); - b43_phy_write(dev, 0x04A0, - (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); - phy_stacksave(0x04A1); - b43_phy_write(dev, 0x04A1, - (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); - phy_stacksave(0x04A2); - b43_phy_write(dev, 0x04A2, - (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); - phy_stacksave(0x04A8); - b43_phy_write(dev, 0x04A8, - (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); - phy_stacksave(0x04AB); - b43_phy_write(dev, 0x04AB, - (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); - - phy_stacksave(0x04A7); - b43_phy_write(dev, 0x04A7, 0x0002); - phy_stacksave(0x04A3); - b43_phy_write(dev, 0x04A3, 0x287A); - phy_stacksave(0x04A9); - b43_phy_write(dev, 0x04A9, 0x2027); - phy_stacksave(0x0493); - b43_phy_write(dev, 0x0493, 0x32F5); - phy_stacksave(0x04AA); - b43_phy_write(dev, 0x04AA, 0x2027); - phy_stacksave(0x04AC); - b43_phy_write(dev, 0x04AC, 0x32F5); - break; - case B43_INTERFMODE_MANUALWLAN: - if (b43_phy_read(dev, 0x0033) & 0x0800) - break; - - phy->aci_enable = 1; - - phy_stacksave(B43_PHY_RADIO_BITFIELD); - phy_stacksave(B43_PHY_G_CRS); - if (phy->rev < 2) { - phy_stacksave(0x0406); - } else { - phy_stacksave(0x04C0); - phy_stacksave(0x04C1); - } - phy_stacksave(0x0033); - phy_stacksave(0x04A7); - phy_stacksave(0x04A3); - phy_stacksave(0x04A9); - phy_stacksave(0x04AA); - phy_stacksave(0x04AC); - phy_stacksave(0x0493); - phy_stacksave(0x04A1); - phy_stacksave(0x04A0); - phy_stacksave(0x04A2); - phy_stacksave(0x048A); - phy_stacksave(0x04A8); - phy_stacksave(0x04AB); - if (phy->rev == 2) { - phy_stacksave(0x04AD); - phy_stacksave(0x04AE); - } else if (phy->rev >= 3) { - phy_stacksave(0x04AD); - phy_stacksave(0x0415); - phy_stacksave(0x0416); - phy_stacksave(0x0417); - ofdmtab_stacksave(0x1A00, 0x2); - ofdmtab_stacksave(0x1A00, 0x3); - } - phy_stacksave(0x042B); - phy_stacksave(0x048C); - - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) - & ~0x1000); - b43_phy_write(dev, B43_PHY_G_CRS, - (b43_phy_read(dev, B43_PHY_G_CRS) - & 0xFFFC) | 0x0002); - - b43_phy_write(dev, 0x0033, 0x0800); - b43_phy_write(dev, 0x04A3, 0x2027); - b43_phy_write(dev, 0x04A9, 0x1CA8); - b43_phy_write(dev, 0x0493, 0x287A); - b43_phy_write(dev, 0x04AA, 0x1CA8); - b43_phy_write(dev, 0x04AC, 0x287A); - - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xFFC0) | 0x001A); - b43_phy_write(dev, 0x04A7, 0x000D); - - if (phy->rev < 2) { - b43_phy_write(dev, 0x0406, 0xFF0D); - } else if (phy->rev == 2) { - b43_phy_write(dev, 0x04C0, 0xFFFF); - b43_phy_write(dev, 0x04C1, 0x00A9); - } else { - b43_phy_write(dev, 0x04C0, 0x00C1); - b43_phy_write(dev, 0x04C1, 0x0059); - } - - b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) - & 0xC0FF) | 0x1800); - b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) - & 0xFFC0) | 0x0015); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xCFFF) | 0x1000); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xF0FF) | 0x0A00); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xCFFF) | 0x1000); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xF0FF) | 0x0800); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xFFCF) | 0x0010); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xFFF0) | 0x0005); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xFFCF) | 0x0010); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xFFF0) | 0x0006); - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xF0FF) | 0x0800); - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xF0FF) | 0x0500); - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xFFF0) | 0x000B); - - if (phy->rev >= 3) { - b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) - & ~0x8000); - b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) - & 0x8000) | 0x36D8); - b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) - & 0x8000) | 0x36D8); - b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) - & 0xFE00) | 0x016D); - } else { - b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) - | 0x1000); - b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) - & 0x9FFF) | 0x2000); - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); - } - if (phy->rev >= 2) { - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) - | 0x0800); - } - b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) - & 0xF0FF) | 0x0200); - if (phy->rev == 2) { - b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) - & 0xFF00) | 0x007F); - b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) - & 0x00FF) | 0x1300); - } else if (phy->rev >= 6) { - b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); - b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); - b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) - & 0x00FF); - } - b43_calc_nrssi_slope(dev); - break; - default: - B43_WARN_ON(1); - } -} - -static void -b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - u32 *stack = phy->interfstack; - - switch (mode) { - case B43_INTERFMODE_NONWLAN: - if (phy->rev != 1) { - b43_phy_write(dev, 0x042B, - b43_phy_read(dev, 0x042B) & ~0x0800); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, - B43_PHY_G_CRS) | 0x4000); - break; - } - radio_stackrestore(0x0078); - b43_calc_nrssi_threshold(dev); - phy_stackrestore(0x0406); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); - if (!dev->bad_frames_preempt) { - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) - & ~(1 << 11)); - } - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); - phy_stackrestore(0x04A0); - phy_stackrestore(0x04A1); - phy_stackrestore(0x04A2); - phy_stackrestore(0x04A8); - phy_stackrestore(0x04AB); - phy_stackrestore(0x04A7); - phy_stackrestore(0x04A3); - phy_stackrestore(0x04A9); - phy_stackrestore(0x0493); - phy_stackrestore(0x04AA); - phy_stackrestore(0x04AC); - break; - case B43_INTERFMODE_MANUALWLAN: - if (!(b43_phy_read(dev, 0x0033) & 0x0800)) - break; - - phy->aci_enable = 0; - - phy_stackrestore(B43_PHY_RADIO_BITFIELD); - phy_stackrestore(B43_PHY_G_CRS); - phy_stackrestore(0x0033); - phy_stackrestore(0x04A3); - phy_stackrestore(0x04A9); - phy_stackrestore(0x0493); - phy_stackrestore(0x04AA); - phy_stackrestore(0x04AC); - phy_stackrestore(0x04A0); - phy_stackrestore(0x04A7); - if (phy->rev >= 2) { - phy_stackrestore(0x04C0); - phy_stackrestore(0x04C1); - } else - phy_stackrestore(0x0406); - phy_stackrestore(0x04A1); - phy_stackrestore(0x04AB); - phy_stackrestore(0x04A8); - if (phy->rev == 2) { - phy_stackrestore(0x04AD); - phy_stackrestore(0x04AE); - } else if (phy->rev >= 3) { - phy_stackrestore(0x04AD); - phy_stackrestore(0x0415); - phy_stackrestore(0x0416); - phy_stackrestore(0x0417); - ofdmtab_stackrestore(0x1A00, 0x2); - ofdmtab_stackrestore(0x1A00, 0x3); - } - phy_stackrestore(0x04A2); - phy_stackrestore(0x048A); - phy_stackrestore(0x042B); - phy_stackrestore(0x048C); - b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW); - b43_calc_nrssi_slope(dev); - break; - default: - B43_WARN_ON(1); - } -} - -#undef phy_stacksave -#undef phy_stackrestore -#undef radio_stacksave -#undef radio_stackrestore -#undef ofdmtab_stacksave -#undef ofdmtab_stackrestore - -int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - int currentmode; - - if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode)) - return -ENODEV; - - phy->aci_wlan_automatic = 0; - switch (mode) { - case B43_INTERFMODE_AUTOWLAN: - phy->aci_wlan_automatic = 1; - if (phy->aci_enable) - mode = B43_INTERFMODE_MANUALWLAN; - else - mode = B43_INTERFMODE_NONE; - break; - case B43_INTERFMODE_NONE: - case B43_INTERFMODE_NONWLAN: - case B43_INTERFMODE_MANUALWLAN: - break; - default: - return -EINVAL; - } - - currentmode = phy->interfmode; - if (currentmode == mode) - return 0; - if (currentmode != B43_INTERFMODE_NONE) - b43_radio_interference_mitigation_disable(dev, currentmode); - - if (mode == B43_INTERFMODE_NONE) { - phy->aci_enable = 0; - phy->aci_hw_rssi = 0; - } else - b43_radio_interference_mitigation_enable(dev, mode); - phy->interfmode = mode; - - return 0; -} - -static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) -{ - u16 reg, index, ret; - - static const u8 rcc_table[] = { - 0x02, 0x03, 0x01, 0x0F, - 0x06, 0x07, 0x05, 0x0F, - 0x0A, 0x0B, 0x09, 0x0F, - 0x0E, 0x0F, 0x0D, 0x0F, - }; - - reg = b43_radio_read16(dev, 0x60); - index = (reg & 0x001E) >> 1; - ret = rcc_table[index] << 1; - ret |= (reg & 0x0001); - ret |= 0x0020; - - return ret; -} - -#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) -static u16 radio2050_rfover_val(struct b43_wldev *dev, - u16 phy_register, unsigned int lpd) -{ - struct b43_phy *phy = &dev->phy; - struct ssb_sprom *sprom = &(dev->dev->bus->sprom); - - if (!phy->gmode) - return 0; - - if (has_loopback_gain(phy)) { - int max_lb_gain = phy->max_lb_gain; - u16 extlna; - u16 i; - - if (phy->radio_rev == 8) - max_lb_gain += 0x3E; - else - max_lb_gain += 0x26; - if (max_lb_gain >= 0x46) { - extlna = 0x3000; - max_lb_gain -= 0x46; - } else if (max_lb_gain >= 0x3A) { - extlna = 0x1000; - max_lb_gain -= 0x3A; - } else if (max_lb_gain >= 0x2E) { - extlna = 0x2000; - max_lb_gain -= 0x2E; - } else { - extlna = 0; - max_lb_gain -= 0x10; - } - - for (i = 0; i < 16; i++) { - max_lb_gain -= (i * 6); - if (max_lb_gain < 6) - break; - } - - if ((phy->rev < 7) || - !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { - if (phy_register == B43_PHY_RFOVER) { - return 0x1B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - extlna |= (i << 8); - switch (lpd) { - case LPD(0, 1, 1): - return 0x0F92; - case LPD(0, 0, 1): - case LPD(1, 0, 1): - return (0x0092 | extlna); - case LPD(1, 0, 0): - return (0x0093 | extlna); - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } else { - if (phy_register == B43_PHY_RFOVER) { - return 0x9B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - if (extlna) - extlna |= 0x8000; - extlna |= (i << 8); - switch (lpd) { - case LPD(0, 1, 1): - return 0x8F92; - case LPD(0, 0, 1): - return (0x8092 | extlna); - case LPD(1, 0, 1): - return (0x2092 | extlna); - case LPD(1, 0, 0): - return (0x2093 | extlna); - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } - } else { - if ((phy->rev < 7) || - !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { - if (phy_register == B43_PHY_RFOVER) { - return 0x1B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - switch (lpd) { - case LPD(0, 1, 1): - return 0x0FB2; - case LPD(0, 0, 1): - return 0x00B2; - case LPD(1, 0, 1): - return 0x30B2; - case LPD(1, 0, 0): - return 0x30B3; - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } else { - if (phy_register == B43_PHY_RFOVER) { - return 0x9B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - switch (lpd) { - case LPD(0, 1, 1): - return 0x8FB2; - case LPD(0, 0, 1): - return 0x80B2; - case LPD(1, 0, 1): - return 0x20B2; - case LPD(1, 0, 0): - return 0x20B3; - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } - } - return 0; -} - -struct init2050_saved_values { - /* Core registers */ - u16 reg_3EC; - u16 reg_3E6; - u16 reg_3F4; - /* Radio registers */ - u16 radio_43; - u16 radio_51; - u16 radio_52; - /* PHY registers */ - u16 phy_pgactl; - u16 phy_cck_5A; - u16 phy_cck_59; - u16 phy_cck_58; - u16 phy_cck_30; - u16 phy_rfover; - u16 phy_rfoverval; - u16 phy_analogover; - u16 phy_analogoverval; - u16 phy_crs0; - u16 phy_classctl; - u16 phy_lo_mask; - u16 phy_lo_ctl; - u16 phy_syncctl; -}; - -u16 b43_radio_init2050(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct init2050_saved_values sav; - u16 rcc; - u16 radio78; - u16 ret; - u16 i, j; - u32 tmp1 = 0, tmp2 = 0; - - memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */ - - sav.radio_43 = b43_radio_read16(dev, 0x43); - sav.radio_51 = b43_radio_read16(dev, 0x51); - sav.radio_52 = b43_radio_read16(dev, 0x52); - sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); - sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A)); - sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59)); - sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58)); + } + b43_shm_clear_tssi(dev); - if (phy->type == B43_PHYTYPE_B) { - sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); - sav.reg_3EC = b43_read16(dev, 0x3EC); + average = (v0 + v1 + v2 + v3 + 2) / 4; - b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF); - b43_write16(dev, 0x3EC, 0x3F3F); - } else if (phy->gmode || phy->rev >= 2) { - sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); - sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); - sav.phy_analogoverval = - b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); - sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); - sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + if (tmp + && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & + 0x8)) + average -= 13; - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) - | 0x0003); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) - & 0xFFFC); - b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) - & 0x7FFF); - b43_phy_write(dev, B43_PHY_CLASSCTL, - b43_phy_read(dev, B43_PHY_CLASSCTL) - & 0xFFFC); - if (has_loopback_gain(phy)) { - sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); - sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); + estimated_pwr = + b43_phy_estimate_power_out(dev, average); - if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); - else - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); - b43_phy_write(dev, B43_PHY_LO_CTL, 0); - } + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if ((dev->dev->bus->sprom.boardflags_lo + & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, - LPD(0, 1, 1))); - b43_phy_write(dev, B43_PHY_RFOVER, - radio2050_rfover_val(dev, B43_PHY_RFOVER, 0)); - } - b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); + /*TODO: + max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ - sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); - b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) - & 0xFF7F); - sav.reg_3E6 = b43_read16(dev, 0x3E6); - sav.reg_3F4 = b43_read16(dev, 0x3F4); + /* Get desired power (in Q5.2) */ + desired_pwr = INT_TO_Q52(phy->power_level); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "Current TX power output: " Q52_FMT + " dBm, " "Desired TX power output: " + Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + } - if (phy->analog == 0) { - b43_write16(dev, 0x03E6, 0x0122); - } else { - if (phy->analog >= 2) { - b43_phy_write(dev, B43_PHY_CCK(0x03), - (b43_phy_read(dev, B43_PHY_CCK(0x03)) - & 0xFFBF) | 0x40); - } - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); - } + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; - rcc = b43_radio_core_calibration_value(dev); + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; - if (phy->type == B43_PHYTYPE_B) - b43_radio_write16(dev, 0x78, 0x26); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, - LPD(0, 1, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); - b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, - LPD(0, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); - b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) - | 0x0004); - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, 0x1F); - } else { - b43_radio_write16(dev, 0x52, 0); - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | 0x0009); - } - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; - for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 0))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); - udelay(20); - tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - } - udelay(10); + /* So do we finally need to adjust something? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + return; - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); - tmp1++; - tmp1 >>= 9; + /* Calculate the new attenuation values. */ + bbatt = phy->bbatt.att; + bbatt += bbatt_delta; + rfatt = phy->rfatt.att; + rfatt += rfatt_delta; - for (i = 0; i < 16; i++) { - radio78 = (bitrev4(i) << 1) | 0x0020; - b43_radio_write16(dev, 0x78, radio78); - udelay(10); - for (j = 0; j < 16; j++) { - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 0))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); - udelay(10); - tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 1))); + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = phy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - } - tmp2++; - tmp2 >>= 8; - if (tmp1 < tmp2) - break; - } + /* Save the control values */ + phy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + phy->rfatt.att = rfatt; + phy->bbatt.att = bbatt; - /* Restore the registers */ - b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl); - b43_radio_write16(dev, 0x51, sav.radio_51); - b43_radio_write16(dev, 0x52, sav.radio_52); - b43_radio_write16(dev, 0x43, sav.radio_43); - b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A); - b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59); - b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58); - b43_write16(dev, 0x3E6, sav.reg_3E6); - if (phy->analog != 0) - b43_write16(dev, 0x3F4, sav.reg_3F4); - b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); - b43_synth_pu_workaround(dev, phy->channel); - if (phy->type == B43_PHYTYPE_B) { - b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30); - b43_write16(dev, 0x3EC, sav.reg_3EC); - } else if (phy->gmode) { - b43_write16(dev, B43_MMIO_PHY_RADIO, - b43_read16(dev, B43_MMIO_PHY_RADIO) - & 0x7FFF); - b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover); - b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval); - b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - sav.phy_analogoverval); - b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0); - b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl); - if (has_loopback_gain(phy)) { - b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask); - b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl); + /* Adjust the hardware */ + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, + phy->tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev); + break; } + case B43_PHYTYPE_N: + b43_nphy_xmitpower(dev); + break; + default: + B43_WARN_ON(1); } - if (i > 15) - ret = radio78; - else - ret = rcc; - - return ret; } -void b43_radio_init2060(struct b43_wldev *dev) +static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) { - int err; - - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_radio_write16(dev, 0x0009, 0x0040); - b43_radio_write16(dev, 0x0005, 0x00AA); - b43_radio_write16(dev, 0x0032, 0x008F); - b43_radio_write16(dev, 0x0006, 0x008F); - b43_radio_write16(dev, 0x0034, 0x008F); - b43_radio_write16(dev, 0x002C, 0x0007); - b43_radio_write16(dev, 0x0082, 0x0080); - b43_radio_write16(dev, 0x0080, 0x0000); - b43_radio_write16(dev, 0x003F, 0x00DA); - b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); - msleep(1); /* delay 400usec */ - - b43_radio_write16(dev, 0x0081, - (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); - msleep(1); /* delay 400usec */ - - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); - b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); - b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); - b43_radio_write16(dev, 0x0081, - (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); - b43_phy_write(dev, 0x0063, 0xDDC6); - b43_phy_write(dev, 0x0069, 0x07BE); - b43_phy_write(dev, 0x006A, 0x0000); - - err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0); - B43_WARN_ON(err); - - msleep(1); + if (num < 0) + return num / den; + else + return (num + den / 2) / den; } -static inline u16 freq_r3A_value(u16 frequency) +static inline + s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) { - u16 value; - - if (frequency < 5091) - value = 0x0040; - else if (frequency < 5321) - value = 0x0000; - else if (frequency < 5806) - value = 0x0080; - else - value = 0x0040; + s32 m1, m2, f = 256, q, delta; + s8 i = 0; - return value; + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; } -void b43_radio_set_tx_iq(struct b43_wldev *dev) +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) { - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = b43_radio_read16(dev, 0x001E); - int i, j; + struct b43_phy *phy = &dev->phy; + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] << 4 | data_low[j])) { - b43_phy_write(dev, 0x0069, - (i - j) << 8 | 0x00C0); - return; - } - } + if (phy->type == B43_PHYTYPE_A) { + pab0 = (s16) (dev->dev->bus->sprom.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.pa1b2); + } else { + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); } -} -int b43_radio_selectchannel(struct b43_wldev *dev, - u8 channel, int synthetic_pu_workaround) -{ - struct b43_phy *phy = &dev->phy; - u16 r8, tmp; - u16 freq; - u16 channelcookie, savedcookie; - int err = 0; + if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; + return 0; + } - if (channel == 0xFF) { + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == B43_PHYTYPE_A) { + if ((s8) dev->dev->bus->sprom.itssi_a != 0 && + (s8) dev->dev->bus->sprom.itssi_a != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_a); + else + phy->tgt_idle_tssi = 62; + } else { + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_bg); + else + phy->tgt_idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + b43err(dev->wl, "Could not allocate memory " + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (b43_tssi2dbm_entry + (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ switch (phy->type) { case B43_PHYTYPE_A: - channel = B43_DEFAULT_CHANNEL_A; - break; + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - channel = B43_DEFAULT_CHANNEL_BG; + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; break; - case B43_PHYTYPE_N: - //FIXME check if we are on 2.4GHz or 5GHz and set a default channel. - channel = 1; + case B43_PHYTYPE_G: + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_g_table; break; - default: - B43_WARN_ON(1); - } - } - - /* First we set the channel radio code to prevent the - * firmware from sending ghost packets. - */ - channelcookie = channel; - if (0 /*FIXME on 5Ghz */) - channelcookie |= 0x100; - //FIXME set 40Mhz flag if required - savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); - - switch (phy->type) { - case B43_PHYTYPE_A: - if (channel > 200) { - err = -EINVAL; - goto out; - } - freq = channel2freq_a(channel); - - r8 = b43_radio_read16(dev, 0x0008); - b43_write16(dev, 0x03F0, freq); - b43_radio_write16(dev, 0x0008, r8); - - //TODO: write max channel TX power? to Radio 0x2D - tmp = b43_radio_read16(dev, 0x002E); - tmp &= 0x0080; - //TODO: OR tmp with the Power out estimation for this channel? - b43_radio_write16(dev, 0x002E, tmp); - - if (freq >= 4920 && freq <= 5500) { - /* - * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; - * = (freq * 0.025862069 - */ - r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ - } - b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) - & 0x000F) | (r8 << 4)); - b43_radio_write16(dev, 0x002A, (r8 << 4)); - b43_radio_write16(dev, 0x002B, (r8 << 4)); - b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) - & 0x00F0) | (r8 << 4)); - b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) - & 0xFF0F) | 0x00B0); - b43_radio_write16(dev, 0x0035, 0x00AA); - b43_radio_write16(dev, 0x0036, 0x0085); - b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) - & 0xFF20) | - freq_r3A_value(freq)); - b43_radio_write16(dev, 0x003D, - b43_radio_read16(dev, 0x003D) & 0x00FF); - b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) - & 0xFF7F) | 0x0080); - b43_radio_write16(dev, 0x0035, - b43_radio_read16(dev, 0x0035) & 0xFFEF); - b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) - & 0xFFEF) | 0x0010); - b43_radio_set_tx_iq(dev); - //TODO: TSSI2dbm workaround - b43_phy_xmitpower(dev); //FIXME correct? - break; - case B43_PHYTYPE_G: - if ((channel < 1) || (channel > 14)) { - err = -EINVAL; - goto out; } - - if (synthetic_pu_workaround) - b43_synth_pu_workaround(dev, channel); - - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); - - if (channel == 14) { - if (dev->dev->bus->sprom.country_code == - SSB_SPROM1CCODE_JAPAN) - b43_hf_write(dev, - b43_hf_read(dev) & ~B43_HF_ACPR); - else - b43_hf_write(dev, - b43_hf_read(dev) | B43_HF_ACPR); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - | (1 << 11)); - } else { - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - & 0xF7BF); - } - break; - case B43_PHYTYPE_N: - err = b43_nphy_selectchannel(dev, channel); - if (err) - goto out; - break; - default: - B43_WARN_ON(1); } - phy->channel = channel; - /* Wait for the radio to tune to the channel and stabilize. */ - msleep(8); -out: - if (err) { - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_CHAN, savedcookie); - } - return err; + return 0; } void b43_radio_turn_on(struct b43_wldev *dev) @@ -3843,21 +450,7 @@ void b43_radio_turn_on(struct b43_wldev *dev) break; case B43_PHYTYPE_B: case B43_PHYTYPE_G: - b43_phy_write(dev, 0x0015, 0x8000); - b43_phy_write(dev, 0x0015, 0xCC00); - b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); - if (phy->radio_off_context.valid) { - /* Restore the RFover values. */ - b43_phy_write(dev, B43_PHY_RFOVER, - phy->radio_off_context.rfover); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - phy->radio_off_context.rfoverval); - phy->radio_off_context.valid = 0; - } - channel = phy->channel; - err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); - err |= b43_radio_selectchannel(dev, channel, 0); - B43_WARN_ON(err); + //XXX break; case B43_PHYTYPE_N: b43_nphy_radio_turn_on(dev); @@ -3886,17 +479,7 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force) b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); break; case B43_PHYTYPE_G: { - u16 rfover, rfoverval; - - rfover = b43_phy_read(dev, B43_PHY_RFOVER); - rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - if (!force) { - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; - } - b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); - b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); + //XXX break; } default: diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h deleted file mode 100644 index 4aab1090352..00000000000 --- a/drivers/net/wireless/b43/phy.h +++ /dev/null @@ -1,340 +0,0 @@ -#ifndef B43_PHY_H_ -#define B43_PHY_H_ - -#include - -struct b43_wldev; -struct b43_phy; - -/*** PHY Registers ***/ - -/* Routing */ -#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ -#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ -#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ -#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ -#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ - -/* CCK (B-PHY) registers. */ -#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) -/* N-PHY registers. */ -#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) -/* N-PHY BMODE registers. */ -#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) -/* OFDM (A-PHY) registers. */ -#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) -/* Extended G-PHY registers. */ -#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) - -/* OFDM (A) PHY Registers */ -#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ -#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ -#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ -#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 -#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ -#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ -#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ -#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ -#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ -#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) -#define B43_PHY_CRS0_EN 0x4000 -#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) -#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ -#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ -#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ -#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ -#define B43_PHY_LMS B43_PHY_OFDM(0x55) -#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ -#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ -#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ -#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ -#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ -#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ -#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ -#define B43_PHY_OTABLENR_SHIFT 10 -#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ -#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ -#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ -#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ -#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) -#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ -#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ -#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ -#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ -#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ -#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ -#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) -#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) -#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) -#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) -#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) -#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ -#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ -#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ -#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) -#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) -#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) -#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ -#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ -#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ -#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ -#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ -#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ -#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ - -/* CCK (B) PHY Registers */ -#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ -#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ -#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ -#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ -#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ -#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 -#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ -#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ -#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ -#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ -#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) -#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ -#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ -#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ - -/* Extended G-PHY Registers */ -#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ -#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ -#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ -#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ -#define B43_PHY_GTABNR_SHIFT 10 -#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ -#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ -#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ -#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ -#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ -#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 -#define B43_PHY_RFOVERVAL_LNA 0x7000 -#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 -#define B43_PHY_RFOVERVAL_PGA 0x0F00 -#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 -#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ -#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 -#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ -#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ -#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ -#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ -#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ - -/*** OFDM table numbers ***/ -#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) -#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) -#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) -#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename -#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) -#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) -#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) -#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) -#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) -#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) -#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) -#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) -#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) -#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) -#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) -#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) -#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) -#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) -#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename -#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename -#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) -#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) -#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename -#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) -#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! -#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) -#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) -#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) -#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) -#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) -#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) -#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) - -u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); -void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, - u16 offset, u16 value); -u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); -void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, - u16 offset, u32 value); - -/*** G-PHY table numbers */ -#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) -#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) -#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) -#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) - -u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement -void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement - -#define B43_DEFAULT_CHANNEL_A 36 -#define B43_DEFAULT_CHANNEL_BG 6 - -enum { - B43_ANTENNA0, /* Antenna 0 */ - B43_ANTENNA1, /* Antenna 0 */ - B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ - B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ - B43_ANTENNA2, - B43_ANTENNA3 = 8, - - B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, - B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, -}; - -enum { - B43_INTERFMODE_NONE, - B43_INTERFMODE_NONWLAN, - B43_INTERFMODE_MANUALWLAN, - B43_INTERFMODE_AUTOWLAN, -}; - -/* Masks for the different PHY versioning registers. */ -#define B43_PHYVER_ANALOG 0xF000 -#define B43_PHYVER_ANALOG_SHIFT 12 -#define B43_PHYVER_TYPE 0x0F00 -#define B43_PHYVER_TYPE_SHIFT 8 -#define B43_PHYVER_VERSION 0x00FF - -void b43_phy_lock(struct b43_wldev *dev); -void b43_phy_unlock(struct b43_wldev *dev); - - -/* Read a value from a PHY register */ -u16 b43_phy_read(struct b43_wldev *dev, u16 offset); -/* Write a value to a PHY register */ -void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); -/* Mask a PHY register with a mask */ -void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); -/* OR a PHY register with a bitmap */ -void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); -/* Mask and OR a PHY register with a mask and bitmap */ -void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); - - -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); - -void b43_phy_early_init(struct b43_wldev *dev); -int b43_phy_init(struct b43_wldev *dev); - -void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); - -void b43_phy_xmitpower(struct b43_wldev *dev); - -/* Returns the boolean whether the board has HardwarePowerControl */ -bool b43_has_hardware_pctl(struct b43_phy *phy); -/* Returns the boolean whether "TX Magnification" is enabled. */ -#define has_tx_magnification(phy) \ - (((phy)->rev >= 2) && \ - ((phy)->radio_ver == 0x2050) && \ - ((phy)->radio_rev == 8)) -/* Card uses the loopback gain stuff */ -#define has_loopback_gain(phy) \ - (((phy)->rev > 1) || ((phy)->gmode)) - -/* Radio Attenuation (RF Attenuation) */ -struct b43_rfatt { - u8 att; /* Attenuation value */ - bool with_padmix; /* Flag, PAD Mixer enabled. */ -}; -struct b43_rfatt_list { - /* Attenuation values list */ - const struct b43_rfatt *list; - u8 len; - /* Minimum/Maximum attenuation values */ - u8 min_val; - u8 max_val; -}; - -/* Returns true, if the values are the same. */ -static inline bool b43_compare_rfatt(const struct b43_rfatt *a, - const struct b43_rfatt *b) -{ - return ((a->att == b->att) && - (a->with_padmix == b->with_padmix)); -} - -/* Baseband Attenuation */ -struct b43_bbatt { - u8 att; /* Attenuation value */ -}; -struct b43_bbatt_list { - /* Attenuation values list */ - const struct b43_bbatt *list; - u8 len; - /* Minimum/Maximum attenuation values */ - u8 min_val; - u8 max_val; -}; - -/* Returns true, if the values are the same. */ -static inline bool b43_compare_bbatt(const struct b43_bbatt *a, - const struct b43_bbatt *b) -{ - return (a->att == b->att); -} - -/* tx_control bits. */ -#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ -#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ -#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ - -/* Write BasebandAttenuation value to the device. */ -void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, - u16 baseband_attenuation); - -extern const u8 b43_radio_channel_codes_bg[]; - -void b43_radio_lock(struct b43_wldev *dev); -void b43_radio_unlock(struct b43_wldev *dev); - - -/* Read a value from a 16bit radio register */ -u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); -/* Write a value to a 16bit radio register */ -void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); -/* Mask a 16bit radio register with a mask */ -void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); -/* OR a 16bit radio register with a bitmap */ -void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); -/* Mask and OR a PHY register with a mask and bitmap */ -void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); - - -u16 b43_radio_init2050(struct b43_wldev *dev); -void b43_radio_init2060(struct b43_wldev *dev); - -void b43_radio_turn_on(struct b43_wldev *dev); -void b43_radio_turn_off(struct b43_wldev *dev, bool force); - -int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, - int synthetic_pu_workaround); - -u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel); -u8 b43_radio_aci_scan(struct b43_wldev *dev); - -int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode); - -void b43_calc_nrssi_slope(struct b43_wldev *dev); -void b43_calc_nrssi_threshold(struct b43_wldev *dev); -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset); -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val); -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val); -void b43_nrssi_mem_update(struct b43_wldev *dev); - -void b43_radio_set_tx_iq(struct b43_wldev *dev); -u16 b43_radio_calibrationvalue(struct b43_wldev *dev); - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt); - -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control); - -#endif /* B43_PHY_H_ */ diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c new file mode 100644 index 00000000000..dd347314b76 --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.c @@ -0,0 +1,536 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11a PHY driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005-2007 Stefano Brivio + Copyright (c) 2005-2008 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_a.h" +#include "phy_common.h" +#include "wa.h" +#include "tables.h" +#include "main.h" + + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_a(u8 channel) +{ + B43_WARN_ON(channel > 200); + + return (5000 + 5 * channel); +} + +static inline u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void b43_radio_set_tx_iq(struct b43_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43_radio_read16(dev, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + b43_phy_write(dev, 0x0069, + (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) +{ + u16 freq, r8, tmp; + + freq = channel2freq_a(channel); + + r8 = b43_radio_read16(dev, 0x0008); + b43_write16(dev, 0x03F0, freq); + b43_radio_write16(dev, 0x0008, r8); + + //TODO: write max channel TX power? to Radio 0x2D + tmp = b43_radio_read16(dev, 0x002E); + tmp &= 0x0080; + //TODO: OR tmp with the Power out estimation for this channel? + b43_radio_write16(dev, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) + & 0x000F) | (r8 << 4)); + b43_radio_write16(dev, 0x002A, (r8 << 4)); + b43_radio_write16(dev, 0x002B, (r8 << 4)); + b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) + & 0x00F0) | (r8 << 4)); + b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) + & 0xFF0F) | 0x00B0); + b43_radio_write16(dev, 0x0035, 0x00AA); + b43_radio_write16(dev, 0x0036, 0x0085); + b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) + & 0xFF20) | + freq_r3A_value(freq)); + b43_radio_write16(dev, 0x003D, + b43_radio_read16(dev, 0x003D) & 0x00FF); + b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) + & 0xFF7F) | 0x0080); + b43_radio_write16(dev, 0x0035, + b43_radio_read16(dev, 0x0035) & 0xFFEF); + b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) + & 0xFFEF) | 0x0010); + b43_radio_set_tx_iq(dev); + //TODO: TSSI2dbm workaround +//FIXME b43_phy_xmitpower(dev); +} + +void b43_radio_init2060(struct b43_wldev *dev) +{ + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_radio_write16(dev, 0x0009, 0x0040); + b43_radio_write16(dev, 0x0005, 0x00AA); + b43_radio_write16(dev, 0x0032, 0x008F); + b43_radio_write16(dev, 0x0006, 0x008F); + b43_radio_write16(dev, 0x0034, 0x008F); + b43_radio_write16(dev, 0x002C, 0x0007); + b43_radio_write16(dev, 0x0082, 0x0080); + b43_radio_write16(dev, 0x0080, 0x0000); + b43_radio_write16(dev, 0x003F, 0x00DA); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); + b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); + b43_phy_write(dev, 0x0063, 0xDDC6); + b43_phy_write(dev, 0x0069, 0x07BE); + b43_phy_write(dev, 0x006A, 0x0000); + + aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev)); + + msleep(1); +} + +static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) +{ + int i; + + if (dev->phy.rev < 3) { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0xFFF8); + } + else + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); + } + } else { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0x0820); + else + for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); + } +} + +static void b43_phy_ww(struct b43_wldev *dev) +{ + u16 b, curr_s, best_s = 0xFFFF; + int i; + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x0009, + b43_radio_read16(dev, 0x0009) | 0x0080); + b43_radio_write16(dev, 0x0012, + (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); + b43_wa_initgains(dev); + b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); + b = b43_phy_read(dev, B43_PHY_PWRDOWN); + b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) | 0x0004); + for (i = 0x10; i <= 0x20; i++) { + b43_radio_write16(dev, 0x0013, i); + curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; + if (!curr_s) { + best_s = 0x0000; + break; + } else if (curr_s >= 0x0080) + curr_s = 0x0100 - curr_s; + if (curr_s < best_s) + best_s = curr_s; + } + b43_phy_write(dev, B43_PHY_PWRDOWN, b); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) & 0xFFFB); + b43_radio_write16(dev, 0x0013, best_s); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); + b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); + b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); + b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); + b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); + b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); + b43_phy_write(dev, B43_PHY_OFDM(0xBB), + (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); + b43_phy_write(dev, B43_PHY_OFDM61, + (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); + b43_phy_write(dev, B43_PHY_OFDM(0x13), + (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); + b43_phy_write(dev, B43_PHY_OFDM(0x14), + (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); + for (i = 0; i < 6; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); + b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); +} + +static void hardware_pctl_init_aphy(struct b43_wldev *dev) +{ + //TODO +} + +void b43_phy_inita(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + /* This lowlevel A-PHY init is also called from G-PHY init. + * So we must not access phy->a, if called from G-PHY code. + */ + B43_WARN_ON((phy->type != B43_PHYTYPE_A) && + (phy->type != B43_PHYTYPE_G)); + + might_sleep(); + + if (phy->rev >= 6) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); + else + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); + } + + b43_wa_all(dev); + + if (phy->type == B43_PHYTYPE_A) { + if (phy->gmode && (phy->rev < 3)) + b43_phy_write(dev, 0x0034, + b43_phy_read(dev, 0x0034) | 0x0001); + b43_phy_rssiagc(dev, 0); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); + + b43_radio_init2060(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + ; //TODO: A PHY LO + } + + if (phy->rev >= 3) + b43_phy_ww(dev); + + hardware_pctl_init_aphy(dev); + + //TODO: radar detection + } + + if ((phy->type == B43_PHYTYPE_G) && + (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { + b43_phy_write(dev, B43_PHY_OFDM(0x6E), + (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) + & 0xE000) | 0x3CF); + } +} + +static int b43_aphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy; + + aphy = kzalloc(sizeof(*aphy), GFP_KERNEL); + if (!aphy) + return -ENOMEM; + dev->phy.a = aphy; + + //TODO init struct b43_phy_a + + return 0; +} + +static int b43_aphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy = dev->phy.a; + + b43_phy_inita(dev); + aphy->initialised = 1; + + return 0; +} + +static void b43_aphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy = dev->phy.a; + + if (aphy->initialised) { + //TODO + aphy->initialised = 0; + } + //TODO + kfree(aphy); + dev->phy.a = NULL; +} + +static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) +{ + /* OFDM registers are base-registers for the A-PHY. */ + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + offset &= ~B43_PHYROUTE; + offset |= B43_PHYROUTE_BASE; + } + +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on A-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { + /* N-BMODE registers are only available on N-PHYs */ + b43err(dev->wl, "Invalid N-BMODE PHY access at " + "0x%04X on A-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ + + return offset; +} + +static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg) +{ + reg = adjust_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + reg = adjust_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* A-PHY needs 0x40 for read access */ + reg |= 0x40; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) +{ + return (dev->phy.rev >= 5); +} + +static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{//TODO +} + +static int b43_aphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (new_channel > 200) + return -EINVAL; + aphy_channel_switch(dev, new_channel); + + return 0; +} + +static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 36; /* Default to channel 36 */ +} + +static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{//TODO + struct b43_phy *phy = &dev->phy; + u64 hf; + u16 tmp; + int autodiv = 0; + + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + if (phy->rev < 3) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + tmp = (tmp & 0xFF00) | 0x24; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } else { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= 0x10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + if (phy->analog == 3) { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x1D); + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x3A); + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +static void b43_aphy_op_xmitpower(struct b43_wldev *dev) +{//TODO +} + +static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) +{//TODO +} + +static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) +{//TODO +} + +const struct b43_phy_operations b43_phyops_a = { + .allocate = b43_aphy_op_allocate, + .init = b43_aphy_op_init, + .exit = b43_aphy_op_exit, + .phy_read = b43_aphy_op_read, + .phy_write = b43_aphy_op_write, + .radio_read = b43_aphy_op_radio_read, + .radio_write = b43_aphy_op_radio_write, + .supports_hwpctl = b43_aphy_op_supports_hwpctl, + .software_rfkill = b43_aphy_op_software_rfkill, + .switch_channel = b43_aphy_op_switch_channel, + .get_default_chan = b43_aphy_op_get_default_chan, + .set_rx_antenna = b43_aphy_op_set_rx_antenna, + .xmitpower = b43_aphy_op_xmitpower, + .pwork_15sec = b43_aphy_op_pwork_15sec, + .pwork_60sec = b43_aphy_op_pwork_60sec, +}; diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h new file mode 100644 index 00000000000..e8640f7312b --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.h @@ -0,0 +1,124 @@ +#ifndef LINUX_B43_PHY_A_H_ +#define LINUX_B43_PHY_A_H_ + +#include "phy_common.h" + + +/* OFDM (A) PHY Registers */ +#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ +#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ +#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ +#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ +#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_CRS0_EN 0x4000 +#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) +#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43_PHY_LMS B43_PHY_OFDM(0x55) +#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ +#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ +#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43_PHY_OTABLENR_SHIFT 10 +#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ +#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) +#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ +#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) +#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) +#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) +#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) +#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ +#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ +#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) +#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) +#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) +#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ +#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ +#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +/*** OFDM table numbers ***/ +#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) +#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename +#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) +#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) +#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) +#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) +#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) +#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) +#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) +#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) +#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) +#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) +#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) +#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) +#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename +#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename +#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) +#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) +#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename +#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) +#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) +#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) +#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) +#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value); +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value); + + +struct b43_phy_a { + bool initialised; + + /* A-PHY TX Power control value. */ + u16 txpwr_offset; + + //TODO lots of missing stuff +}; + +/** + * b43_phy_inita - Lowlevel A-PHY init routine. + * This is _only_ used by the G-PHY code. + */ +void b43_phy_inita(struct b43_wldev *dev); + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_a; + +#endif /* LINUX_B43_PHY_A_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c new file mode 100644 index 00000000000..45074c05d51 --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.c @@ -0,0 +1,276 @@ +/* + + Broadcom B43 wireless driver + Common PHY routines + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005-2007 Stefano Brivio + Copyright (c) 2005-2008 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "phy_common.h" +#include "phy_g.h" +#include "phy_a.h" +#include "nphy.h" +#include "b43.h" +#include "main.h" + + +int b43_phy_operations_setup(struct b43_wldev *dev) +{ + struct b43_phy *phy = &(dev->phy); + int err; + + phy->ops = NULL; + + switch (phy->type) { + case B43_PHYTYPE_A: + phy->ops = &b43_phyops_a; + break; + case B43_PHYTYPE_G: + phy->ops = &b43_phyops_g; + break; + case B43_PHYTYPE_N: +#ifdef CONFIG_B43_NPHY + phy->ops = &b43_phyops_n; +#endif + break; + case B43_PHYTYPE_LP: + /* FIXME: Not yet */ + break; + } + if (B43_WARN_ON(!phy->ops)) + return -ENODEV; + + err = phy->ops->allocate(dev); + if (err) + phy->ops = NULL; + + return err; +} + +int b43_phy_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + const struct b43_phy_operations *ops = phy->ops; + int err; + + phy->channel = ops->get_default_chan(dev); + + ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + err = ops->init(dev); + if (err) { + b43err(dev->wl, "PHY init failed\n"); + goto err_block_rf; + } + /* Make sure to switch hardware and firmware (SHM) to + * the default channel. */ + err = b43_switch_channel(dev, ops->get_default_chan(dev)); + if (err) { + b43err(dev->wl, "PHY init: Channel switch to default failed\n"); + goto err_phy_exit; + } + + return 0; + +err_phy_exit: + if (ops->exit) + ops->exit(dev); +err_block_rf: + ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + + return err; +} + +void b43_phy_exit(struct b43_wldev *dev) +{ + const struct b43_phy_operations *ops = dev->phy.ops; + + ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + if (ops->exit) + ops->exit(dev); +} + +bool b43_has_hardware_pctl(struct b43_wldev *dev) +{ + if (!dev->phy.hardware_power_control) + return 0; + if (!dev->phy.ops->supports_hwpctl) + return 0; + return dev->phy.ops->supports_hwpctl(dev); +} + +void b43_radio_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); + macctl |= B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write and wait for the device + * to exit any radio register access. */ + b43_read32(dev, B43_MMIO_MACCTL); + udelay(10); +} + +void b43_radio_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + /* Commit any write */ + b43_read16(dev, B43_MMIO_PHY_VER); + /* unlock */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); + macctl &= ~B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +void b43_phy_lock(struct b43_wldev *dev) +{ +#if B43_DEBUG + B43_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); + + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); +} + +void b43_phy_unlock(struct b43_wldev *dev) +{ +#if B43_DEBUG + B43_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); + + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); +} + +u16 b43_radio_read(struct b43_wldev *dev, u16 reg) +{ + return dev->phy.ops->radio_read(dev, reg); +} + +void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + dev->phy.ops->radio_write(dev, reg, value); +} + +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) & mask); +} + +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) | set); +} + +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_radio_write16(dev, offset, + (b43_radio_read16(dev, offset) & mask) | set); +} + +u16 b43_phy_read(struct b43_wldev *dev, u16 reg) +{ + return dev->phy.ops->phy_read(dev, reg); +} + +void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + dev->phy.ops->phy_write(dev, reg, value); +} + +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); +} + +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); +} + +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); +} + +int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) +{ + struct b43_phy *phy = &(dev->phy); + u16 channelcookie, savedcookie; + int err; + + if (new_channel == B43_DEFAULT_CHANNEL) + new_channel = phy->ops->get_default_chan(dev); + + /* First we set the channel radio code to prevent the + * firmware from sending ghost packets. + */ + channelcookie = new_channel; + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + channelcookie |= 0x100; + //FIXME set 40Mhz flag if required + savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); + + /* Now try to switch the PHY hardware channel. */ + err = phy->ops->switch_channel(dev, new_channel); + if (err) + goto err_restore_cookie; + + dev->phy.channel = new_channel; + /* Wait for the radio to tune to the channel and stabilize. */ + msleep(8); + + return 0; + +err_restore_cookie: + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_CHAN, savedcookie); + + return err; +} + +void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + + if (state == RFKILL_STATE_HARD_BLOCKED) { + /* We cannot hardware-block the device */ + state = RFKILL_STATE_SOFT_BLOCKED; + } + + phy->ops->software_rfkill(dev, state); + phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h new file mode 100644 index 00000000000..9b9635eda9c --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.h @@ -0,0 +1,312 @@ +#ifndef LINUX_B43_PHY_COMMON_H_ +#define LINUX_B43_PHY_COMMON_H_ + +#include + +struct b43_wldev; + + +/* PHY register routing bits */ +#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ +#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ +#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ +#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ +#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ + +/* CCK (B-PHY) registers. */ +#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY registers. */ +#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY BMODE registers. */ +#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) +/* OFDM (A-PHY) registers. */ +#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers. */ +#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) + + +/* Masks for the PHY versioning registers. */ +#define B43_PHYVER_ANALOG 0xF000 +#define B43_PHYVER_ANALOG_SHIFT 12 +#define B43_PHYVER_TYPE 0x0F00 +#define B43_PHYVER_TYPE_SHIFT 8 +#define B43_PHYVER_VERSION 0x00FF + +/** + * enum b43_interference_mitigation - Interference Mitigation mode + * + * @B43_INTERFMODE_NONE: Disabled + * @B43_INTERFMODE_NONWLAN: Non-WLAN Interference Mitigation + * @B43_INTERFMODE_MANUALWLAN: WLAN Interference Mitigation + * @B43_INTERFMODE_AUTOWLAN: Automatic WLAN Interference Mitigation + */ +enum b43_interference_mitigation { + B43_INTERFMODE_NONE, + B43_INTERFMODE_NONWLAN, + B43_INTERFMODE_MANUALWLAN, + B43_INTERFMODE_AUTOWLAN, +}; + +/* Antenna identifiers */ +enum { + B43_ANTENNA0, /* Antenna 0 */ + B43_ANTENNA1, /* Antenna 0 */ + B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ + B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + B43_ANTENNA2, + B43_ANTENNA3 = 8, + + B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, + B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, +}; + +/** + * struct b43_phy_operations - Function pointers for PHY ops. + * + * @prepare: Prepare the PHY. This is called before @init. + * Can be NULL, if not required. + * @init: Initialize the PHY. + * Must not be NULL. + * @exit: Shutdown the PHY and free all data structures. + * Can be NULL, if not required. + * + * @phy_read: Read from a PHY register. + * Must not be NULL. + * @phy_write: Write to a PHY register. + * Must not be NULL. + * @radio_read: Read from a Radio register. + * Must not be NULL. + * @radio_write: Write to a Radio register. + * Must not be NULL. + * + * @supports_hwpctl: Returns a boolean whether Hardware Power Control + * is supported or not. + * If NULL, hwpctl is assumed to be never supported. + * @software_rfkill: Turn the radio ON or OFF. + * Possible state values are + * RFKILL_STATE_SOFT_BLOCKED or + * RFKILL_STATE_UNBLOCKED + * Must not be NULL. + * @switch_channel: Switch the radio to another channel. + * Must not be NULL. + * @get_default_chan: Just returns the default channel number. + * Must not be NULL. + * @set_rx_antenna: Set the antenna used for RX. + * Can be NULL, if not supported. + * @interf_mitigation: Switch the Interference Mitigation mode. + * Can be NULL, if not supported. + * + * @xmitpower: FIXME REMOVEME + * Must not be NULL. + * + * @pwork_15sec: Periodic work. Called every 15 seconds. + * Can be NULL, if not required. + * @pwork_60sec: Periodic work. Called every 60 seconds. + * Can be NULL, if not required. + */ +struct b43_phy_operations { + /* Initialisation */ + int (*allocate)(struct b43_wldev *dev); + int (*prepare)(struct b43_wldev *dev); + int (*init)(struct b43_wldev *dev); + void (*exit)(struct b43_wldev *dev); + + /* Register access */ + u16 (*phy_read)(struct b43_wldev *dev, u16 reg); + void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value); + u16 (*radio_read)(struct b43_wldev *dev, u16 reg); + void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value); + + /* Radio */ + bool (*supports_hwpctl)(struct b43_wldev *dev); + void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); + unsigned int (*get_default_chan)(struct b43_wldev *dev); + void (*set_rx_antenna)(struct b43_wldev *dev, int antenna); + int (*interf_mitigation)(struct b43_wldev *dev, + enum b43_interference_mitigation new_mode); + + /* Transmission power adjustment */ + void (*xmitpower)(struct b43_wldev *dev); + + /* Misc */ + void (*pwork_15sec)(struct b43_wldev *dev); + void (*pwork_60sec)(struct b43_wldev *dev); +}; + +struct b43_phy_a; +struct b43_phy_g; +struct b43_phy_n; + +struct b43_phy { + /* Hardware operation callbacks. */ + const struct b43_phy_operations *ops; + + /* Most hardware context information is stored in the standard- + * specific data structures pointed to by the pointers below. + * Only one of them is valid (the currently enabled PHY). */ +#ifdef CONFIG_B43_DEBUG + /* No union for debug build to force NULL derefs in buggy code. */ + struct { +#else + union { +#endif + /* A-PHY specific information */ + struct b43_phy_a *a; + /* G-PHY specific information */ + struct b43_phy_g *g; + /* N-PHY specific information */ + struct b43_phy_n *n; + }; + + /* Band support flags. */ + bool supports_2ghz; + bool supports_5ghz; + + /* GMODE bit enabled? */ + bool gmode; + + /* Analog Type */ + u8 analog; + /* B43_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 radio_rev; /* Radio revision */ + + /* Software state of the radio */ + bool radio_on; + + /* Desired TX power level (in dBm). + * This is set by the user and adjusted in b43_phy_xmitpower(). */ + u8 power_level; + + /* Hardware Power Control enabled? */ + bool hardware_power_control; + + /* current channel */ + unsigned int channel; + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + +#ifdef CONFIG_B43_DEBUG + /* PHY registers locked by b43_phy_lock()? */ + bool phy_locked; +#endif /* B43_DEBUG */ +}; + + +/** + * b43_phy_operations_setup - Initialize the PHY operations datastructure + * based on the current PHY type. + */ +int b43_phy_operations_setup(struct b43_wldev *dev); + +/** + * b43_phy_init - Initialise the PHY + */ +int b43_phy_init(struct b43_wldev *dev); + +/** + * b43_phy_exit - Cleanup PHY + */ +void b43_phy_exit(struct b43_wldev *dev); + +/** + * b43_has_hardware_pctl - Hardware Power Control supported? + * Returns a boolean, whether hardware power control is supported. + */ +bool b43_has_hardware_pctl(struct b43_wldev *dev); + +/** + * b43_phy_read - 16bit PHY register read access + */ +u16 b43_phy_read(struct b43_wldev *dev, u16 reg); + +/** + * b43_phy_write - 16bit PHY register write access + */ +void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value); + +/** + * b43_phy_mask - Mask a PHY register with a mask + */ +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); + +/** + * b43_phy_set - OR a PHY register with a bitmap + */ +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); + +/** + * b43_phy_maskset - Mask and OR a PHY register with a mask and bitmap + */ +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + +/** + * b43_radio_read - 16bit Radio register read access + */ +u16 b43_radio_read(struct b43_wldev *dev, u16 reg); +#define b43_radio_read16 b43_radio_read /* DEPRECATED */ + +/** + * b43_radio_write - 16bit Radio register write access + */ +void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value); +#define b43_radio_write16 b43_radio_write /* DEPRECATED */ + +/** + * b43_radio_mask - Mask a 16bit radio register with a mask + */ +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); + +/** + * b43_radio_set - OR a 16bit radio register with a bitmap + */ +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); + +/** + * b43_radio_maskset - Mask and OR a radio register with a mask and bitmap + */ +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + +/** + * b43_radio_lock - Lock firmware radio register access + */ +void b43_radio_lock(struct b43_wldev *dev); + +/** + * b43_radio_unlock - Unlock firmware radio register access + */ +void b43_radio_unlock(struct b43_wldev *dev); + +/** + * b43_phy_lock - Lock firmware PHY register access + */ +void b43_phy_lock(struct b43_wldev *dev); + +/** + * b43_phy_unlock - Unlock firmware PHY register access + */ +void b43_phy_unlock(struct b43_wldev *dev); + +/** + * b43_switch_channel - Switch to another channel + */ +int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); +/** + * B43_DEFAULT_CHANNEL - Switch to the default channel. + */ +#define B43_DEFAULT_CHANNEL UINT_MAX + +/** + * b43_software_rfkill - Turn the radio ON or OFF in software. + */ +void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); + +#endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c new file mode 100644 index 00000000000..bb95c54cd43 --- /dev/null +++ b/drivers/net/wireless/b43/phy_g.c @@ -0,0 +1,3229 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11g PHY driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005-2007 Stefano Brivio + Copyright (c) 2005-2008 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_g.h" +#include "phy_common.h" +#include "lo.h" +#include "main.h" + +#include + + +static const s8 b43_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +const u8 b43_radio_channel_codes_bg[] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, +}; + + +static void b43_calc_nrssi_threshold(struct b43_wldev *dev); + + +#define bitrev4(tmp) (bitrev8(tmp) >> 4) + + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_bg(u8 channel) +{ + B43_WARN_ON(!(channel >= 1 && channel <= 14)); + + return b43_radio_channel_codes_bg[channel - 1]; +} + +static void generate_rfatt_list(struct b43_wldev *dev, + struct b43_rfatt_list *list) +{ + struct b43_phy *phy = &dev->phy; + + /* APHY.rev < 5 || GPHY.rev < 6 */ + static const struct b43_rfatt rfatt_0[] = { + {.att = 3,.with_padmix = 0,}, + {.att = 1,.with_padmix = 0,}, + {.att = 5,.with_padmix = 0,}, + {.att = 7,.with_padmix = 0,}, + {.att = 9,.with_padmix = 0,}, + {.att = 2,.with_padmix = 0,}, + {.att = 0,.with_padmix = 0,}, + {.att = 4,.with_padmix = 0,}, + {.att = 6,.with_padmix = 0,}, + {.att = 8,.with_padmix = 0,}, + {.att = 1,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 3,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + }; + /* Radio.rev == 8 && Radio.version == 0x2050 */ + static const struct b43_rfatt rfatt_1[] = { + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 10,.with_padmix = 1,}, + {.att = 12,.with_padmix = 1,}, + {.att = 14,.with_padmix = 1,}, + }; + /* Otherwise */ + static const struct b43_rfatt rfatt_2[] = { + {.att = 0,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + }; + + if (!b43_has_hardware_pctl(dev)) { + /* Software pctl */ + list->list = rfatt_0; + list->len = ARRAY_SIZE(rfatt_0); + list->min_val = 0; + list->max_val = 9; + return; + } + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + /* Hardware pctl */ + list->list = rfatt_1; + list->len = ARRAY_SIZE(rfatt_1); + list->min_val = 0; + list->max_val = 14; + return; + } + /* Hardware pctl */ + list->list = rfatt_2; + list->len = ARRAY_SIZE(rfatt_2); + list->min_val = 0; + list->max_val = 9; +} + +static void generate_bbatt_list(struct b43_wldev *dev, + struct b43_bbatt_list *list) +{ + static const struct b43_bbatt bbatt_0[] = { + {.att = 0,}, + {.att = 1,}, + {.att = 2,}, + {.att = 3,}, + {.att = 4,}, + {.att = 5,}, + {.att = 6,}, + {.att = 7,}, + {.att = 8,}, + }; + + list->list = bbatt_0; + list->len = ARRAY_SIZE(bbatt_0); + list->min_val = 0; + list->max_val = 8; +} + +static void b43_shm_clear_tssi(struct b43_wldev *dev) +{ + b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); +} + +/* Synthetic PU workaround */ +static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + b43_write16(dev, B43_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); + } + msleep(1); + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); +} + +/* Set the baseband attenuation value on chip. */ +void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->analog == 0) { + b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) + & 0xFFF0) | + baseband_attenuation); + } else if (phy->analog > 1) { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFFC3) | (baseband_attenuation << 2)); + } else { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFF87) | (baseband_attenuation << 3)); + } +} + +/* Adjust the transmission power output (G-PHY) */ +void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + u16 bb, rf; + u16 tx_bias, tx_magn; + + bb = bbatt->att; + rf = rfatt->att; + tx_bias = lo->tx_bias; + tx_magn = lo->tx_magn; + if (unlikely(tx_bias == 0xFF)) + tx_bias = 0; + + /* Save the values for later */ + gphy->tx_control = tx_control; + memcpy(&gphy->rfatt, rfatt, sizeof(*rfatt)); + gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); + memcpy(&gphy->bbatt, bbatt, sizeof(*bbatt)); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " + "rfatt(%u), tx_control(0x%02X), " + "tx_bias(0x%02X), tx_magn(0x%02X)\n", + bb, rf, tx_control, tx_bias, tx_magn); + } + + b43_gphy_set_baseband_attenuation(dev, bb); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, + (rf & 0x000F) | (tx_control & 0x0070)); + } else { + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | (rf & 0x000F)); + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & ~0x0070) | (tx_control & + 0x0070)); + } + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, tx_magn | tx_bias); + } else { + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & 0xFFF0) | (tx_bias & 0x000F)); + } + b43_lo_g_adjust(dev); +} + +/* GPHY_TSSI_Power_Lookup_Table_Init */ +static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + int i; + u16 value; + + for (i = 0; i < 32; i++) + b43_ofdmtab_write16(dev, 0x3C20, i, gphy->tssi2dbm[i]); + for (i = 32; i < 64; i++) + b43_ofdmtab_write16(dev, 0x3C00, i - 32, gphy->tssi2dbm[i]); + for (i = 0; i < 64; i += 2) { + value = (u16) gphy->tssi2dbm[i]; + value |= ((u16) gphy->tssi2dbm[i + 1]) << 8; + b43_phy_write(dev, 0x380 + (i / 2), value); + } +} + +/* GPHY_Gain_Lookup_Table_Init */ +static void b43_gphy_gain_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + u16 nr_written = 0; + u16 tmp; + u8 rf, bb; + + for (rf = 0; rf < lo->rfatt_list.len; rf++) { + for (bb = 0; bb < lo->bbatt_list.len; bb++) { + if (nr_written >= 0x40) + return; + tmp = lo->bbatt_list.list[bb].att; + tmp <<= 8; + if (phy->radio_rev == 8) + tmp |= 0x50; + else + tmp |= 0x40; + tmp |= lo->rfatt_list.list[rf].att; + b43_phy_write(dev, 0x3C0 + nr_written, tmp); + nr_written++; + } + } +} + +static void b43_set_all_gains(struct b43_wldev *dev, + s16 first, s16 second, s16 third) +{ + struct b43_phy *phy = &dev->phy; + u16 i; + u16 start = 0x08, end = 0x18; + u16 tmp; + u16 table; + + if (phy->rev <= 1) { + start = 0x10; + end = 0x20; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) + b43_ofdmtab_write16(dev, table, i, first); + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, second); + + if (third != -1) { + tmp = ((u16) third << 14) | ((u16) third << 6); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); + } + b43_dummy_transmission(dev); +} + +static void b43_set_original_gains(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 i, tmp; + u16 table; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + start = 0x0010; + end = 0x0020; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + b43_ofdmtab_write16(dev, table, i, tmp); + } + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, i - start); + + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); + b43_dummy_transmission(dev); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +{ + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + mmiowb(); + b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) +{ + u16 val; + + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA); + + return (s16) val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = b43_nrssi_hw_read(dev, i); + tmp -= val; + tmp = clamp_val(tmp, -32, 31); + b43_nrssi_hw_write(dev, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_mem_update(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + s16 i, delta; + s32 tmp; + + delta = 0x1F - gphy->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * gphy->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = clamp_val(tmp, 0, 0x3F); + gphy->nrssi_lt[i] = tmp; + } +} + +static void b43_calc_nrssi_offset(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = b43_phy_read(dev, 0x0001); + backup[1] = b43_phy_read(dev, 0x0811); + backup[2] = b43_phy_read(dev, 0x0812); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup[3] = b43_phy_read(dev, 0x0814); + backup[4] = b43_phy_read(dev, 0x0815); + } + backup[5] = b43_phy_read(dev, 0x005A); + backup[6] = b43_phy_read(dev, 0x0059); + backup[7] = b43_phy_read(dev, 0x0058); + backup[8] = b43_phy_read(dev, 0x000A); + backup[9] = b43_phy_read(dev, 0x0003); + backup[10] = b43_radio_read16(dev, 0x007A); + backup[11] = b43_radio_read16(dev, 0x0043); + + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); + b43_phy_write(dev, 0x0001, + (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = b43_phy_read(dev, 0x002E); + backup[13] = b43_phy_read(dev, 0x002F); + backup[14] = b43_phy_read(dev, 0x080F); + backup[15] = b43_phy_read(dev, 0x0810); + backup[16] = b43_phy_read(dev, 0x0801); + backup[17] = b43_phy_read(dev, 0x0060); + backup[18] = b43_phy_read(dev, 0x0014); + backup[19] = b43_phy_read(dev, 0x0478); + + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, 0x002F, 0); + b43_phy_write(dev, 0x080F, 0); + b43_phy_write(dev, 0x0810, 0); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); + } + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0001); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFE); + } + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + if (phy->rev == 0) { + b43_phy_write(dev, 0x0003, 0x0122); + } else { + b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) + | 0x2000); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0004); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFB); + } + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) + | 0x0040); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_set_all_gains(dev, 3, 0, 1); + b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & + 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + b43_radio_write16(dev, 0x007B, saved); + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x002E, backup[12]); + b43_phy_write(dev, 0x002F, backup[13]); + b43_phy_write(dev, 0x080F, backup[14]); + b43_phy_write(dev, 0x0810, backup[15]); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, backup[3]); + b43_phy_write(dev, 0x0815, backup[4]); + } + b43_phy_write(dev, 0x005A, backup[5]); + b43_phy_write(dev, 0x0059, backup[6]); + b43_phy_write(dev, 0x0058, backup[7]); + b43_phy_write(dev, 0x000A, backup[8]); + b43_phy_write(dev, 0x0003, backup[9]); + b43_radio_write16(dev, 0x0043, backup[11]); + b43_radio_write16(dev, 0x007A, backup[10]); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); + b43_set_original_gains(dev); + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0801, backup[16]); + b43_phy_write(dev, 0x0060, backup[17]); + b43_phy_write(dev, 0x0014, backup[18]); + b43_phy_write(dev, 0x0478, backup[19]); + } + b43_phy_write(dev, 0x0001, backup[0]); + b43_phy_write(dev, 0x0812, backup[2]); + b43_phy_write(dev, 0x0811, backup[1]); +} + +void b43_calc_nrssi_slope(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43_calc_nrssi_offset(dev); + + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43_read16(dev, 0x03E2); + b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0015); + backup[4] = b43_phy_read(dev, 0x005A); + backup[5] = b43_phy_read(dev, 0x0059); + backup[6] = b43_phy_read(dev, 0x0058); + backup[8] = b43_read16(dev, 0x03E6); + backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43_phy_read(dev, 0x002E); + backup[11] = b43_phy_read(dev, 0x002F); + backup[12] = b43_phy_read(dev, 0x080F); + backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); + backup[14] = b43_phy_read(dev, 0x0801); + backup[15] = b43_phy_read(dev, 0x0060); + backup[16] = b43_phy_read(dev, 0x0014); + backup[17] = b43_phy_read(dev, 0x0478); + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: + case 6: + case 7: + b43_phy_write(dev, 0x0478, + b43_phy_read(dev, 0x0478) + | 0x0100); + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + | 0x0040); + break; + case 3: + case 5: + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + & 0xFFBF); + break; + } + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) + | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) + | 0x0200); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0070); + b43_set_all_gains(dev, 0, 8, 0); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0030); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0010); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + } + + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | 0x2000); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0020); + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0020); + } + + b43_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x0043, 0x001F); + } else { + tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; + b43_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; + b43_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + gphy->nrssislope = 0x00010000; + else + gphy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + gphy->nrssi[0] = nrssi1; + gphy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43_phy_write(dev, 0x002E, backup[10]); + b43_phy_write(dev, 0x002F, backup[11]); + b43_phy_write(dev, 0x080F, backup[12]); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + b43_phy_read(dev, 0x0812) & 0xFFCF); + b43_phy_write(dev, 0x0811, + b43_phy_read(dev, 0x0811) & 0xFFCF); + } + + b43_radio_write16(dev, 0x007A, backup[0]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + b43_write16(dev, 0x03E2, backup[7]); + b43_write16(dev, 0x03E6, backup[8]); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); + b43_phy_write(dev, 0x0015, backup[3]); + b43_phy_write(dev, 0x005A, backup[4]); + b43_phy_write(dev, 0x0059, backup[5]); + b43_phy_write(dev, 0x0058, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + b43_phy_write(dev, 0x0802, + b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); + b43_set_original_gains(dev); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + if (phy->rev >= 3) { + b43_phy_write(dev, 0x0801, backup[14]); + b43_phy_write(dev, 0x0060, backup[15]); + b43_phy_write(dev, 0x0014, backup[16]); + b43_phy_write(dev, 0x0478, backup[17]); + } + b43_nrssi_mem_update(dev); + b43_calc_nrssi_threshold(dev); +} + +static void b43_calc_nrssi_threshold(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + s32 a, b; + s16 tmp16; + u16 tmp_u16; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if (!phy->gmode || + !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + tmp16 = b43_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x09EB); + } else { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + if (gphy->interfmode == B43_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!gphy->aci_wlan_automatic && gphy->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (gphy->nrssi[1] - gphy->nrssi[0]); + a += (gphy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = clamp_val(a, -31, 31); + + b = b * (gphy->nrssi[1] - gphy->nrssi[0]); + b += (gphy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = clamp_val(b, -31, 31); + + tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32) b & 0x0000003F); + tmp_u16 |= (((u32) a & 0x0000003F) << 6); + b43_phy_write(dev, 0x048A, tmp_u16); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 * _stackptr, size_t * stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + *stackptr = offset; + *stackptr |= ((u32) id) << 12; + *stackptr |= ((u32) value) << 16; + (*stackidx)++; + B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) +{ + size_t i; + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + B43_WARN_ON(1); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + b43_phy_read(dev, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + b43_phy_write(dev, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + b43_radio_read16(dev, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + b43_radio_write16(dev, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ofdmtab_stacksave(table, offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset)|(table), \ + b43_ofdmtab_read16(dev, (table), (offset))); \ + } while (0) +#define ofdmtab_stackrestore(table, offset) \ + do { \ + b43_ofdmtab_write16(dev, (table), (offset), \ + _stack_restore(stack, 0x3, \ + (offset)|(table))); \ + } while (0) + +static void +b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 tmp, flipped; + size_t stackidx = 0; + u32 *stack = gphy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); + B43_WARN_ON(tmp > 15); + flipped = bitrev4(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = (bitrev4(flipped) << 1) | 0x0020; + b43_radio_write16(dev, 0x0078, flipped); + + b43_calc_nrssi_threshold(dev); + + phy_stacksave(0x0406); + b43_phy_write(dev, 0x0406, 0x7E28); + + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); + phy_stacksave(0x04A1); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); + phy_stacksave(0x04A2); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); + phy_stacksave(0x04A8); + b43_phy_write(dev, 0x04A8, + (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); + b43_phy_write(dev, 0x04AB, + (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); + + phy_stacksave(0x04A7); + b43_phy_write(dev, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + b43_phy_write(dev, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + b43_phy_write(dev, 0x04A9, 0x2027); + phy_stacksave(0x0493); + b43_phy_write(dev, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + b43_phy_write(dev, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + b43_phy_write(dev, 0x04AC, 0x32F5); + break; + case B43_INTERFMODE_MANUALWLAN: + if (b43_phy_read(dev, 0x0033) & 0x0800) + break; + + gphy->aci_enable = 1; + + phy_stacksave(B43_PHY_RADIO_BITFIELD); + phy_stacksave(B43_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); + } else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ofdmtab_stacksave(0x1A00, 0x2); + ofdmtab_stacksave(0x1A00, 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~0x1000); + b43_phy_write(dev, B43_PHY_G_CRS, + (b43_phy_read(dev, B43_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + b43_phy_write(dev, 0x0033, 0x0800); + b43_phy_write(dev, 0x04A3, 0x2027); + b43_phy_write(dev, 0x04A9, 0x1CA8); + b43_phy_write(dev, 0x0493, 0x287A); + b43_phy_write(dev, 0x04AA, 0x1CA8); + b43_phy_write(dev, 0x04AC, 0x287A); + + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xFFC0) | 0x001A); + b43_phy_write(dev, 0x04A7, 0x000D); + + if (phy->rev < 2) { + b43_phy_write(dev, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + b43_phy_write(dev, 0x04C0, 0xFFFF); + b43_phy_write(dev, 0x04C1, 0x00A9); + } else { + b43_phy_write(dev, 0x04C0, 0x00C1); + b43_phy_write(dev, 0x04C1, 0x0059); + } + + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xC0FF) | 0x1800); + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xFFC0) | 0x0015); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xF0FF) | 0x0A00); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFF0) | 0x0005); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFF0) | 0x0006); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0500); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + & ~0x8000); + b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) + & 0xFE00) | 0x016D); + } else { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + | 0x1000); + b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) + & 0x9FFF) | 0x2000); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) + | 0x0800); + } + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) + & 0xFF00) | 0x007F); + b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); + b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); + b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) + & 0x00FF); + } + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +static void +b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u32 *stack = gphy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) & ~0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) | 0x4000); + break; + } + radio_stackrestore(0x0078); + b43_calc_nrssi_threshold(dev); + phy_stackrestore(0x0406); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); + if (!dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case B43_INTERFMODE_MANUALWLAN: + if (!(b43_phy_read(dev, 0x0033) & 0x0800)) + break; + + gphy->aci_enable = 0; + + phy_stackrestore(B43_PHY_RADIO_BITFIELD); + phy_stackrestore(B43_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ofdmtab_stackrestore(0x1A00, 0x2); + ofdmtab_stackrestore(0x1A00, 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x048A); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW); + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ofdmtab_stacksave +#undef ofdmtab_stackrestore + +static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) +{ + u16 reg, index, ret; + + static const u8 rcc_table[] = { + 0x02, 0x03, 0x01, 0x0F, + 0x06, 0x07, 0x05, 0x0F, + 0x0A, 0x0B, 0x09, 0x0F, + 0x0E, 0x0F, 0x0D, 0x0F, + }; + + reg = b43_radio_read16(dev, 0x60); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) +static u16 radio2050_rfover_val(struct b43_wldev *dev, + u16 phy_register, unsigned int lpd) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + + if (!phy->gmode) + return 0; + + if (has_loopback_gain(phy)) { + int max_lb_gain = gphy->max_lb_gain; + u16 extlna; + u16 i; + + if (phy->radio_rev == 8) + max_lb_gain += 0x3E; + else + max_lb_gain += 0x26; + if (max_lb_gain >= 0x46) { + extlna = 0x3000; + max_lb_gain -= 0x46; + } else if (max_lb_gain >= 0x3A) { + extlna = 0x1000; + max_lb_gain -= 0x3A; + } else if (max_lb_gain >= 0x2E) { + extlna = 0x2000; + max_lb_gain -= 0x2E; + } else { + extlna = 0; + max_lb_gain -= 0x10; + } + + for (i = 0; i < 16; i++) { + max_lb_gain -= (i * 6); + if (max_lb_gain < 6) + break; + } + + if ((phy->rev < 7) || + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x0F92; + case LPD(0, 0, 1): + case LPD(1, 0, 1): + return (0x0092 | extlna); + case LPD(1, 0, 0): + return (0x0093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + if (extlna) + extlna |= 0x8000; + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x8F92; + case LPD(0, 0, 1): + return (0x8092 | extlna); + case LPD(1, 0, 1): + return (0x2092 | extlna); + case LPD(1, 0, 0): + return (0x2093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } else { + if ((phy->rev < 7) || + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0FB2; + case LPD(0, 0, 1): + return 0x00B2; + case LPD(1, 0, 1): + return 0x30B2; + case LPD(1, 0, 0): + return 0x30B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x8FB2; + case LPD(0, 0, 1): + return 0x80B2; + case LPD(1, 0, 1): + return 0x20B2; + case LPD(1, 0, 0): + return 0x20B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } + return 0; +} + +struct init2050_saved_values { + /* Core registers */ + u16 reg_3EC; + u16 reg_3E6; + u16 reg_3F4; + /* Radio registers */ + u16 radio_43; + u16 radio_51; + u16 radio_52; + /* PHY registers */ + u16 phy_pgactl; + u16 phy_cck_5A; + u16 phy_cck_59; + u16 phy_cck_58; + u16 phy_cck_30; + u16 phy_rfover; + u16 phy_rfoverval; + u16 phy_analogover; + u16 phy_analogoverval; + u16 phy_crs0; + u16 phy_classctl; + u16 phy_lo_mask; + u16 phy_lo_ctl; + u16 phy_syncctl; +}; + +u16 b43_radio_init2050(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct init2050_saved_values sav; + u16 rcc; + u16 radio78; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */ + + sav.radio_43 = b43_radio_read16(dev, 0x43); + sav.radio_51 = b43_radio_read16(dev, 0x51); + sav.radio_52 = b43_radio_read16(dev, 0x52); + sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); + sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59)); + sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58)); + + if (phy->type == B43_PHYTYPE_B) { + sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); + sav.reg_3EC = b43_read16(dev, 0x3EC); + + b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF); + b43_write16(dev, 0x3EC, 0x3F3F); + } else if (phy->gmode || phy->rev >= 2) { + sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); + sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); + sav.phy_analogoverval = + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); + sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) + | 0x0003); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) + & 0xFFFC); + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_CLASSCTL, + b43_phy_read(dev, B43_PHY_CLASSCTL) + & 0xFFFC); + if (has_loopback_gain(phy)) { + sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); + sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + } + + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + b43_phy_write(dev, B43_PHY_RFOVER, + radio2050_rfover_val(dev, B43_PHY_RFOVER, 0)); + } + b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); + + sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); + b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) + & 0xFF7F); + sav.reg_3E6 = b43_read16(dev, 0x3E6); + sav.reg_3F4 = b43_read16(dev, 0x3F4); + + if (phy->analog == 0) { + b43_write16(dev, 0x03E6, 0x0122); + } else { + if (phy->analog >= 2) { + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) + & 0xFFBF) | 0x40); + } + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); + } + + rcc = b43_radio_core_calibration_value(dev); + + if (phy->type == B43_PHYTYPE_B) + b43_radio_write16(dev, 0x78, 0x26); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); + b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) + | 0x0004); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x1F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x0009); + } + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(20); + tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + udelay(10); + + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + tmp1++; + tmp1 >>= 9; + + for (i = 0; i < 16; i++) { + radio78 = (bitrev4(i) << 1) | 0x0020; + b43_radio_write16(dev, 0x78, radio78); + udelay(10); + for (j = 0; j < 16; j++) { + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(10); + tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl); + b43_radio_write16(dev, 0x51, sav.radio_51); + b43_radio_write16(dev, 0x52, sav.radio_52); + b43_radio_write16(dev, 0x43, sav.radio_43); + b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A); + b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59); + b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58); + b43_write16(dev, 0x3E6, sav.reg_3E6); + if (phy->analog != 0) + b43_write16(dev, 0x3F4, sav.reg_3F4); + b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); + b43_synth_pu_workaround(dev, phy->channel); + if (phy->type == B43_PHYTYPE_B) { + b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30); + b43_write16(dev, 0x3EC, sav.reg_3EC); + } else if (phy->gmode) { + b43_write16(dev, B43_MMIO_PHY_RADIO, + b43_read16(dev, B43_MMIO_PHY_RADIO) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval); + b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + sav.phy_analogoverval); + b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0); + b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl); + if (has_loopback_gain(phy)) { + b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask); + b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl); + } + } + if (i > 15) + ret = radio78; + else + ret = rcc; + + return ret; +} + +static void b43_phy_initb5(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 offset, value; + u8 old_channel; + + if (phy->analog == 1) { + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0050); + } + if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type != SSB_BOARD_BU4306)) { + value = 0x2120; + for (offset = 0x00A8; offset < 0x00C7; offset++) { + b43_phy_write(dev, offset, value); + value += 0x202; + } + } + b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0038, 0x0667); + + if (phy->gmode || phy->rev >= 2) { + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) + | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) + | 0x0004); + } + b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); + + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + + b43_phy_write(dev, 0x001C, 0x186A); + + b43_phy_write(dev, 0x0013, + (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); + b43_phy_write(dev, 0x0035, + (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); + b43_phy_write(dev, 0x005D, + (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->analog == 1) { + b43_phy_write(dev, 0x0026, 0xCE00); + b43_phy_write(dev, 0x0021, 0x3763); + b43_phy_write(dev, 0x0022, 0x1BC3); + b43_phy_write(dev, 0x0023, 0x06F9); + b43_phy_write(dev, 0x0024, 0x037E); + } else + b43_phy_write(dev, 0x0026, 0xCC00); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43_phy_write(dev, 0x0020, 0x3E1C); + else + b43_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43_write16(dev, 0x03E4, 0x3000); + + old_channel = phy->channel; + /* Force to channel 7, even if not supported. */ + b43_gphy_channel_switch(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + } + + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); + + b43_gphy_channel_switch(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x002A, 0x88A3); + + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); + + if (phy->radio_ver == 0x2050) + b43_radio_write16(dev, 0x005D, 0x000D); + + b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void b43_phy_initb6(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 offset, val; + u8 old_channel; + + b43_phy_write(dev, 0x003E, 0x817A); + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || phy->radio_rev == 5) { + b43_radio_write16(dev, 0x51, 0x37); + b43_radio_write16(dev, 0x52, 0x70); + b43_radio_write16(dev, 0x53, 0xB3); + b43_radio_write16(dev, 0x54, 0x9B); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x88); + b43_radio_write16(dev, 0x5D, 0x88); + b43_radio_write16(dev, 0x5E, 0x88); + b43_radio_write16(dev, 0x7D, 0x88); + b43_hf_write(dev, b43_hf_read(dev) + | B43_HF_TSSIRPSMW); + } + B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x51, 0); + b43_radio_write16(dev, 0x52, 0x40); + b43_radio_write16(dev, 0x53, 0xB7); + b43_radio_write16(dev, 0x54, 0x98); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x6B); + b43_radio_write16(dev, 0x5C, 0x0F); + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { + b43_radio_write16(dev, 0x5D, 0xFA); + b43_radio_write16(dev, 0x5E, 0xD8); + } else { + b43_radio_write16(dev, 0x5D, 0xF5); + b43_radio_write16(dev, 0x5E, 0xB8); + } + b43_radio_write16(dev, 0x0073, 0x0003); + b43_radio_write16(dev, 0x007D, 0x00A8); + b43_radio_write16(dev, 0x007C, 0x0001); + b43_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43_PHYTYPE_G) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + b43_phy_write(dev, 0x5B, 0); + b43_phy_write(dev, 0x5C, 0); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43_gphy_channel_switch(dev, 1, 0); + else + b43_gphy_channel_switch(dev, 13, 0); + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) + | 0x0002)); + b43_radio_write16(dev, 0x50, 0x20); + } + if (phy->radio_rev <= 2) { + b43_radio_write16(dev, 0x7C, 0x20); + b43_radio_write16(dev, 0x5A, 0x70); + b43_radio_write16(dev, 0x5B, 0x7B); + b43_radio_write16(dev, 0x5C, 0xB0); + } + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); + + b43_gphy_channel_switch(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43_phy_write(dev, 0x2A, 0x88C2); + else + b43_phy_write(dev, 0x2A, 0x8AC0); + b43_phy_write(dev, 0x0038, 0x0668); + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); + if (phy->radio_rev <= 5) { + b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) + & 0xFF80) | 0x0003); + } + if (phy->radio_rev <= 2) + b43_radio_write16(dev, 0x005D, 0x000D); + + if (phy->analog == 4) { + b43_write16(dev, 0x3E4, 9); + b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) + & 0x0FFF); + } else { + b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) + | 0x0004); + } + if (phy->type == B43_PHYTYPE_B) + B43_WARN_ON(1); + else if (phy->type == B43_PHYTYPE_G) + b43_write16(dev, 0x03E6, 0x0); +} + +static void b43_calc_loopback_gain(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 backup_phy[16] = { 0 }; + u16 backup_radio[3]; + u16 backup_bband; + u16 i, j, loop_i_max; + u16 trsw_rx; + u16 loop1_outer_done, loop1_inner_done; + + backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); + backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); + backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); + backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + } + backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); + backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); + backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); + backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); + backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); + backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + backup_bband = gphy->bbatt.att; + backup_radio[0] = b43_radio_read16(dev, 0x52); + backup_radio[1] = b43_radio_read16(dev, 0x43); + backup_radio[2] = b43_radio_read16(dev, 0x7A); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, + b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFE); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFD); + } + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xFFCF) | 0x10); + + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + + b43_phy_write(dev, B43_PHY_CCK(0x0A), + b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFB); + } + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) + & 0xFF9F) | 0x40); + + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x000F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x9); + } + b43_gphy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) + & 0xFFC0) | 0x01); + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) + & 0xC0FF) | 0x800); + + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); + + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) + | 0x0800); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x8000); + } + } + b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) + & 0x00F7); + + j = 0; + loop_i_max = (phy->radio_rev == 8) ? 15 : 9; + for (i = 0; i < loop_i_max; i++) { + for (j = 0; j < 16; j++) { + b43_radio_write16(dev, 0x43, i); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop1; + } + } + exit_loop1: + loop1_outer_done = i; + loop1_inner_done = j; + if (j >= 8) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x30); + trsw_rx = 0x1B; + for (j = j - 8; j < 16; j++) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + trsw_rx -= 3; + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop2; + } + } else + trsw_rx = 0x18; + exit_loop2: + + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); + } + b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); + b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); + b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); + + b43_gphy_set_baseband_attenuation(dev, backup_bband); + + b43_radio_write16(dev, 0x52, backup_radio[0]); + b43_radio_write16(dev, 0x43, backup_radio[1]); + b43_radio_write16(dev, 0x7A, backup_radio[2]); + + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); + udelay(10); + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); + b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); + b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); + + gphy->max_lb_gain = + ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; + gphy->trsw_rx_gain = trsw_rx * 2; +} + +static void b43_hardware_pctl_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(dev)) { + b43_phy_write(dev, 0x047A, 0xC111); + return; + } + + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); + b43_phy_write(dev, 0x002F, 0x0202); + b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); + b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + | 0x8000); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + } else { + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0200); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + & 0x7FFF); + b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) + & 0xFFFE); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + } +} + +/* Hardware power control for G-PHY */ +static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + if (!b43_has_hardware_pctl(dev)) { + /* No hardware power control */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); + return; + } + + b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) + | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); + b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) + | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); + b43_gphy_tssi_power_lt_init(dev); + b43_gphy_gain_lt_init(dev); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); + b43_phy_write(dev, 0x0014, 0x0000); + + B43_WARN_ON(phy->rev < 6); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + | 0x0800); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + & 0xFEFF); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) + & 0xFFBF); + + b43_gphy_dc_lt_init(dev, 1); + + /* Enable hardware pctl in firmware. */ + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); +} + +/* Intialize B/G PHY power control */ +static void b43_phy_init_pctl(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_rfatt old_rfatt; + struct b43_bbatt old_bbatt; + u8 old_tx_control = 0; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + b43_phy_write(dev, 0x0028, 0x8018); + + /* This does something with the Analog... */ + b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) + & 0xFFDF); + + if (!phy->gmode) + return; + b43_hardware_pctl_early_init(dev); + if (gphy->cur_idle_tssi == 0) { + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + (b43_radio_read16(dev, 0x0076) + & 0x00F7) | 0x0084); + } else { + struct b43_rfatt rfatt; + struct b43_bbatt bbatt; + + memcpy(&old_rfatt, &gphy->rfatt, sizeof(old_rfatt)); + memcpy(&old_bbatt, &gphy->bbatt, sizeof(old_bbatt)); + old_tx_control = gphy->tx_control; + + bbatt.att = 11; + if (phy->radio_rev == 8) { + rfatt.att = 15; + rfatt.with_padmix = 1; + } else { + rfatt.att = 9; + rfatt.with_padmix = 0; + } + b43_set_txpower_g(dev, &bbatt, &rfatt, 0); + } + b43_dummy_transmission(dev); + gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); + if (B43_DEBUG) { + /* Current-Idle-TSSI sanity check. */ + if (abs(gphy->cur_idle_tssi - gphy->tgt_idle_tssi) >= 20) { + b43dbg(dev->wl, + "!WARNING! Idle-TSSI phy->cur_idle_tssi " + "measuring failed. (cur=%d, tgt=%d). Disabling TX power " + "adjustment.\n", gphy->cur_idle_tssi, + gphy->tgt_idle_tssi); + gphy->cur_idle_tssi = 0; + } + } + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + b43_radio_read16(dev, 0x0076) + & 0xFF7B); + } else { + b43_set_txpower_g(dev, &old_bbatt, + &old_rfatt, old_tx_control); + } + } + b43_hardware_pctl_init_gphy(dev); + b43_shm_clear_tssi(dev); +} + +static void b43_phy_initg(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 tmp; + + if (phy->rev == 1) + b43_phy_initb5(dev); + else + b43_phy_initb6(dev); + + if (phy->rev >= 2 || phy->gmode) + b43_phy_inita(dev); + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); + } + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->rev > 5) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x400); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->gmode || phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); + tmp &= B43_PHYVER_VERSION; + if (tmp == 3 || tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); + } + if (tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xCC), + (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) + & 0x00FF) | 0x1F00); + } + } + if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) + b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); + if (phy->radio_rev == 8) { + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x80); + b43_phy_write(dev, B43_PHY_OFDM(0x3E), + b43_phy_read(dev, B43_PHY_OFDM(0x3E)) + | 0x4); + } + if (has_loopback_gain(phy)) + b43_calc_loopback_gain(dev); + + if (phy->radio_rev != 8) { + if (gphy->initval == 0xFFFF) + gphy->initval = b43_radio_init2050(dev); + else + b43_radio_write16(dev, 0x0078, gphy->initval); + } + b43_lo_g_init(dev); + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | gphy->lo_control->tx_bias | gphy-> + lo_control->tx_magn); + } else { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | gphy->lo_control->tx_bias); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) + & 0x0FFF) | (gphy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); + if (phy->gmode || phy->rev >= 2) { + b43_lo_g_adjust(dev); + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); + } + + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the clamp_val() in nrssi_hw_update()) + */ + b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? + b43_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (gphy->nrssi[0] == -1000) { + B43_WARN_ON(gphy->nrssi[1] != -1000); + b43_calc_nrssi_slope(dev); + } else + b43_calc_nrssi_threshold(dev); + } + if (phy->radio_rev == 8) + b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); + b43_phy_init_pctl(dev); + /* FIXME: The spec says in the following if, the 0 should be replaced + 'if OFDM may not be used in the current locale' + but OFDM is legal everywhere */ + if ((dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) || 0) { + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0xBFFF); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), + b43_phy_read(dev, B43_PHY_OFDM(0xC3)) + & 0x7FFF); + } +} + +void b43_gphy_channel_switch(struct b43_wldev *dev, + unsigned int channel, + bool synthetic_pu_workaround) +{ + if (synthetic_pu_workaround) + b43_synth_pu_workaround(dev, channel); + + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.country_code == + SSB_SPROM1CCODE_JAPAN) + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_ACPR); + else + b43_hf_write(dev, + b43_hf_read(dev) | B43_HF_ACPR); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + & 0xF7BF); + } +} + +static void default_baseband_attenuation(struct b43_wldev *dev, + struct b43_bbatt *bb) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + bb->att = 0; + else + bb->att = 2; +} + +static void default_radio_attenuation(struct b43_wldev *dev, + struct b43_rfatt *rf) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + rf->with_padmix = 0; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G) { + if (bus->boardinfo.rev < 0x43) { + rf->att = 2; + return; + } else if (bus->boardinfo.rev < 0x51) { + rf->att = 3; + return; + } + } + + if (phy->type == B43_PHYTYPE_A) { + rf->att = 0x60; + return; + } + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + rf->att = 6; + return; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + rf->att = 5; + return; + case 1: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 3; + else + rf->att = 1; + } else { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 7; + else + rf->att = 6; + } + return; + case 2: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 5; + else if (bus->chip_id == 0x4320) + rf->att = 4; + else + rf->att = 3; + } else + rf->att = 6; + return; + case 3: + rf->att = 5; + return; + case 4: + case 5: + rf->att = 1; + return; + case 6: + case 7: + rf->att = 5; + return; + case 8: + rf->att = 0xA; + rf->with_padmix = 1; + return; + case 9: + default: + rf->att = 5; + return; + } + } + rf->att = 5; +} + +static u16 default_tx_control(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; + if (phy->radio_rev < 6) + return B43_TXCTL_PA2DB; + if (phy->radio_rev == 8) + return B43_TXCTL_TXMIX; + return 0; +} + +static u8 b43_gphy_aci_detect(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = b43_phy_read(dev, 0x0403); + b43_switch_channel(dev, channel); + b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (gphy->aci_hw_rssi) + rssi = b43_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43_phy_write(dev, 0x0403, saved); + + return ret; +} + +static u8 b43_gphy_aci_scan(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i, j, start, end; + + if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i - 1] = b43_gphy_aci_detect(dev, i); + } + b43_switch_channel(dev, channel); + b43_phy_write(dev, 0x0802, + (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); + b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + b43_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43_radio_unlock(dev); + b43_phy_unlock(dev); + + return ret[channel - 1]; +} + +static s32 b43_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num / den; + else + return (num + den / 2) / den; +} + +static s8 b43_tssi2dbm_entry(s8 entry[], u8 index, + s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, + s16 pab0, s16 pab1, s16 pab2) +{ + unsigned int i; + u8 *tab; + int err; + + tab = kmalloc(64, GFP_KERNEL); + if (!tab) { + b43err(dev->wl, "Could not allocate memory " + "for tssi2dbm table\n"); + return NULL; + } + for (i = 0; i < 64; i++) { + err = b43_tssi2dbm_entry(tab, i, pab0, pab1, pab2); + if (err) { + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(tab); + return NULL; + } + } + + return tab; +} + +/* Initialise the TSSI->dBm lookup table */ +static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + s16 pab0, pab1, pab2; + + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); + + B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) && + (phy->radio_ver != 0x2050)); /* Not supported anymore */ + + gphy->dyn_tssi_tbl = 0; + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) { + gphy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_bg); + } else + gphy->tgt_idle_tssi = 62; + gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, + pab1, pab2); + if (!gphy->tssi2dbm) + return -ENOMEM; + gphy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + gphy->tgt_idle_tssi = 52; + gphy->tssi2dbm = b43_tssi2dbm_g_table; + } + + return 0; +} + +static int b43_gphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy; + struct b43_txpower_lo_control *lo; + int err, i; + + gphy = kzalloc(sizeof(*gphy), GFP_KERNEL); + if (!gphy) { + err = -ENOMEM; + goto error; + } + dev->phy.g = gphy; + + memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig)); + + /* NRSSI */ + for (i = 0; i < ARRAY_SIZE(gphy->nrssi); i++) + gphy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(gphy->nrssi_lt); i++) + gphy->nrssi_lt[i] = i; + + gphy->lofcal = 0xFFFF; + gphy->initval = 0xFFFF; + + gphy->interfmode = B43_INTERFMODE_NONE; + + /* OFDM-table address caching. */ + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; + + + lo = kzalloc(sizeof(*lo), GFP_KERNEL); + if (!lo) { + err = -ENOMEM; + goto err_free_gphy; + } + gphy->lo_control = lo; + + lo->tx_bias = 0xFF; + INIT_LIST_HEAD(&lo->calib_list); + + err = b43_gphy_init_tssi2dbm_table(dev); + if (err) + goto err_free_lo; + + return 0; + +err_free_lo: + kfree(lo); +err_free_gphy: + kfree(gphy); +error: + return err; +} + +static int b43_gphy_op_prepare(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + default_baseband_attenuation(dev, &gphy->bbatt); + default_radio_attenuation(dev, &gphy->rfatt); + gphy->tx_control = (default_tx_control(dev) << 4); + generate_rfatt_list(dev, &lo->rfatt_list); + generate_bbatt_list(dev, &lo->bbatt_list); + + /* Commit previous writes */ + b43_read32(dev, B43_MMIO_MACCTL); + + if (phy->rev == 1) { + /* Workaround: Temporarly disable gmode through the early init + * phase, as the gmode stuff is not needed for phy rev 1 */ + phy->gmode = 0; + b43_wireless_core_reset(dev, 0); + b43_phy_initg(dev); + phy->gmode = 1; + b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); + } + + return 0; +} + +static int b43_gphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + + b43_phy_initg(dev); + gphy->initialised = 1; + + return 0; +} + +static void b43_gphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + + if (gphy->initialised) { + //TODO + gphy->initialised = 0; + } + b43_lo_g_cleanup(dev); + kfree(gphy->lo_control); + if (gphy->dyn_tssi_tbl) + kfree(gphy->tssi2dbm); + kfree(gphy); + dev->phy.g = NULL; +} + +static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* G-PHY needs 0x80 for read access. */ + reg |= 0x80; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) +{ + return (dev->phy.rev >= 6); +} + +static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + unsigned int channel; + + might_sleep(); + + if (state == RFKILL_STATE_UNBLOCKED) { + /* Turn radio ON */ + if (phy->radio_on) + return; + + b43_phy_write(dev, 0x0015, 0x8000); + b43_phy_write(dev, 0x0015, 0xCC00); + b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + if (gphy->radio_off_context.valid) { + /* Restore the RFover values. */ + b43_phy_write(dev, B43_PHY_RFOVER, + gphy->radio_off_context.rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + gphy->radio_off_context.rfoverval); + gphy->radio_off_context.valid = 0; + } + channel = phy->channel; + b43_gphy_channel_switch(dev, 6, 1); + b43_gphy_channel_switch(dev, channel, 0); + } else { + /* Turn radio OFF */ + u16 rfover, rfoverval; + + rfover = b43_phy_read(dev, B43_PHY_RFOVER); + rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + gphy->radio_off_context.rfover = rfover; + gphy->radio_off_context.rfoverval = rfoverval; + gphy->radio_off_context.valid = 1; + b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); + } +} + +static int b43_gphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + b43_gphy_channel_switch(dev, new_channel, 0); + + return 0; +} + +static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 1; /* Default to channel 1 */ +} + +static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{ + struct b43_phy *phy = &dev->phy; + u64 hf; + u16 tmp; + int autodiv = 0; + + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); + if (autodiv) + tmp |= B43_PHY_ANTWRSETT_ARXDIV; + else + tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; + b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); + if (phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= B43_PHY_OFDM61_10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + + tmp = + b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); + tmp = (tmp & 0xFF00) | 0x15; + b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, + tmp); + + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + if (phy->rev >= 6) + b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, + enum b43_interference_mitigation mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + int currentmode; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if ((phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + gphy->aci_wlan_automatic = 0; + switch (mode) { + case B43_INTERFMODE_AUTOWLAN: + gphy->aci_wlan_automatic = 1; + if (gphy->aci_enable) + mode = B43_INTERFMODE_MANUALWLAN; + else + mode = B43_INTERFMODE_NONE; + break; + case B43_INTERFMODE_NONE: + case B43_INTERFMODE_NONWLAN: + case B43_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = gphy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43_INTERFMODE_NONE) + b43_radio_interference_mitigation_disable(dev, currentmode); + + if (mode == B43_INTERFMODE_NONE) { + gphy->aci_enable = 0; + gphy->aci_hw_rssi = 0; + } else + b43_radio_interference_mitigation_enable(dev, mode); + gphy->interfmode = mode; + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy_g *gphy = dev->phy.g; + s8 dbm; + s32 tmp; + + tmp = (gphy->tgt_idle_tssi - gphy->cur_idle_tssi + tssi); + tmp = clamp_val(tmp, 0x00, 0x3F); + dbm = gphy->tssi2dbm[tmp]; + + return dbm; +} + +static void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) +{ + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; + + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ + + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; + + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ + + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; + } + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; + } + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; + } + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; + } + break; + } + + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); +} + +static void b43_gphy_op_xmitpower(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 tmp; + s8 v0, v1, v2, v3; + s8 average; + int max_pwr; + int desired_pwr, estimated_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + int rfatt, bbatt; + u8 tx_control; + + if (gphy->cur_idle_tssi == 0) + return; + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) { + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + b43_shm_clear_tssi(dev); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & 0x8)) + average -= 13; + + estimated_pwr = b43_gphy_estimate_power_out(dev, average); + + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if ((dev->dev->bus->sprom.boardflags_lo + & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } + + /*TODO: + max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + /* Get desired power (in Q5.2) */ + desired_pwr = INT_TO_Q52(phy->power_level); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "Current TX power output: " Q52_FMT + " dBm, " "Desired TX power output: " + Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + /* So do we finally need to adjust something? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + return; + + /* Calculate the new attenuation values. */ + bbatt = gphy->bbatt.att; + bbatt += bbatt_delta; + rfatt = gphy->rfatt.att; + rfatt += rfatt_delta; + + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = gphy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } + } + /* Save the control values */ + gphy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + gphy->rfatt.att = rfatt; + gphy->bbatt.att = bbatt; + + /* Adjust the hardware */ + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, + gphy->tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev); +} + +static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + //TODO: update_aci_moving_average + if (gphy->aci_enable && gphy->aci_wlan_automatic) { + b43_mac_suspend(dev); + if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) { + if (0 /*TODO: bunch of conditions */ ) { + phy->ops->interf_mitigation(dev, + B43_INTERFMODE_MANUALWLAN); + } + } else if (0 /*TODO*/) { + if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev)) + phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); + } + b43_mac_enable(dev); + } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } + b43_lo_g_maintanance_work(dev); +} + +static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) + return; + + b43_mac_suspend(dev); + b43_calc_nrssi_slope(dev); + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { + u8 old_chan = phy->channel; + + /* VCO Calibration */ + if (old_chan >= 8) + b43_switch_channel(dev, 1); + else + b43_switch_channel(dev, 13); + b43_switch_channel(dev, old_chan); + } + b43_mac_enable(dev); +} + +const struct b43_phy_operations b43_phyops_g = { + .allocate = b43_gphy_op_allocate, + .prepare = b43_gphy_op_prepare, + .init = b43_gphy_op_init, + .exit = b43_gphy_op_exit, + .phy_read = b43_gphy_op_read, + .phy_write = b43_gphy_op_write, + .radio_read = b43_gphy_op_radio_read, + .radio_write = b43_gphy_op_radio_write, + .supports_hwpctl = b43_gphy_op_supports_hwpctl, + .software_rfkill = b43_gphy_op_software_rfkill, + .switch_channel = b43_gphy_op_switch_channel, + .get_default_chan = b43_gphy_op_get_default_chan, + .set_rx_antenna = b43_gphy_op_set_rx_antenna, + .interf_mitigation = b43_gphy_op_interf_mitigation, + .xmitpower = b43_gphy_op_xmitpower, + .pwork_15sec = b43_gphy_op_pwork_15sec, + .pwork_60sec = b43_gphy_op_pwork_60sec, +}; diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h new file mode 100644 index 00000000000..1f0daebd6eb --- /dev/null +++ b/drivers/net/wireless/b43/phy_g.h @@ -0,0 +1,201 @@ +#ifndef LINUX_B43_PHY_G_H_ +#define LINUX_B43_PHY_G_H_ + +/* OFDM PHY registers are defined in the A-PHY header. */ +#include "phy_a.h" + +/* CCK (B) PHY Registers */ +#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ +#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ +#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ +#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 +#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) +#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ + +/* Extended G-PHY Registers */ +#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ +#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43_PHY_GTABNR_SHIFT 10 +#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ +#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ +#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 +#define B43_PHY_RFOVERVAL_LNA 0x7000 +#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 +#define B43_PHY_RFOVERVAL_PGA 0x0F00 +#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 +#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ +#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 +#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ +#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ +#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ +#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ +#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ + + +/*** G-PHY table numbers */ +#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) +#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) +#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) +#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); + + +/* Returns the boolean whether "TX Magnification" is enabled. */ +#define has_tx_magnification(phy) \ + (((phy)->rev >= 2) && \ + ((phy)->radio_ver == 0x2050) && \ + ((phy)->radio_rev == 8)) +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +/* Radio Attenuation (RF Attenuation) */ +struct b43_rfatt { + u8 att; /* Attenuation value */ + bool with_padmix; /* Flag, PAD Mixer enabled. */ +}; +struct b43_rfatt_list { + /* Attenuation values list */ + const struct b43_rfatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, + const struct b43_rfatt *b) +{ + return ((a->att == b->att) && + (a->with_padmix == b->with_padmix)); +} + +/* Baseband Attenuation */ +struct b43_bbatt { + u8 att; /* Attenuation value */ +}; +struct b43_bbatt_list { + /* Attenuation values list */ + const struct b43_bbatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, + const struct b43_bbatt *b) +{ + return (a->att == b->att); +} + +/* tx_control bits. */ +#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ +#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ +#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ + +struct b43_txpower_lo_control; + +struct b43_phy_g { + bool initialised; + bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ + + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + + /* LocalOscillator control values. */ + struct b43_txpower_lo_control *lo_control; + /* Values from b43_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ + + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43_INTERFSTACK_SIZE 26 + u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + u16 lofcal; + + u16 initval; //FIXME rename? + + /* The device does address auto increment for the OFDM tables. + * We cache the previously used address here and omit the address + * write on the next table access, if possible. */ + u16 ofdmtab_addr; /* The address currently set in hardware. */ + enum { /* The last data flow direction. */ + B43_OFDMTAB_DIRECTION_UNKNOWN = 0, + B43_OFDMTAB_DIRECTION_READ, + B43_OFDMTAB_DIRECTION_WRITE, + } ofdmtab_addr_direction; +}; + +void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation); +void b43_gphy_channel_switch(struct b43_wldev *dev, + unsigned int channel, + bool synthetic_pu_workaround); + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_g; + +#endif /* LINUX_B43_PHY_G_H_ */ diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index fec5645944a..7b9e99adb8c 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -24,6 +24,7 @@ #include "rfkill.h" #include "b43.h" +#include "phy_common.h" #include @@ -114,11 +115,11 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) goto out_unlock; } if (!dev->phy.radio_on) - b43_radio_turn_on(dev); + b43_software_rfkill(dev, state); break; case RFKILL_STATE_SOFT_BLOCKED: if (dev->phy.radio_on) - b43_radio_turn_off(dev, 0); + b43_software_rfkill(dev, state); break; default: b43warn(wl, "Received unexpected rfkill state %d.\n", state); diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 275095b8cbe..5adaa3692d7 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -29,7 +29,7 @@ #include "b43.h" #include "sysfs.h" #include "main.h" -#include "phy.h" +#include "phy_common.h" #define GENERIC_FILESIZE 64 @@ -59,7 +59,12 @@ static ssize_t b43_attr_interfmode_show(struct device *dev, mutex_lock(&wldev->wl->mutex); - switch (wldev->phy.interfmode) { + if (wldev->phy.type != B43_PHYTYPE_G) { + mutex_unlock(&wldev->wl->mutex); + return -ENOSYS; + } + + switch (wldev->phy.g->interfmode) { case B43_INTERFMODE_NONE: count = snprintf(buf, PAGE_SIZE, @@ -117,11 +122,15 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, mutex_lock(&wldev->wl->mutex); spin_lock_irqsave(&wldev->wl->irq_lock, flags); - err = b43_radio_set_interference_mitigation(wldev, mode); - if (err) { - b43err(wldev->wl, "Interference Mitigation not " - "supported by device\n"); - } + if (wldev->phy.ops->interf_mitigation) { + err = wldev->phy.ops->interf_mitigation(wldev, mode); + if (err) { + b43err(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + } + } else + err = -ENOSYS; + mmiowb(); spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); mutex_unlock(&wldev->wl->mutex); diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c index 3f5ea06bf13..1ef9a6463ec 100644 --- a/drivers/net/wireless/b43/tables.c +++ b/drivers/net/wireless/b43/tables.c @@ -27,7 +27,8 @@ #include "b43.h" #include "tables.h" -#include "phy.h" +#include "phy_g.h" + const u32 b43_tab_rotor[] = { 0xFEB93FFD, 0xFEC63FFD, /* 0 */ @@ -377,17 +378,17 @@ static inline void assert_sizes(void) u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; return b43_phy_read(dev, B43_PHY_OTABLEI); @@ -398,34 +399,34 @@ u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, u16 offset, u16 value) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); } u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u32 ret; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; ret = b43_phy_read(dev, B43_PHY_OTABLEQ); ret <<= 16; ret |= b43_phy_read(dev, B43_PHY_OTABLEI); @@ -436,17 +437,17 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, u16 offset, u32 value) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 2aa57551786..1de2c2e2e14 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -24,7 +24,7 @@ #include "b43.h" #include "tables_nphy.h" -#include "phy.h" +#include "phy_common.h" #include "nphy.h" diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index daa94211f83..0c0fb15abb9 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -27,7 +27,7 @@ #include "b43.h" #include "main.h" #include "tables.h" -#include "phy.h" +#include "phy_common.h" #include "wa.h" static void b43_wa_papd(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 9dda8169f7c..c8a831234e4 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -28,7 +28,7 @@ */ #include "xmit.h" -#include "phy.h" +#include "phy_common.h" #include "dma.h" #include "pio.h" @@ -431,6 +431,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, int adjust_2053, int adjust_2050) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; s32 tmp; switch (phy->radio_ver) { @@ -450,7 +451,8 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; - tmp = phy->nrssi_lt[in_rssi]; + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + tmp = gphy->nrssi_lt[in_rssi]; tmp = 31 - tmp; tmp *= -131; tmp /= 128; -- cgit v1.2.3 From 18c8adeb0244f823ba78a51e23f813fe68bc3c54 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 28 Aug 2008 19:33:40 +0200 Subject: b43: Rewrite TX power adjustment This patch rewrites the TX power recalculation algorithms to scale better with changed enviromnent. If there's low TX traffic, the power will be checked against the desired values every 60 seconds. If there is high TX traffic, the check is redone every 2 seconds. This improves the reaction times a lot and confuses the rate control less. It will also reduce the time it initially takes to tune to a new TX power value. With the old algorithm it could take about 30 to 45 seconds to settle to a new power value. This will happen in about two to four seconds now. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 10 ++ drivers/net/wireless/b43/main.c | 18 ++- drivers/net/wireless/b43/nphy.c | 15 ++- drivers/net/wireless/b43/phy_a.c | 11 +- drivers/net/wireless/b43/phy_common.c | 91 ++++++++++++++ drivers/net/wireless/b43/phy_common.h | 75 +++++++++++- drivers/net/wireless/b43/phy_g.c | 218 +++++++++++++++++++--------------- drivers/net/wireless/b43/phy_g.h | 22 ++-- drivers/net/wireless/b43/xmit.c | 2 + 9 files changed, 341 insertions(+), 121 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index fc280157596..f9c8161671d 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -173,6 +173,11 @@ enum { #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ +/* TSSI information */ +#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */ +#define B43_SHM_SH_TSSI_OFDM_A 0x0068 /* TSSI for last 4 OFDM frames (32bit) */ +#define B43_SHM_SH_TSSI_OFDM_G 0x0070 /* TSSI for last 4 OFDM frames (32bit) */ +#define B43_TSSI_MAX 0x7F /* Max value for one TSSI value */ /* SHM_SHARED TX FIFO variables */ #define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ #define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ @@ -648,6 +653,11 @@ struct b43_wl { struct b43_qos_params qos_params[4]; /* Workqueue for updating QOS parameters in hardware. */ struct work_struct qos_update_work; + + /* Work for adjustment of the transmission power. + * This is scheduled when we determine that the actual TX output + * power doesn't match what we want. */ + struct work_struct txpower_adjust_work; }; /* In-memory representation of a cached microcode file. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index af43f03b318..63bafc2f3f0 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2805,6 +2805,9 @@ static void b43_periodic_every60sec(struct b43_wldev *dev) if (ops->pwork_60sec) ops->pwork_60sec(dev); + + /* Force check the TX power emission now. */ + b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME); } static void b43_periodic_every30sec(struct b43_wldev *dev) @@ -2835,8 +2838,6 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) if (phy->ops->pwork_15sec) phy->ops->pwork_15sec(dev); - phy->ops->xmitpower(dev); - atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); wmb(); } @@ -3382,10 +3383,13 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Adjust the desired TX power level. */ if (conf->power_level != 0) { - if (conf->power_level != phy->power_level) { - phy->power_level = conf->power_level; - phy->ops->xmitpower(dev); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->power_level != phy->desired_txpower) { + phy->desired_txpower = conf->power_level; + b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | + B43_TXPWR_IGNORE_TSSI); } + spin_unlock_irqrestore(&wl->irq_lock, flags); } /* Antennas for RX and management frame TX. */ @@ -3785,6 +3789,7 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, struct b43_phy *phy) { phy->hardware_power_control = !!modparam_hwpctl; + phy->next_txpwr_check_time = jiffies; /* PHY TX errors counter. */ atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); } @@ -4204,6 +4209,8 @@ static void b43_op_stop(struct ieee80211_hw *hw) b43_wireless_core_stop(dev); b43_wireless_core_exit(dev); mutex_unlock(&wl->mutex); + + cancel_work_sync(&(wl->txpower_adjust_work)); } static int b43_op_set_retry_limit(struct ieee80211_hw *hw, @@ -4581,6 +4588,7 @@ static int b43_wireless_init(struct ssb_device *dev) INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->qos_update_work, b43_qos_update_work); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); + INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 831986c459f..4cfeab8560f 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -34,10 +34,16 @@ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO } -void b43_nphy_xmitpower(struct b43_wldev *dev) +static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) {//TODO } +static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + static void b43_chantab_radio_upload(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry *e) { @@ -602,10 +608,6 @@ static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) return 36; } -static void b43_nphy_op_xmitpower(struct b43_wldev *dev) -{//TODO -} - const struct b43_phy_operations b43_phyops_n = { .allocate = b43_nphy_op_allocate, .init = b43_nphy_op_init, @@ -617,5 +619,6 @@ const struct b43_phy_operations b43_phyops_n = { .software_rfkill = b43_nphy_op_software_rfkill, .switch_channel = b43_nphy_op_switch_channel, .get_default_chan = b43_nphy_op_get_default_chan, - .xmitpower = b43_nphy_op_xmitpower, + .recalc_txpower = b43_nphy_op_recalc_txpower, + .adjust_txpower = b43_nphy_op_adjust_txpower, }; diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index dd347314b76..4d7d59e3096 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -505,10 +505,16 @@ static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) b43_hf_write(dev, hf); } -static void b43_aphy_op_xmitpower(struct b43_wldev *dev) +static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) {//TODO } +static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) {//TODO } @@ -530,7 +536,8 @@ const struct b43_phy_operations b43_phyops_a = { .switch_channel = b43_aphy_op_switch_channel, .get_default_chan = b43_aphy_op_get_default_chan, .set_rx_antenna = b43_aphy_op_set_rx_antenna, - .xmitpower = b43_aphy_op_xmitpower, + .recalc_txpower = b43_aphy_op_recalc_txpower, + .adjust_txpower = b43_aphy_op_adjust_txpower, .pwork_15sec = b43_aphy_op_pwork_15sec, .pwork_60sec = b43_aphy_op_pwork_60sec, }; diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 45074c05d51..5a550a7af2e 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -274,3 +274,94 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) phy->ops->software_rfkill(dev, state); phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); } + +/** + * b43_phy_txpower_adjust_work - TX power workqueue. + * + * Workqueue for updating the TX power parameters in hardware. + */ +void b43_phy_txpower_adjust_work(struct work_struct *work) +{ + struct b43_wl *wl = container_of(work, struct b43_wl, + txpower_adjust_work); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + + if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED))) + dev->phy.ops->adjust_txpower(dev); + + mutex_unlock(&wl->mutex); +} + +/* Called with wl->irq_lock locked */ +void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) +{ + struct b43_phy *phy = &dev->phy; + unsigned long now = jiffies; + enum b43_txpwr_result result; + + if (!(flags & B43_TXPWR_IGNORE_TIME)) { + /* Check if it's time for a TXpower check. */ + if (time_before(now, phy->next_txpwr_check_time)) + return; /* Not yet */ + } + /* The next check will be needed in two seconds, or later. */ + phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2)); + + if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306)) + return; /* No software txpower adjustment needed */ + + result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI)); + if (result == B43_TXPWR_RES_DONE) + return; /* We are done. */ + B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST); + B43_WARN_ON(phy->ops->adjust_txpower == NULL); + + /* We must adjust the transmission power in hardware. + * Schedule b43_phy_txpower_adjust_work(). */ + queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work); +} + +int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) +{ + const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK); + unsigned int a, b, c, d; + unsigned int average; + u32 tmp; + + tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset); + a = tmp & 0xFF; + b = (tmp >> 8) & 0xFF; + c = (tmp >> 16) & 0xFF; + d = (tmp >> 24) & 0xFF; + if (a == 0 || a == B43_TSSI_MAX || + b == 0 || b == B43_TSSI_MAX || + c == 0 || c == B43_TSSI_MAX || + d == 0 || d == B43_TSSI_MAX) + return -ENOENT; + /* The values are OK. Clear them. */ + tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) | + (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24); + b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp); + + if (is_ofdm) { + a = (a + 32) & 0x3F; + b = (b + 32) & 0x3F; + c = (c + 32) & 0x3F; + d = (d + 32) & 0x3F; + } + + /* Get the average of the values with 0.5 added to each value. */ + average = (a + b + c + d + 2) / 4; + if (is_ofdm) { + /* Adjust for CCK-boost */ + if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO) + & B43_HF_CCKBOOST) + average = (average >= 13) ? (average - 13) : 0; + } + + return average; +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9b9635eda9c..f8db9f40df5 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -60,6 +60,17 @@ enum { B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, }; +/** + * enum b43_txpwr_result - Return value for the recalc_txpower PHY op. + * + * @B43_TXPWR_RES_NEED_ADJUST: Values changed. Hardware adjustment is needed. + * @B43_TXPWR_RES_DONE: No more work to do. Everything is done. + */ +enum b43_txpwr_result { + B43_TXPWR_RES_NEED_ADJUST, + B43_TXPWR_RES_DONE, +}; + /** * struct b43_phy_operations - Function pointers for PHY ops. * @@ -96,8 +107,23 @@ enum { * @interf_mitigation: Switch the Interference Mitigation mode. * Can be NULL, if not supported. * - * @xmitpower: FIXME REMOVEME + * @recalc_txpower: Recalculate the transmission power parameters. + * This callback has to recalculate the TX power settings, + * but does not need to write them to the hardware, yet. + * Returns enum b43_txpwr_result to indicate whether the hardware + * needs to be adjusted. + * If B43_TXPWR_NEED_ADJUST is returned, @adjust_txpower + * will be called later. + * If the parameter "ignore_tssi" is true, the TSSI values should + * be ignored and a recalculation of the power settings should be + * done even if the TSSI values did not change. + * This callback is called with wl->irq_lock held and must not sleep. * Must not be NULL. + * @adjust_txpower: Write the previously calculated TX power settings + * (from @recalc_txpower) to the hardware. + * This function may sleep. + * Can be NULL, if (and ONLY if) @recalc_txpower _always_ + * returns B43_TXPWR_RES_DONE. * * @pwork_15sec: Periodic work. Called every 15 seconds. * Can be NULL, if not required. @@ -127,7 +153,9 @@ struct b43_phy_operations { enum b43_interference_mitigation new_mode); /* Transmission power adjustment */ - void (*xmitpower)(struct b43_wldev *dev); + enum b43_txpwr_result (*recalc_txpower)(struct b43_wldev *dev, + bool ignore_tssi); + void (*adjust_txpower)(struct b43_wldev *dev); /* Misc */ void (*pwork_15sec)(struct b43_wldev *dev); @@ -183,11 +211,15 @@ struct b43_phy { /* Desired TX power level (in dBm). * This is set by the user and adjusted in b43_phy_xmitpower(). */ - u8 power_level; + int desired_txpower; /* Hardware Power Control enabled? */ bool hardware_power_control; + /* The time (in absolute jiffies) when the next TX power output + * check is needed. */ + unsigned long next_txpwr_check_time; + /* current channel */ unsigned int channel; @@ -309,4 +341,41 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); */ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); +/** + * b43_phy_txpower_check - Check TX power output. + * + * Compare the current TX power output to the desired power emission + * and schedule an adjustment in case it mismatches. + * Requires wl->irq_lock locked. + * + * @flags: OR'ed enum b43_phy_txpower_check_flags flags. + * See the docs below. + */ +void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags); +/** + * enum b43_phy_txpower_check_flags - Flags for b43_phy_txpower_check() + * + * @B43_TXPWR_IGNORE_TIME: Ignore the schedule time and force-redo + * the check now. + * @B43_TXPWR_IGNORE_TSSI: Redo the recalculation, even if the average + * TSSI did not change. + */ +enum b43_phy_txpower_check_flags { + B43_TXPWR_IGNORE_TIME = (1 << 0), + B43_TXPWR_IGNORE_TSSI = (1 << 1), +}; + +struct work_struct; +void b43_phy_txpower_adjust_work(struct work_struct *work); + +/** + * b43_phy_shm_tssi_read - Read the average of the last 4 TSSI from SHM. + * + * @shm_offset: The SHM address to read the values from. + * + * Returns the average of the 4 TSSI values, or a negative error code. + */ +int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); + + #endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index bb95c54cd43..fce84896d34 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2659,6 +2659,7 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev) /* OFDM-table address caching. */ gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; + gphy->average_tssi = 0xFF; lo = kzalloc(sizeof(*lo), GFP_KERNEL); if (!lo) { @@ -3011,113 +3012,20 @@ static void b43_put_attenuation_into_ranges(struct b43_wldev *dev, *_bbatt = clamp_val(bbatt, bb_min, bb_max); } -static void b43_gphy_op_xmitpower(struct b43_wldev *dev) +static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; - u16 tmp; - s8 v0, v1, v2, v3; - s8 average; - int max_pwr; - int desired_pwr, estimated_pwr, pwr_adjust; - int rfatt_delta, bbatt_delta; int rfatt, bbatt; u8 tx_control; - if (gphy->cur_idle_tssi == 0) - return; - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; - - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - tmp = 0; - - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) { - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) - return; - v0 = (v0 + 0x20) & 0x3F; - v1 = (v1 + 0x20) & 0x3F; - v2 = (v2 + 0x20) & 0x3F; - v3 = (v3 + 0x20) & 0x3F; - tmp = 1; - } - b43_shm_clear_tssi(dev); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & 0x8)) - average -= 13; - - estimated_pwr = b43_gphy_estimate_power_out(dev, average); - - max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.boardflags_lo - & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) - max_pwr -= 0x3; - if (unlikely(max_pwr <= 0)) { - b43warn(dev->wl, - "Invalid max-TX-power value in SPROM.\n"); - max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.maxpwr_bg = max_pwr; - } - - /*TODO: - max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - /* Get desired power (in Q5.2) */ - desired_pwr = INT_TO_Q52(phy->power_level); - /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = clamp_val(desired_pwr, 0, max_pwr); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, - "Current TX power output: " Q52_FMT - " dBm, " "Desired TX power output: " - Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), - Q52_ARG(desired_pwr)); - } - - /* Calculate the adjustment delta. */ - pwr_adjust = desired_pwr - estimated_pwr; - - /* RF attenuation delta. */ - rfatt_delta = ((pwr_adjust + 7) / 8); - /* Lower attenuation => Bigger power output. Negate it. */ - rfatt_delta = -rfatt_delta; - - /* Baseband attenuation delta. */ - bbatt_delta = pwr_adjust / 2; - /* Lower attenuation => Bigger power output. Negate it. */ - bbatt_delta = -bbatt_delta; - /* RF att affects power level 4 times as much as - * Baseband attennuation. Subtract it. */ - bbatt_delta -= 4 * rfatt_delta; - - /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) - return; + spin_lock_irq(&dev->wl->irq_lock); /* Calculate the new attenuation values. */ bbatt = gphy->bbatt.att; - bbatt += bbatt_delta; + bbatt += gphy->bbatt_delta; rfatt = gphy->rfatt.att; - rfatt += rfatt_delta; + rfatt += gphy->rfatt_delta; b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); tx_control = gphy->tx_control; @@ -3152,6 +3060,14 @@ static void b43_gphy_op_xmitpower(struct b43_wldev *dev) gphy->rfatt.att = rfatt; gphy->bbatt.att = bbatt; + /* We drop the lock early, so we can sleep during hardware + * adjustment. Possible races with op_recalc_txpower are harmless, + * as we will be called once again in case we raced. */ + spin_unlock_irq(&dev->wl->irq_lock); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) + b43dbg(dev->wl, "Adjusting TX power\n"); + /* Adjust the hardware */ b43_phy_lock(dev); b43_radio_lock(dev); @@ -3161,6 +3077,111 @@ static void b43_gphy_op_xmitpower(struct b43_wldev *dev) b43_phy_unlock(dev); } +static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + unsigned int average_tssi; + int cck_result, ofdm_result; + int estimated_pwr, desired_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + unsigned int max_pwr; + + /* First get the average TSSI */ + cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK); + ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G); + if ((cck_result < 0) && (ofdm_result < 0)) { + /* No TSSI information available */ + if (!ignore_tssi) + goto no_adjustment_needed; + cck_result = 0; + ofdm_result = 0; + } + if (cck_result < 0) + average_tssi = ofdm_result; + else if (ofdm_result < 0) + average_tssi = cck_result; + else + average_tssi = (cck_result + ofdm_result) / 2; + /* Merge the average with the stored value. */ + if (likely(gphy->average_tssi != 0xFF)) + average_tssi = (average_tssi + gphy->average_tssi) / 2; + gphy->average_tssi = average_tssi; + B43_WARN_ON(average_tssi >= B43_TSSI_MAX); + + /* Estimate the TX power emission based on the TSSI */ + estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi); + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + max_pwr -= 3; /* minus 0.75 */ + if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = INT_TO_Q52(20); /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } + + /* Get desired power (in Q5.2) */ + if (phy->desired_txpower < 0) + desired_pwr = INT_TO_Q52(0); + else + desired_pwr = INT_TO_Q52(phy->desired_txpower); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "[TX power] current = " Q52_FMT + " dBm, desired = " Q52_FMT + " dBm, max = " Q52_FMT "\n", + Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr), + Q52_ARG(max_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + if (pwr_adjust == 0) + goto no_adjustment_needed; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust; + b43dbg(dev->wl, + "[TX power deltas] %s" Q52_FMT " dBm => " + "bbatt-delta = %d, rfatt-delta = %d\n", + (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm), + bbatt_delta, rfatt_delta); + } + /* So do we finally need to adjust something in hardware? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + goto no_adjustment_needed; + + /* Save the deltas for later when we adjust the power. */ + gphy->bbatt_delta = bbatt_delta; + gphy->rfatt_delta = rfatt_delta; + + /* We need to adjust the TX power on the device. */ + return B43_TXPWR_RES_NEED_ADJUST; + +no_adjustment_needed: + return B43_TXPWR_RES_DONE; +} + static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3223,7 +3244,8 @@ const struct b43_phy_operations b43_phyops_g = { .get_default_chan = b43_gphy_op_get_default_chan, .set_rx_antenna = b43_gphy_op_set_rx_antenna, .interf_mitigation = b43_gphy_op_interf_mitigation, - .xmitpower = b43_gphy_op_xmitpower, + .recalc_txpower = b43_gphy_op_recalc_txpower, + .adjust_txpower = b43_gphy_op_adjust_txpower, .pwork_15sec = b43_gphy_op_pwork_15sec, .pwork_60sec = b43_gphy_op_pwork_60sec, }; diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 1f0daebd6eb..7f95edea1c6 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -115,7 +115,6 @@ struct b43_txpower_lo_control; struct b43_phy_g { bool initialised; - bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ /* ACI (adjacent channel interference) flags. */ bool aci_enable; @@ -135,12 +134,26 @@ struct b43_phy_g { u16 minlowsig[2]; u16 minlowsigpos[2]; - /* TSSI to dBm table in use */ + /* Pointer to the table used to convert a + * TSSI value to dBm-Q5.2 */ const s8 *tssi2dbm; + /* tssi2dbm is kmalloc()ed. Only used for free()ing. */ + bool dyn_tssi_tbl; /* Target idle TSSI */ int tgt_idle_tssi; /* Current idle TSSI */ int cur_idle_tssi; + /* The current average TSSI. + * Needs irq_lock, as it's updated in the IRQ path. */ + u8 average_tssi; + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ + /* The calculated attenuation deltas that are used later + * when adjusting the actual power output. */ + int bbatt_delta; + int rfatt_delta; /* LocalOscillator control values. */ struct b43_txpower_lo_control *lo_control; @@ -151,11 +164,6 @@ struct b43_phy_g { s16 lna_gain; /* LNA */ s16 pga_gain; /* PGA */ - /* Current TX power level attenuation control values */ - struct b43_bbatt bbatt; - struct b43_rfatt rfatt; - u8 tx_control; /* B43_TXCTL_XXX */ - /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code. diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index c8a831234e4..5e0b71c3ad0 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -680,6 +680,8 @@ void b43_handle_txstatus(struct b43_wldev *dev, b43_pio_handle_txstatus(dev, status); else b43_dma_handle_txstatus(dev, status); + + b43_phy_txpower_check(dev, 0); } /* Fill out the mac80211 TXstatus report based on the b43-specific -- cgit v1.2.3 From 994917f8b718f1cd7114317cc3cbf04fe46c1841 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 31 Aug 2008 15:20:26 +0200 Subject: pcmcia: card services header cleanup 16-bit PCMCIA device handling function definitions are moved to ds.h, internal definitions to cs_internal.h. Signed-off-by: Dominik Brodowski --- drivers/net/wireless/orinoco_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index c7b57d9d499..f8d9de2fb4c 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -80,7 +80,7 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) /* We need atomic ops here, because we're not holding the lock */ set_bit(0, &card->hard_reset_in_progress); - err = pcmcia_reset_card(link, NULL); + err = pcmcia_reset_card(link->socket); if (err) return err; -- cgit v1.2.3 From 2f3061eb1086f98990d6495b8c63a1b83f2f59aa Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 31 Aug 2008 15:50:33 +0200 Subject: pcmcia: remove unused argument to pcmcia_parse_tuple() Since we're just parsing the tuple being passed to this function, we don't need any device-specific information. Also, remove the call to pcmcia_validate_cis() from pcmciamtd.c, since it is already called by the PCMCIA core. Signed-off-by: Dominik Brodowski --- drivers/net/wireless/b43/pcmcia.c | 2 +- drivers/net/wireless/hostap/hostap_cs.c | 2 +- drivers/net/wireless/libertas/if_cs.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index ab42fb6addf..3cfc30307a2 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -87,7 +87,7 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) res = pcmcia_get_tuple_data(dev, &tuple); if (res != 0) goto err_kfree_ssb; - res = pcmcia_parse_tuple(dev, &tuple, &parse); + res = pcmcia_parse_tuple(&tuple, &parse); if (res != 0) goto err_kfree_ssb; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 2826e674a8e..63374027735 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -305,7 +305,7 @@ static int sandisk_enable_wireless(struct net_device *dev) tuple.DesiredTuple = CISTPL_LONGLINK_MFC; if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || pcmcia_get_tuple_data(hw_priv->link, &tuple) || - pcmcia_parse_tuple(hw_priv->link, &tuple, parse) || + pcmcia_parse_tuple(&tuple, parse) || parse->longlink_mfc.nfn < 2) { /* No multi-function links found */ ret = -ENODEV; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 04d7a251e3f..e2fe2d67732 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -798,7 +798,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 || (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 || - (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0) + (ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) { lbs_pr_err("error in pcmcia_get_first_tuple etc\n"); goto out1; -- cgit v1.2.3 From fa9abe050d0a018b888fce61a4353afab17b0860 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 28 Aug 2008 19:13:51 +0200 Subject: b43: Don't use memcpy for overlapping areas It is valid to pass &gphy->rfatt and &gphy->bbatt as rfatt and bbatt pointer arguments to the function. So we have to use memmove for the possibly overlapping memory areas. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_g.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index fce84896d34..063db5c00ce 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -232,11 +232,12 @@ void b43_set_txpower_g(struct b43_wldev *dev, if (unlikely(tx_bias == 0xFF)) tx_bias = 0; - /* Save the values for later */ + /* Save the values for later. Use memmove, because it's valid + * to pass &gphy->rfatt as rfatt pointer argument. Same for bbatt. */ gphy->tx_control = tx_control; - memcpy(&gphy->rfatt, rfatt, sizeof(*rfatt)); + memmove(&gphy->rfatt, rfatt, sizeof(*rfatt)); gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); - memcpy(&gphy->bbatt, bbatt, sizeof(*bbatt)); + memmove(&gphy->bbatt, bbatt, sizeof(*bbatt)); if (b43_debug(dev, B43_DBG_XMITPOWER)) { b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " -- cgit v1.2.3 From c6e387a214f4b2c4bd48020409e366c133385d98 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Fri, 29 Aug 2008 22:45:39 +0300 Subject: ath5k: HW code cleanup * No code changes... * Split hw.c to multiple files for better maintenance and add some documentation on each file code is going to grow soon (eeprom.c for example is going to get much stuff currently developed on ath_info) so it's better this way. * Rename following functions to maintain naming scheme: ah_setup_xtx_desc -> ah_setup_mrr_tx_desc (Because xtx doesn't say much, it's actually a multi-rate-retry tx descriptor) ath5k_hw_put_tx/rx_buf - > ath5k_hw_set_tx/rxdp ath5k_hw_get_tx/rx_buf -> ath5k_hw_get_tx/rxdp (We don't put any "buf" we set descriptor pointers on hw) ath5k_hw_tx_start -> ath5k_hw_start_tx_dma ath5k_hw_start_rx -> ath5k_hw_start_rx_dma ath5k_hw_stop_pcu_recv -> ath5k_hw_stop_rx_pcu (It's easier this way to identify them, we also have ath5k_hw_start_rx_pcu which completes the set) ath5k_hw_set_intr -> ath5k_hw_set_imr (As in get_isr we set imr here, not "intr") * Move ath5k_hw_setup_rx_desc on ah->ah_setup_rx_desc so we can include support for different rx descriptors in the future * Further cleanups so that checkpatch doesn't complain (only some > 80 col warnings for eeprom.h and reg.h as usual due to comments) Tested on 5211 and 5213 cards and works ok. Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/Makefile | 12 +- drivers/net/wireless/ath5k/ath5k.h | 390 ++- drivers/net/wireless/ath5k/attach.c | 315 +++ drivers/net/wireless/ath5k/base.c | 32 +- drivers/net/wireless/ath5k/caps.c | 193 ++ drivers/net/wireless/ath5k/debug.c | 4 +- drivers/net/wireless/ath5k/desc.c | 667 +++++ drivers/net/wireless/ath5k/desc.h | 332 +++ drivers/net/wireless/ath5k/dma.c | 566 +++++ drivers/net/wireless/ath5k/eeprom.c | 466 ++++ drivers/net/wireless/ath5k/eeprom.h | 215 ++ drivers/net/wireless/ath5k/gpio.c | 176 ++ drivers/net/wireless/ath5k/hw.c | 4492 --------------------------------- drivers/net/wireless/ath5k/hw.h | 616 ----- drivers/net/wireless/ath5k/initvals.c | 22 +- drivers/net/wireless/ath5k/pcu.c | 1002 ++++++++ drivers/net/wireless/ath5k/phy.c | 10 +- drivers/net/wireless/ath5k/qcu.c | 488 ++++ drivers/net/wireless/ath5k/reg.h | 102 +- drivers/net/wireless/ath5k/reset.c | 925 +++++++ 20 files changed, 5709 insertions(+), 5316 deletions(-) create mode 100644 drivers/net/wireless/ath5k/attach.c create mode 100644 drivers/net/wireless/ath5k/caps.c create mode 100644 drivers/net/wireless/ath5k/desc.c create mode 100644 drivers/net/wireless/ath5k/desc.h create mode 100644 drivers/net/wireless/ath5k/dma.c create mode 100644 drivers/net/wireless/ath5k/eeprom.c create mode 100644 drivers/net/wireless/ath5k/eeprom.h create mode 100644 drivers/net/wireless/ath5k/gpio.c delete mode 100644 drivers/net/wireless/ath5k/hw.c delete mode 100644 drivers/net/wireless/ath5k/hw.h create mode 100644 drivers/net/wireless/ath5k/pcu.c create mode 100644 drivers/net/wireless/ath5k/qcu.c create mode 100644 drivers/net/wireless/ath5k/reset.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile index 564ecd0c5d4..719cfaef708 100644 --- a/drivers/net/wireless/ath5k/Makefile +++ b/drivers/net/wireless/ath5k/Makefile @@ -1,6 +1,14 @@ -ath5k-y += base.o -ath5k-y += hw.o +ath5k-y += caps.o ath5k-y += initvals.o +ath5k-y += eeprom.o +ath5k-y += gpio.o +ath5k-y += desc.o +ath5k-y += dma.o +ath5k-y += qcu.o +ath5k-y += pcu.o ath5k-y += phy.o +ath5k-y += reset.o +ath5k-y += attach.o +ath5k-y += base.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index c1b49787366..4c0211798a7 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -18,18 +18,23 @@ #ifndef _ATH5K_H #define _ATH5K_H -/* Set this to 1 to disable regulatory domain restrictions for channel tests. - * WARNING: This is for debuging only and has side effects (eg. scan takes too - * long and results timeouts). It's also illegal to tune to some of the - * supported frequencies in some countries, so use this at your own risk, - * you've been warned. */ +/* TODO: Clean up channel debuging -doesn't work anyway- and start + * working on reg. control code using all available eeprom information + * -rev. engineering needed- */ #define CHAN_DEBUG 0 #include #include #include -#include "hw.h" +/* RX/TX descriptor hw structs + * TODO: Driver part should only see sw structs */ +#include "desc.h" + +/* EEPROM structs/offsets + * TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities) + * and clean up common bits, then introduce set/get functions in eeprom.c */ +#include "eeprom.h" /* PCI IDs */ #define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ @@ -86,8 +91,93 @@ #define ATH5K_ERR(_sc, _fmt, ...) \ ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__) +/* + * AR5K REGISTER ACCESS + */ + +/* Some macros to read/write fields */ + +/* First shift, then mask */ +#define AR5K_REG_SM(_val, _flags) \ + (((_val) << _flags##_S) & (_flags)) + +/* First mask, then shift */ +#define AR5K_REG_MS(_val, _flags) \ + (((_val) & (_flags)) >> _flags##_S) + +/* Some registers can hold multiple values of interest. For this + * reason when we want to write to these registers we must first + * retrieve the values which we do not want to clear (lets call this + * old_data) and then set the register with this and our new_value: + * ( old_data | new_value) */ +#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \ + (((_val) << _flags##_S) & (_flags)), _reg) + +#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \ + (_mask)) | (_flags), _reg) + +#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \ + ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg) + +#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ + ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) + +/* Access to PHY registers */ +#define AR5K_PHY_READ(ah, _reg) \ + ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) + +#define AR5K_PHY_WRITE(ah, _reg, _val) \ + ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) + +/* Access QCU registers per queue */ +#define AR5K_REG_READ_Q(ah, _reg, _queue) \ + (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ + +#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \ + ath5k_hw_reg_write(ah, (1 << _queue), _reg) + +#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \ + _reg |= 1 << _queue; \ +} while (0) + +#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \ + _reg &= ~(1 << _queue); \ +} while (0) + +/* Used while writing initvals */ +#define AR5K_REG_WAIT(_i) do { \ + if (_i % 64) \ + udelay(1); \ +} while (0) + +/* Register dumps are done per operation mode */ +#define AR5K_INI_RFGAIN_5GHZ 0 +#define AR5K_INI_RFGAIN_2GHZ 1 + +/* TODO: Clean this up */ +#define AR5K_INI_VAL_11A 0 +#define AR5K_INI_VAL_11A_TURBO 1 +#define AR5K_INI_VAL_11B 2 +#define AR5K_INI_VAL_11G 3 +#define AR5K_INI_VAL_11G_TURBO 4 +#define AR5K_INI_VAL_XR 0 +#define AR5K_INI_VAL_MAX 5 + +#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS +#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS + +/* Used for BSSID etc manipulation */ +#define AR5K_LOW_ID(_a)( \ +(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ +) + +#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) + /* * Some tuneable values (these should be changeable by the user) + * TODO: Make use of them and add more options OR use debug/configfs */ #define AR5K_TUNE_DMA_BEACON_RESP 2 #define AR5K_TUNE_SW_BEACON_RESP 10 @@ -98,13 +188,13 @@ #define AR5K_TUNE_REGISTER_TIMEOUT 20000 /* Register for RSSI threshold has a mask of 0xff, so 255 seems to * be the max value. */ -#define AR5K_TUNE_RSSI_THRES 129 +#define AR5K_TUNE_RSSI_THRES 129 /* This must be set when setting the RSSI threshold otherwise it can * prevent a reset. If AR5K_RSSI_THR is read after writing to it * the BMISS_THRES will be seen as 0, seems harware doesn't keep * track of it. Max value depends on harware. For AR5210 this is just 7. * For AR5211+ this seems to be up to 255. */ -#define AR5K_TUNE_BMISS_THRES 7 +#define AR5K_TUNE_BMISS_THRES 7 #define AR5K_TUNE_REGISTER_DWELL_TIME 20000 #define AR5K_TUNE_BEACON_INTERVAL 100 #define AR5K_TUNE_AIFS 2 @@ -123,6 +213,55 @@ #define AR5K_TUNE_ANT_DIVERSITY true #define AR5K_TUNE_HWTXTRIES 4 +#define AR5K_INIT_CARR_SENSE_EN 1 + +/*Swap RX/TX Descriptor for big endian archs*/ +#if defined(__BIG_ENDIAN) +#define AR5K_INIT_CFG ( \ + AR5K_CFG_SWTD | AR5K_CFG_SWRD \ +) +#else +#define AR5K_INIT_CFG 0x00000000 +#endif + +/* Initial values */ +#define AR5K_INIT_TX_LATENCY 502 +#define AR5K_INIT_USEC 39 +#define AR5K_INIT_USEC_TURBO 79 +#define AR5K_INIT_USEC_32 31 +#define AR5K_INIT_SLOT_TIME 396 +#define AR5K_INIT_SLOT_TIME_TURBO 480 +#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 +#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 +#define AR5K_INIT_PROG_IFS 920 +#define AR5K_INIT_PROG_IFS_TURBO 960 +#define AR5K_INIT_EIFS 3440 +#define AR5K_INIT_EIFS_TURBO 6880 +#define AR5K_INIT_SIFS 560 +#define AR5K_INIT_SIFS_TURBO 480 +#define AR5K_INIT_SH_RETRY 10 +#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY +#define AR5K_INIT_SSH_RETRY 32 +#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY +#define AR5K_INIT_TX_RETRY 10 + +#define AR5K_INIT_TRANSMIT_LATENCY ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC) \ +) +#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC_TURBO) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ + (AR5K_INIT_PROG_IFS) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \ + (AR5K_INIT_PROG_IFS_TURBO) \ +) + /* token to use for aifs, cwmin, cwmax in MadWiFi */ #define AR5K_TXQ_USEDEFAULT ((u32) -1) @@ -196,7 +335,6 @@ struct ath5k_srev_name { #define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ /* IEEE defs */ - #define IEEE80211_MAX_LEN 2500 /* TODO add support to mac80211 for vendor-specific rates and modes */ @@ -268,16 +406,13 @@ enum ath5k_driver_mode { AR5K_MODE_MAX = 5 }; -/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */ -#define AR5K_SET_SHORT_PREAMBLE 0x04 - /****************\ TX DEFINITIONS \****************/ /* - * TX Status + * TX Status descriptor */ struct ath5k_tx_status { u16 ts_seqnum; @@ -349,7 +484,6 @@ enum ath5k_tx_queue_id { AR5K_TX_QUEUE_ID_XR_DATA = 9, }; - /* * Flags to set hw queue's parameters... */ @@ -382,7 +516,8 @@ struct ath5k_txq_info { /* * Transmit packet types. - * These are not fully used inside OpenHAL yet + * used on tx control descriptor + * TODO: Use them inside base.c corectly */ enum ath5k_pkt_type { AR5K_PKT_TYPE_NORMAL = 0, @@ -425,7 +560,7 @@ enum ath5k_dmasize { \****************/ /* - * RX Status + * RX Status descriptor */ struct ath5k_rx_status { u16 rs_datalen; @@ -489,34 +624,59 @@ struct ath5k_beacon_state { #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) +/*******************************\ + GAIN OPTIMIZATION DEFINITIONS +\*******************************/ + +enum ath5k_rfgain { + AR5K_RFGAIN_INACTIVE = 0, + AR5K_RFGAIN_READ_REQUESTED, + AR5K_RFGAIN_NEED_CHANGE, +}; + +#define AR5K_GAIN_CRN_FIX_BITS_5111 4 +#define AR5K_GAIN_CRN_FIX_BITS_5112 7 +#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112 +#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15 +#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20 +#define AR5K_GAIN_CCK_PROBE_CORR 5 +#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15 +#define AR5K_GAIN_STEP_COUNT 10 +#define AR5K_GAIN_PARAM_TX_CLIP 0 +#define AR5K_GAIN_PARAM_PD_90 1 +#define AR5K_GAIN_PARAM_PD_84 2 +#define AR5K_GAIN_PARAM_GAIN_SEL 3 +#define AR5K_GAIN_PARAM_MIX_ORN 0 +#define AR5K_GAIN_PARAM_PD_138 1 +#define AR5K_GAIN_PARAM_PD_137 2 +#define AR5K_GAIN_PARAM_PD_136 3 +#define AR5K_GAIN_PARAM_PD_132 4 +#define AR5K_GAIN_PARAM_PD_131 5 +#define AR5K_GAIN_PARAM_PD_130 6 +#define AR5K_GAIN_CHECK_ADJUST(_g) \ + ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) + +struct ath5k_gain_opt_step { + s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; + s32 gos_gain; +}; + +struct ath5k_gain { + u32 g_step_idx; + u32 g_current; + u32 g_target; + u32 g_low; + u32 g_high; + u32 g_f_corr; + u32 g_active; + const struct ath5k_gain_opt_step *g_step; +}; + + /********************\ COMMON DEFINITIONS \********************/ -/* - * Atheros hardware descriptor - * This is read and written to by the hardware - */ -struct ath5k_desc { - u32 ds_link; /* physical address of the next descriptor */ - u32 ds_data; /* physical address of data buffer (skb) */ - - union { - struct ath5k_hw_5210_tx_desc ds_tx5210; - struct ath5k_hw_5212_tx_desc ds_tx5212; - struct ath5k_hw_all_rx_desc ds_rx; - } ud; -} __packed; - -#define AR5K_RXDESC_INTREQ 0x0020 - -#define AR5K_TXDESC_CLRDMASK 0x0001 -#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/ -#define AR5K_TXDESC_RTSENA 0x0004 -#define AR5K_TXDESC_CTSENA 0x0008 -#define AR5K_TXDESC_INTREQ 0x0010 -#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ - #define AR5K_SLOT_TIME_9 396 #define AR5K_SLOT_TIME_20 880 #define AR5K_SLOT_TIME_MAX 0xffff @@ -548,15 +708,16 @@ struct ath5k_desc { #define CHANNEL_MODES CHANNEL_ALL /* - * Used internaly in OpenHAL (ar5211.c/ar5212.c - * for reset_tx_queue). Also see struct struct ieee80211_channel. + * Used internaly for reset_tx_queue). + * Also see struct struct ieee80211_channel. */ #define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0) #define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0) /* - * The following structure will be used to map 2GHz channels to + * The following structure is used to map 2GHz channels to * 5GHz Atheros channels. + * TODO: Clean up */ struct ath5k_athchan_2ghz { u32 a2_flags; @@ -564,9 +725,9 @@ struct ath5k_athchan_2ghz { }; -/* - * Rate definitions - */ +/******************\ + RATE DEFINITIONS +\******************/ /** * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32. @@ -618,6 +779,8 @@ struct ath5k_athchan_2ghz { #define ATH5K_RATE_CODE_XR_2M 0x06 #define ATH5K_RATE_CODE_XR_3M 0x01 +/* adding this flag to rate_code enables short preamble */ +#define AR5K_SET_SHORT_PREAMBLE 0x04 /* * Crypto definitions @@ -639,7 +802,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 */ @@ -750,7 +912,8 @@ enum ath5k_power_mode { /* * These match net80211 definitions (not used in - * d80211). + * mac80211). + * TODO: Clean this up */ #define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/ #define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/ @@ -766,7 +929,8 @@ enum ath5k_power_mode { /* * Chipset capabilities -see ath5k_hw_get_capability- * get_capability function is not yet fully implemented - * in OpenHAL so most of these don't work yet... + * in ath5k so most of these don't work yet... + * TODO: Implement these & merge with _TUNE_ stuff above */ enum ath5k_capability_type { AR5K_CAP_REG_DMN = 0, /* Used to get current reg. domain id */ @@ -835,6 +999,7 @@ struct ath5k_capabilities { #define AR5K_MAX_GPIO 10 #define AR5K_MAX_RF_BANKS 8 +/* TODO: Clean up and merge with ath5k_softc */ struct ath5k_hw { u32 ah_magic; @@ -927,11 +1092,13 @@ struct ath5k_hw { /* * Function pointers */ + int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags); int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, + int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, @@ -944,33 +1111,38 @@ struct ath5k_hw { * Prototypes */ -/* General Functions */ -extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set); /* Attach/Detach Functions */ extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); -extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode); extern void ath5k_hw_detach(struct ath5k_hw *ah); + /* Reset Functions */ +extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel); /* Power management functions */ extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); + /* DMA Related Functions */ -extern void ath5k_hw_start_rx(struct ath5k_hw *ah); +extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah); extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); -extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah); -extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr); -extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue); +extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah); +extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr); +extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue); extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue); -extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr); +extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue); +extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, + u32 phys_addr); extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); /* Interrupt handling */ extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); -extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask); +extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum +ath5k_int new_mask); extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats); + /* EEPROM access functions */ -extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain); +extern int ath5k_eeprom_init(struct ath5k_hw *ah); +extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); + /* Protocol Control Unit Functions */ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); /* BSSID Functions */ @@ -980,14 +1152,14 @@ extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); /* Receive start/stop functions */ extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); -extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah); +extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); /* RX Filter functions */ extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1); -extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index); +extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index); extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index); extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); -/* Beacon related functions */ +/* Beacon control functions */ extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah); extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah); @@ -1009,61 +1181,129 @@ extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); + /* Queue Control Unit, DFS Control Unit Functions */ -extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); -extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info); extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info); +extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, + const struct ath5k_txq_info *queue_info); +extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, + enum ath5k_tx_queue queue_type, + struct ath5k_txq_info *queue_info); +extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); -extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah); +extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); + /* Hardware Descriptor Functions */ -extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags); +extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah); + /* GPIO Functions */ extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); -extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); +extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); + /* Misc functions */ +int ath5k_hw_set_capabilities(struct ath5k_hw *ah); extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); - +extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id); +extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah); /* Initial register settings functions */ extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); + /* Initialize RF */ extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); - - /* PHY/RF channel functions */ extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); /* PHY calibration */ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); -extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); +extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); /* Misc PHY functions */ extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant); extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); -extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); /* TX power setup */ extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower); extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power); +/* + * Functions used internaly + */ + +/* + * Translate usec to hw clock units + */ +static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) +{ + return turbo ? (usec * 80) : (usec * 40); +} +/* + * Translate hw clock units to usec + */ +static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) +{ + return turbo ? (clock / 80) : (clock / 40); +} + +/* + * Read from a register + */ static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) { return ioread32(ah->ah_iobase + reg); } +/* + * Write to a register + */ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) { iowrite32(val, ah->ah_iobase + reg); } +#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY) +/* + * Check if a register write has been completed + */ +static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, + u32 val, bool is_set) +{ + int i; + u32 data; + + for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { + data = ath5k_hw_reg_read(ah, reg); + if (is_set && (data & flag)) + break; + else if ((data & flag) == val) + break; + udelay(15); + } + + return (i <= 0) ? -EAGAIN : 0; +} +#endif + +static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) +{ + u32 retval = 0, bit, i; + + for (i = 0; i < bits; i++) { + bit = (val >> i) & 1; + retval = (retval << 1) | bit; + } + + return retval; +} + #endif diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c new file mode 100644 index 00000000000..0eb2511fe14 --- /dev/null +++ b/drivers/net/wireless/ath5k/attach.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/*************************************\ +* Attach/Detach Functions and helpers * +\*************************************/ + +#include +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/** + * ath5k_hw_post - Power On Self Test helper function + * + * @ah: The &struct ath5k_hw + */ +static int ath5k_hw_post(struct ath5k_hw *ah) +{ + + int i, c; + u16 cur_reg; + u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)}; + u32 var_pattern; + u32 static_pattern[4] = { + 0x55555555, 0xaaaaaaaa, + 0x66666666, 0x99999999 + }; + u32 init_val; + u32 cur_val; + + for (c = 0; c < 2; c++) { + + cur_reg = regs[c]; + + /* Save previous value */ + init_val = ath5k_hw_reg_read(ah, cur_reg); + + for (i = 0; i < 256; i++) { + var_pattern = i << 16 | i; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + cur_val = ath5k_hw_reg_read(ah, cur_reg); + + if (cur_val != var_pattern) { + ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); + return -EAGAIN; + } + + /* Found on ndiswrapper dumps */ + var_pattern = 0x0039080f; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + } + + for (i = 0; i < 4; i++) { + var_pattern = static_pattern[i]; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + cur_val = ath5k_hw_reg_read(ah, cur_reg); + + if (cur_val != var_pattern) { + ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); + return -EAGAIN; + } + + /* Found on ndiswrapper dumps */ + var_pattern = 0x003b080f; + ath5k_hw_reg_write(ah, var_pattern, cur_reg); + } + + /* Restore previous value */ + ath5k_hw_reg_write(ah, init_val, cur_reg); + + } + + return 0; + +} + +/** + * ath5k_hw_attach - Check if hw is supported and init the needed structs + * + * @sc: The &struct ath5k_softc we got from the driver's attach function + * @mac_version: The mac version id (check out ath5k.h) based on pci id + * + * Check if the device is supported, perform a POST and initialize the needed + * structs. Returns -ENOMEM if we don't have memory for the needed structs, + * -ENODEV if the device is not supported or prints an error msg if something + * else went wrong. + */ +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]; + int ret; + u32 srev; + + /*If we passed the test malloc a ath5k_hw struct*/ + ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); + if (ah == NULL) { + ret = -ENOMEM; + ATH5K_ERR(sc, "out of memory\n"); + goto err; + } + + ah->ah_sc = sc; + ah->ah_iobase = sc->iobase; + + /* + * HW information + */ + ah->ah_op_mode = IEEE80211_IF_TYPE_STA; + ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; + ah->ah_turbo = false; + ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; + ah->ah_imr = 0; + ah->ah_atim_window = 0; + ah->ah_aifs = AR5K_TUNE_AIFS; + ah->ah_cw_min = AR5K_TUNE_CWMIN; + ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; + ah->ah_software_retry = false; + ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; + + /* + * Set the mac revision based on the pci id + */ + ah->ah_version = mac_version; + + /*Fill the ath5k_hw struct with the needed functions*/ + ret = ath5k_hw_init_desc_functions(ah); + if (ret) + goto err_free; + + /* Bring device out of sleep and reset it's units */ + ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); + if (ret) + goto err_free; + + /* Get MAC, PHY and RADIO revisions */ + srev = ath5k_hw_reg_read(ah, AR5K_SREV); + ah->ah_mac_srev = srev; + ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); + ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); + ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & + 0xffffffff; + ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_5GHZ); + + if (ah->ah_version == AR5K_AR5210) + ah->ah_radio_2ghz_revision = 0; + else + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); + + /* Return on unsuported chips (unsupported eeprom etc) */ + if ((srev >= AR5K_SREV_VER_AR5416) && + (srev < AR5K_SREV_VER_AR2425)) { + ATH5K_ERR(sc, "Device not yet supported.\n"); + ret = -ENODEV; + goto err_free; + } else if (srev == AR5K_SREV_VER_AR2425) { + ATH5K_WARN(sc, "Support for RF2425 is under development.\n"); + } + + /* Identify single chip solutions */ + if (((srev <= AR5K_SREV_VER_AR5414) && + (srev >= AR5K_SREV_VER_AR2413)) || + (srev == AR5K_SREV_VER_AR2425)) { + ah->ah_single_chip = true; + } else { + ah->ah_single_chip = false; + } + + /* Single chip radio */ + if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision) + ah->ah_radio_2ghz_revision = 0; + + /* Identify the radio chip*/ + if (ah->ah_version == AR5K_AR5210) { + ah->ah_radio = AR5K_RF5110; + /* + * Register returns 0x0/0x04 for radio revision + * so ath5k_hw_radio_revision doesn't parse the value + * correctly. For now we are based on mac's srev to + * identify RF2425 radio. + */ + } else if (srev == AR5K_SREV_VER_AR2425) { + ah->ah_radio = AR5K_RF2425; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { + ah->ah_radio = AR5K_RF5111; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { + ah->ah_radio = AR5K_RF5112; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { + ah->ah_radio = AR5K_RF2413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) { + ah->ah_radio = AR5K_RF5413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) { + /* AR5424 */ + if (srev >= AR5K_SREV_VER_AR5424) { + ah->ah_radio = AR5K_RF5413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; + /* AR2424 */ + } else { + ah->ah_radio = AR5K_RF2413; /* For testing */ + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; + } + } + ah->ah_phy = AR5K_PHY(0); + + /* + * Write PCI-E power save settings + */ + if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { + ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080); + ath5k_hw_reg_write(ah, 0x24924924, 0x4080); + ath5k_hw_reg_write(ah, 0x28000039, 0x4080); + ath5k_hw_reg_write(ah, 0x53160824, 0x4080); + ath5k_hw_reg_write(ah, 0xe5980579, 0x4080); + ath5k_hw_reg_write(ah, 0x001defff, 0x4080); + ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080); + ath5k_hw_reg_write(ah, 0xbe105554, 0x4080); + ath5k_hw_reg_write(ah, 0x000e3007, 0x4080); + ath5k_hw_reg_write(ah, 0x00000000, 0x4084); + } + + /* + * POST + */ + ret = ath5k_hw_post(ah); + if (ret) + goto err_free; + + /* Write AR5K_PCICFG_UNK on 2112B and later chips */ + if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B || + srev > AR5K_SREV_VER_AR2413) { + ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG); + } + + /* + * Get card capabilities, values, ... + */ + ret = ath5k_eeprom_init(ah); + if (ret) { + ATH5K_ERR(sc, "unable to init EEPROM\n"); + goto err_free; + } + + /* Get misc capabilities */ + ret = ath5k_hw_set_capabilities(ah); + if (ret) { + ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", + sc->pdev->device); + goto err_free; + } + + /* Get 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; + } + + 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); + ath5k_hw_set_opmode(ah); + + ath5k_hw_set_rfgain_opt(ah); + + return ah; +err_free: + kfree(ah); +err: + return ERR_PTR(ret); +} + +/** + * ath5k_hw_detach - Free the ath5k_hw struct + * + * @ah: The &struct ath5k_hw + */ +void ath5k_hw_detach(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); + + if (ah->ah_rf_banks != NULL) + kfree(ah->ah_rf_banks); + + /* assume interrupts are down */ + kfree(ah); +} diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index bcec74e839e..7989ab5c2bb 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -707,7 +707,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) * return false w/o doing anything. MAC's that do * support it will return true w/o doing anything. */ - ret = ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); if (ret < 0) goto err; if (ret > 0) @@ -1137,7 +1137,7 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ds = bf->desc; ds->ds_link = bf->daddr; /* link to self */ ds->ds_data = bf->skbaddr; - ath5k_hw_setup_rx_desc(ah, ds, + ah->ah_setup_rx_desc(ah, ds, skb_tailroom(skb), /* buffer size */ 0); @@ -1188,12 +1188,12 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) list_add_tail(&bf->list, &txq->q); sc->tx_stats[txq->qnum].len++; if (txq->link == NULL) /* is this first packet? */ - ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); + ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); else /* no, so only link it */ *txq->link = bf->daddr; txq->link = &ds->ds_link; - ath5k_hw_tx_start(ah, txq->qnum); + ath5k_hw_start_tx_dma(ah, txq->qnum); mmiowb(); spin_unlock_bh(&txq->lock); @@ -1393,7 +1393,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n", qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max); - ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi); + ret = ath5k_hw_set_tx_queueprops(ah, sc->bhalq, &qi); if (ret) { ATH5K_ERR(sc, "%s: unable to update parameters for beacon " "hardware queue!\n", __func__); @@ -1442,14 +1442,14 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) /* don't touch the hardware if marked invalid */ ath5k_hw_stop_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n", - ath5k_hw_get_tx_buf(ah, sc->bhalq)); + ath5k_hw_get_txdp(ah, sc->bhalq)); for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) { ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, " "link %p\n", sc->txqs[i].qnum, - ath5k_hw_get_tx_buf(ah, + ath5k_hw_get_txdp(ah, sc->txqs[i].qnum), sc->txqs[i].link); } @@ -1509,8 +1509,8 @@ ath5k_rx_start(struct ath5k_softc *sc) bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); spin_unlock_bh(&sc->rxbuflock); - ath5k_hw_put_rx_buf(ah, bf->daddr); - ath5k_hw_start_rx(ah); /* enable recv descriptors */ + ath5k_hw_set_rxdp(ah, bf->daddr); + ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ ath5k_mode_setup(sc); /* set filters, etc. */ ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ @@ -1527,7 +1527,7 @@ ath5k_rx_stop(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ + ath5k_hw_stop_rx_pcu(ah); /* disable PCU */ ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ @@ -1976,8 +1976,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* NB: hw still stops DMA, so proceed */ } - ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); - ath5k_hw_tx_start(ah, sc->bhalq); + ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); + ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", sc->bhalq, (unsigned long long)bf->daddr, bf->desc); @@ -2106,7 +2106,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - ath5k_hw_set_intr(ah, 0); + ath5k_hw_set_imr(ah, 0); sc->bmisscount = 0; sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); @@ -2132,7 +2132,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) } /* TODO else AP */ - ath5k_hw_set_intr(ah, sc->imask); + ath5k_hw_set_imr(ah, sc->imask); } @@ -2211,7 +2211,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) if (!test_bit(ATH_STAT_INVALID, sc->status)) { ath5k_led_off(sc); - ath5k_hw_set_intr(ah, 0); + ath5k_hw_set_imr(ah, 0); synchronize_irq(sc->pdev->irq); } ath5k_txq_cleanup(sc); @@ -2604,7 +2604,7 @@ ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); if (stop) { - ath5k_hw_set_intr(ah, 0); + ath5k_hw_set_imr(ah, 0); ath5k_txq_cleanup(sc); ath5k_rx_stop(sc); } diff --git a/drivers/net/wireless/ath5k/caps.c b/drivers/net/wireless/ath5k/caps.c new file mode 100644 index 00000000000..150f5ed204a --- /dev/null +++ b/drivers/net/wireless/ath5k/caps.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby + * + * Permission to use, copy, modify, and 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. + * + */ + +/**************\ +* Capabilities * +\**************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Fill the capabilities struct + * TODO: Merge this with EEPROM code when we are done with it + */ +int ath5k_hw_set_capabilities(struct ath5k_hw *ah) +{ + u16 ee_header; + + ATH5K_TRACE(ah->ah_sc); + /* Capabilities stored in the EEPROM */ + ee_header = ah->ah_capabilities.cap_eeprom.ee_header; + + if (ah->ah_version == AR5K_AR5210) { + /* + * Set radio capabilities + * (The AR5110 only supports the middle 5GHz band) + */ + ah->ah_capabilities.cap_range.range_5ghz_min = 5120; + ah->ah_capabilities.cap_range.range_5ghz_max = 5430; + ah->ah_capabilities.cap_range.range_2ghz_min = 0; + ah->ah_capabilities.cap_range.range_2ghz_max = 0; + + /* Set supported modes */ + __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode); + } else { + /* + * XXX The tranceiver supports frequencies from 4920 to 6100GHz + * XXX and from 2312 to 2732GHz. There are problems with the + * XXX current ieee80211 implementation because the IEEE + * XXX channel mapping does not support negative channel + * XXX numbers (2312MHz is channel -19). Of course, this + * XXX doesn't matter because these channels are out of range + * XXX but some regulation domains like MKK (Japan) will + * XXX support frequencies somewhere around 4.8GHz. + */ + + /* + * Set radio capabilities + */ + + if (AR5K_EEPROM_HDR_11A(ee_header)) { + /* 4920 */ + ah->ah_capabilities.cap_range.range_5ghz_min = 5005; + ah->ah_capabilities.cap_range.range_5ghz_max = 6100; + + /* Set supported modes */ + __set_bit(AR5K_MODE_11A, + ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A_TURBO, + ah->ah_capabilities.cap_mode); + if (ah->ah_version == AR5K_AR5212) + __set_bit(AR5K_MODE_11G_TURBO, + ah->ah_capabilities.cap_mode); + } + + /* Enable 802.11b if a 2GHz capable radio (2111/5112) is + * connected */ + if (AR5K_EEPROM_HDR_11B(ee_header) || + AR5K_EEPROM_HDR_11G(ee_header)) { + /* 2312 */ + ah->ah_capabilities.cap_range.range_2ghz_min = 2412; + ah->ah_capabilities.cap_range.range_2ghz_max = 2732; + + if (AR5K_EEPROM_HDR_11B(ee_header)) + __set_bit(AR5K_MODE_11B, + ah->ah_capabilities.cap_mode); + + if (AR5K_EEPROM_HDR_11G(ee_header)) + __set_bit(AR5K_MODE_11G, + ah->ah_capabilities.cap_mode); + } + } + + /* GPIO */ + ah->ah_gpio_npins = AR5K_NUM_GPIO; + + /* Set number of supported TX queues */ + if (ah->ah_version == AR5K_AR5210) + ah->ah_capabilities.cap_queues.q_tx_num = + AR5K_NUM_TX_QUEUES_NOQCU; + else + ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + + return 0; +} + +/* Main function used by the driver part to check caps */ +int ath5k_hw_get_capability(struct ath5k_hw *ah, + enum ath5k_capability_type cap_type, + u32 capability, u32 *result) +{ + ATH5K_TRACE(ah->ah_sc); + + switch (cap_type) { + case AR5K_CAP_NUM_TXQUEUES: + if (result) { + if (ah->ah_version == AR5K_AR5210) + *result = AR5K_NUM_TX_QUEUES_NOQCU; + else + *result = AR5K_NUM_TX_QUEUES; + goto yes; + } + case AR5K_CAP_VEOL: + goto yes; + case AR5K_CAP_COMPRESSION: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + case AR5K_CAP_BURST: + goto yes; + case AR5K_CAP_TPC: + goto yes; + case AR5K_CAP_BSSIDMASK: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + case AR5K_CAP_XR: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + default: + goto no; + } + +no: + return -EINVAL; +yes: + return 0; +} + +/* + * TODO: Following functions should be part of a new function + * set_capability + */ + +int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, + u16 assoc_id) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); + return 0; + } + + return -EIO; +} + +int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); + return 0; + } + + return -EIO; +} diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c index 6fa6c8e04ff..8f92d670f61 100644 --- a/drivers/net/wireless/ath5k/debug.c +++ b/drivers/net/wireless/ath5k/debug.c @@ -58,8 +58,8 @@ * THE POSSIBILITY OF SUCH DAMAGES. */ -#include "debug.h" #include "base.h" +#include "debug.h" static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); @@ -525,7 +525,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) return; printk(KERN_DEBUG "rx queue %x, link %p\n", - ath5k_hw_get_rx_buf(ah), sc->rxlink); + ath5k_hw_get_rxdp(ah), sc->rxlink); spin_lock_bh(&sc->rxbuflock); list_for_each_entry(bf, &sc->rxbuf, list) { diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c new file mode 100644 index 00000000000..d45b90a6e06 --- /dev/null +++ b/drivers/net/wireless/ath5k/desc.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Pavel Roskin + * + * Permission to use, copy, modify, and 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. + * + */ + +/******************************\ + Hardware Descriptor Functions +\******************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * TX Descriptors + */ + +/* + * Initialize the 2-word tx control descriptor on 5210/5211 + */ +static int +ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, + unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, + unsigned int key_index, unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, unsigned int rtscts_duration) +{ + u32 frame_type; + struct ath5k_hw_2w_tx_ctl *tx_ctl; + unsigned int frame_len; + + tx_ctl = &desc->ud.ds_tx5210.tx_ctl; + + /* + * Validate input + * - Zero retries don't make sense. + * - A zero rate will put the HW into a mode where it continously sends + * noise on the channel, so it is important to avoid this. + */ + if (unlikely(tx_tries0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero retries\n"); + WARN_ON(1); + return -EINVAL; + } + if (unlikely(tx_rate0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + /* Clear descriptor */ + memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); + + /* Setup control descriptor */ + + /* Verify and set frame length */ + + /* remove padding we might have added before */ + frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + + if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + + tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + if (type == AR5K_PKT_TYPE_BEACON) + pkt_len = roundup(pkt_len, 4); + + if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + + tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; + + /* + * Verify and set header length + * XXX: I only found that on 5210 code, does it work on 5211 ? + */ + if (ah->ah_version == AR5K_AR5210) { + if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) + return -EINVAL; + tx_ctl->tx_control_0 |= + AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); + } + + /*Diferences between 5210-5211*/ + if (ah->ah_version == AR5K_AR5210) { + switch (type) { + case AR5K_PKT_TYPE_BEACON: + case AR5K_PKT_TYPE_PROBE_RESP: + frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; + case AR5K_PKT_TYPE_PIFS: + frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; + default: + frame_type = type /*<< 2 ?*/; + } + + tx_ctl->tx_control_0 |= + AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | + AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + + } else { + tx_ctl->tx_control_0 |= + AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | + AR5K_REG_SM(antenna_mode, + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); + tx_ctl->tx_control_1 |= + AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); + } +#define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) { \ + tx_ctl->tx_control_##_c |= \ + AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ + } + + _TX_FLAGS(0, CLRDMASK); + _TX_FLAGS(0, VEOL); + _TX_FLAGS(0, INTREQ); + _TX_FLAGS(0, RTSENA); + _TX_FLAGS(1, NOACK); + +#undef _TX_FLAGS + + /* + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { + tx_ctl->tx_control_0 |= + AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_ctl->tx_control_1 |= + AR5K_REG_SM(key_index, + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + } + + /* + * RTS/CTS Duration [5210 ?] + */ + if ((ah->ah_version == AR5K_AR5210) && + (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) + tx_ctl->tx_control_1 |= rtscts_duration & + AR5K_2W_TX_DESC_CTL1_RTS_DURATION; + + return 0; +} + +/* + * Initialize the 4-word tx control descriptor on 5212 + */ +static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, + enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, + unsigned int tx_tries0, unsigned int key_index, + unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, + unsigned int rtscts_duration) +{ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + unsigned int frame_len; + + ATH5K_TRACE(ah->ah_sc); + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + + /* + * Validate input + * - Zero retries don't make sense. + * - A zero rate will put the HW into a mode where it continously sends + * noise on the channel, so it is important to avoid this. + */ + if (unlikely(tx_tries0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero retries\n"); + WARN_ON(1); + return -EINVAL; + } + if (unlikely(tx_rate0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + /* Clear descriptor */ + memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); + + /* Setup control descriptor */ + + /* Verify and set frame length */ + + /* remove padding we might have added before */ + frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + + if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + + tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + if (type == AR5K_PKT_TYPE_BEACON) + pkt_len = roundup(pkt_len, 4); + + if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + + tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + + tx_ctl->tx_control_0 |= + AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | + AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); + tx_ctl->tx_control_1 |= AR5K_REG_SM(type, + AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); + tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); + tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + +#define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) { \ + tx_ctl->tx_control_##_c |= \ + AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ + } + + _TX_FLAGS(0, CLRDMASK); + _TX_FLAGS(0, VEOL); + _TX_FLAGS(0, INTREQ); + _TX_FLAGS(0, RTSENA); + _TX_FLAGS(0, CTSENA); + _TX_FLAGS(1, NOACK); + +#undef _TX_FLAGS + + /* + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { + tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, + AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + } + + /* + * RTS/CTS + */ + if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { + if ((flags & AR5K_TXDESC_RTSENA) && + (flags & AR5K_TXDESC_CTSENA)) + return -EINVAL; + tx_ctl->tx_control_2 |= rtscts_duration & + AR5K_4W_TX_DESC_CTL2_RTS_DURATION; + tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); + } + + return 0; +} + +/* + * Initialize a 4-word multi rate retry tx control descriptor on 5212 + */ +static int +ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, + u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) +{ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + + /* + * Rates can be 0 as long as the retry count is 0 too. + * A zero rate and nonzero retry count will put the HW into a mode where + * it continously sends noise on the channel, so it is important to + * avoid this. + */ + if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || + (tx_rate2 == 0 && tx_tries2 != 0) || + (tx_rate3 == 0 && tx_tries3 != 0))) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + if (ah->ah_version == AR5K_AR5212) { + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + +#define _XTX_TRIES(_n) \ + if (tx_tries##_n) { \ + tx_ctl->tx_control_2 |= \ + AR5K_REG_SM(tx_tries##_n, \ + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ + tx_ctl->tx_control_3 |= \ + AR5K_REG_SM(tx_rate##_n, \ + AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ + } + + _XTX_TRIES(1); + _XTX_TRIES(2); + _XTX_TRIES(3); + +#undef _XTX_TRIES + + return 1; + } + + return 0; +} + +/* + * Proccess the tx status descriptor on 5210/5211 + */ +static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_tx_status *ts) +{ + struct ath5k_hw_2w_tx_ctl *tx_ctl; + struct ath5k_hw_tx_status *tx_status; + + ATH5K_TRACE(ah->ah_sc); + + tx_ctl = &desc->ud.ds_tx5210.tx_ctl; + tx_status = &desc->ud.ds_tx5210.tx_stat; + + /* No frame has been send or error */ + if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) + return -EINPROGRESS; + + /* + * Get descriptor status + */ + ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); + ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + /*TODO: ts->ts_virtcol + test*/ + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); + ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + ts->ts_antenna = 1; + ts->ts_status = 0; + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, + AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + + if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (tx_status->tx_status_0 & + AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + ts->ts_status |= AR5K_TXERR_XRETRY; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + ts->ts_status |= AR5K_TXERR_FIFO; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + ts->ts_status |= AR5K_TXERR_FILT; + } + + return 0; +} + +/* + * Proccess a tx status descriptor on 5212 + */ +static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_tx_status *ts) +{ + struct ath5k_hw_4w_tx_ctl *tx_ctl; + struct ath5k_hw_tx_status *tx_status; + + ATH5K_TRACE(ah->ah_sc); + + tx_ctl = &desc->ud.ds_tx5212.tx_ctl; + tx_status = &desc->ud.ds_tx5212.tx_stat; + + /* No frame has been send or error */ + if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) + return -EINPROGRESS; + + /* + * Get descriptor status + */ + ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); + ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); + ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + ts->ts_antenna = (tx_status->tx_status_1 & + AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; + ts->ts_status = 0; + + switch (AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { + case 0: + ts->ts_rate = tx_ctl->tx_control_3 & + AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + break; + case 1: + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); + ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); + break; + case 2: + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); + ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); + break; + case 3: + ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); + ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); + break; + } + + /* TX error */ + if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (tx_status->tx_status_0 & + AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + ts->ts_status |= AR5K_TXERR_XRETRY; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + ts->ts_status |= AR5K_TXERR_FIFO; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + ts->ts_status |= AR5K_TXERR_FILT; + } + + return 0; +} + +/* + * RX Descriptors + */ + +/* + * Initialize an rx control descriptor + */ +static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags) +{ + struct ath5k_hw_rx_ctl *rx_ctl; + + ATH5K_TRACE(ah->ah_sc); + rx_ctl = &desc->ud.ds_rx.rx_ctl; + + /* + * Clear the descriptor + * If we don't clean the status descriptor, + * while scanning we get too many results, + * most of them virtual, after some secs + * of scanning system hangs. M.F. + */ + memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); + + /* Setup descriptor */ + rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; + if (unlikely(rx_ctl->rx_control_1 != size)) + return -EINVAL; + + if (flags & AR5K_RXDESC_INTREQ) + rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; + + return 0; +} + +/* + * Proccess the rx status descriptor on 5210/5211 + */ +static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) +{ + struct ath5k_hw_rx_status *rx_status; + + rx_status = &desc->ud.ds_rx.u.rx_stat; + + /* No frame received / not ready */ + if (unlikely(!(rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_DONE))) + return -EINPROGRESS; + + /* + * Frame receive status + */ + rs->rs_datalen = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); + rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); + rs->rs_antenna = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA; + rs->rs_more = rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_MORE; + /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ + rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + rs->rs_status = 0; + rs->rs_phyerr = 0; + + /* + * Key table status + */ + if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); + else + rs->rs_keyix = AR5K_RXKEYIX_INVALID; + + /* + * Receive/descriptor errors + */ + if (!(rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; + + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) + rs->rs_status |= AR5K_RXERR_FIFO; + + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; + rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); + } + + if (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; + } + + return 0; +} + +/* + * Proccess the rx status descriptor on 5212 + */ +static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc, struct ath5k_rx_status *rs) +{ + struct ath5k_hw_rx_status *rx_status; + struct ath5k_hw_rx_error *rx_err; + + ATH5K_TRACE(ah->ah_sc); + rx_status = &desc->ud.ds_rx.u.rx_stat; + + /* Overlay on error */ + rx_err = &desc->ud.ds_rx.u.rx_err; + + /* No frame received / not ready */ + if (unlikely(!(rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_DONE))) + return -EINPROGRESS; + + /* + * Frame receive status + */ + rs->rs_datalen = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); + rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); + rs->rs_antenna = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA; + rs->rs_more = rx_status->rx_status_0 & + AR5K_5212_RX_DESC_STATUS0_MORE; + rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + rs->rs_status = 0; + rs->rs_phyerr = 0; + + /* + * Key table status + */ + if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); + else + rs->rs_keyix = AR5K_RXKEYIX_INVALID; + + /* + * Receive/descriptor errors + */ + if (!(rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_CRC; + + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + rs->rs_status |= AR5K_RXERR_PHY; + rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, + AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); + } + + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + rs->rs_status |= AR5K_RXERR_DECRYPT; + + if (rx_status->rx_status_1 & + AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + rs->rs_status |= AR5K_RXERR_MIC; + } + + return 0; +} + +/* + * Init function pointers inside ath5k_hw struct + */ +int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) +{ + + if (ah->ah_version != AR5K_AR5210 && + ah->ah_version != AR5K_AR5211 && + ah->ah_version != AR5K_AR5212) + return -ENOTSUPP; + + /* XXX: What is this magic value and where is it used ? */ + if (ah->ah_version == AR5K_AR5212) + ah->ah_magic = AR5K_EEPROM_MAGIC_5212; + else if (ah->ah_version == AR5K_AR5211) + ah->ah_magic = AR5K_EEPROM_MAGIC_5211; + + if (ah->ah_version == AR5K_AR5212) { + ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; + ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; + ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; + ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; + } else { + ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; + ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; + ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; + ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; + } + + if (ah->ah_version == AR5K_AR5212) + ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; + else if (ah->ah_version <= AR5K_AR5211) + ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/desc.h b/drivers/net/wireless/ath5k/desc.h new file mode 100644 index 00000000000..56158c804e3 --- /dev/null +++ b/drivers/net/wireless/ath5k/desc.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/* + * Internal RX/TX descriptor structures + * (rX: reserved fields possibily used by future versions of the ar5k chipset) + */ + +/* + * common hardware RX control descriptor + */ +struct ath5k_hw_rx_ctl { + u32 rx_control_0; /* RX control word 0 */ + u32 rx_control_1; /* RX control word 1 */ +} __packed; + +/* RX control word 0 field/sflags */ +#define AR5K_DESC_RX_CTL0 0x00000000 + +/* RX control word 1 fields/flags */ +#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff +#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 + +/* + * common hardware RX status descriptor + * 5210/11 and 5212 differ only in the flags defined below + */ +struct ath5k_hw_rx_status { + u32 rx_status_0; /* RX status word 0 */ + u32 rx_status_1; /* RX status word 1 */ +} __packed; + +/* 5210/5211 */ +/* RX status word 0 fields/flags */ +#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff +#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 + +/* RX status word 1 fields/flags */ +#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 +#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 +#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 +#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 +#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 +#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 + +/* 5212 */ +/* RX status word 0 fields/flags */ +#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff +#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 +#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 + +/* RX status word 1 fields/flags */ +#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 +#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 +#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 +#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 +#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 +#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 +#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 + +/* + * common hardware RX error descriptor + */ +struct ath5k_hw_rx_error { + u32 rx_error_0; /* RX status word 0 */ + u32 rx_error_1; /* RX status word 1 */ +} __packed; + +/* RX error word 0 fields/flags */ +#define AR5K_RX_DESC_ERROR0 0x00000000 + +/* RX error word 1 fields/flags */ +#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 +#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 + +/* PHY Error codes */ +#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 +#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 +#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 +#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 +#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 +#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 +#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 +#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 + +/* + * 5210/5211 hardware 2-word TX control descriptor + */ +struct ath5k_hw_2w_tx_ctl { + u32 tx_control_0; /* TX control word 0 */ + u32 tx_control_1; /* TX control word 1 */ +} __packed; + +/* TX control word 0 fields/flags */ +#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff +#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/ +#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 +#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 +#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 +#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ +#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26 +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 + +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT \ + (ah->ah_version == AR5K_AR5210 ? \ + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) + +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 +#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 +#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 + +/* TX control word 1 fields/flags */ +#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff +#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000 +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000 + +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX \ + (ah->ah_version == AR5K_AR5210 ? \ + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) + +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 +#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20 +#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/ + +/* Frame types */ +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 + +/* + * 5212 hardware 4-word TX control descriptor + */ +struct ath5k_hw_4w_tx_ctl { + u32 tx_control_0; /* TX control word 0 */ + +#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 +#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 +#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 +#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 +#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 +#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 +#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 + + u32 tx_control_1; /* TX control word 1 */ + +#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff +#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 +#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 + + u32 tx_control_2; /* TX control word 2 */ + +#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff +#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 + + u32 tx_control_3; /* TX control word 3 */ + +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 +} __packed; + +/* + * Common TX status descriptor + */ +struct ath5k_hw_tx_status { + u32 tx_status_0; /* TX status word 0 */ + u32 tx_status_1; /* TX status word 1 */ +} __packed; + +/* TX status word 0 fields/flags */ +#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 +#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 +#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 +#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 +/*??? +#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 +*/ +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 +/*??? +#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 +*/ +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 +#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 +#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 + +/* TX status word 1 fields/flags */ +#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 +#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe +#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 +#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 +#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21 +#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000 +#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000 + +/* + * 5210/5211 hardware TX descriptor + */ +struct ath5k_hw_5210_tx_desc { + struct ath5k_hw_2w_tx_ctl tx_ctl; + struct ath5k_hw_tx_status tx_stat; +} __packed; + +/* + * 5212 hardware TX descriptor + */ +struct ath5k_hw_5212_tx_desc { + struct ath5k_hw_4w_tx_ctl tx_ctl; + struct ath5k_hw_tx_status tx_stat; +} __packed; + +/* + * common hardware RX descriptor + */ +struct ath5k_hw_all_rx_desc { + struct ath5k_hw_rx_ctl rx_ctl; + union { + struct ath5k_hw_rx_status rx_stat; + struct ath5k_hw_rx_error rx_err; + } u; +} __packed; + +/* + * Atheros hardware descriptor + * This is read and written to by the hardware + */ +struct ath5k_desc { + u32 ds_link; /* physical address of the next descriptor */ + u32 ds_data; /* physical address of data buffer (skb) */ + + union { + struct ath5k_hw_5210_tx_desc ds_tx5210; + struct ath5k_hw_5212_tx_desc ds_tx5212; + struct ath5k_hw_all_rx_desc ds_rx; + } ud; +} __packed; + +#define AR5K_RXDESC_INTREQ 0x0020 + +#define AR5K_TXDESC_CLRDMASK 0x0001 +#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/ +#define AR5K_TXDESC_RTSENA 0x0004 +#define AR5K_TXDESC_CTSENA 0x0008 +#define AR5K_TXDESC_INTREQ 0x0010 +#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ + diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c new file mode 100644 index 00000000000..a28090be960 --- /dev/null +++ b/drivers/net/wireless/ath5k/dma.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/*************************************\ +* DMA and interrupt masking functions * +\*************************************/ + +/* + * dma.c - DMA and interrupt masking functions + * + * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and + * handle queue setup for 5210 chipset (rest are handled on qcu.c). + * Also we setup interrupt mask register (IMR) and read the various iterrupt + * status registers (ISR). + * + * TODO: Handle SISR on 5211+ and introduce a function to return the queue + * number that resulted the interrupt. + */ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/*********\ +* Receive * +\*********/ + +/** + * ath5k_hw_start_rx_dma - Start DMA receive + * + * @ah: The &struct ath5k_hw + */ +void ath5k_hw_start_rx_dma(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); +} + +/** + * ath5k_hw_stop_rx_dma - Stop DMA receive + * + * @ah: The &struct ath5k_hw + */ +int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) +{ + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); + + /* + * It may take some time to disable the DMA receive unit + */ + for (i = 2000; i > 0 && + (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; + i--) + udelay(10); + + return i ? 0 : -EBUSY; +} + +/** + * ath5k_hw_get_rxdp - Get RX Descriptor's address + * + * @ah: The &struct ath5k_hw + * + * XXX: Is RXDP read and clear ? + */ +u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) +{ + return ath5k_hw_reg_read(ah, AR5K_RXDP); +} + +/** + * ath5k_hw_set_rxdp - Set RX Descriptor's address + * + * @ah: The &struct ath5k_hw + * @phys_addr: RX descriptor address + * + * XXX: Should we check if rx is enabled before setting rxdp ? + */ +void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) +{ + ATH5K_TRACE(ah->ah_sc); + + ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); +} + + +/**********\ +* Transmit * +\**********/ + +/** + * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Start DMA transmit for a specific queue and since 5210 doesn't have + * QCU/DCU, set up queue parameters for 5210 here based on queue type (one + * queue for normal data and one queue for beacons). For queue setup + * on newer chips check out qcu.c. Returns -EINVAL if queue number is out + * of range or if queue is already disabled. + * + * NOTE: Must be called after setting up tx control descriptor for that + * queue (see below). + */ +int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) +{ + u32 tx_queue; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + if (ah->ah_version == AR5K_AR5210) { + tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); + + /* + * Set the queue by type on 5210 + */ + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; + break; + case AR5K_TX_QUEUE_BEACON: + tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, + AR5K_BSR); + break; + case AR5K_TX_QUEUE_CAB: + tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V | + AR5K_BCR_BDMAE, AR5K_BSR); + break; + default: + return -EINVAL; + } + /* Start queue */ + ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); + } else { + /* Return if queue is disabled */ + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) + return -EIO; + + /* Start queue */ + AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); + } + + return 0; +} + +/** + * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Stop DMA transmit on a specific hw queue and drain queue so we don't + * have any pending frames. Returns -EBUSY if we still have pending frames, + * -EINVAL if queue number is out of range. + * + * TODO: Test queue drain code + */ +int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) +{ + unsigned int i = 100; + u32 tx_queue, pending; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + if (ah->ah_version == AR5K_AR5210) { + tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); + + /* + * Set by queue type + */ + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + /* XXX Fix me... */ + tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, 0, AR5K_BSR); + break; + default: + return -EINVAL; + } + + /* Stop queue */ + ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); + } else { + /* + * Schedule TX disable and wait until queue is empty + */ + AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); + + /*Check for pending frames*/ + do { + pending = ath5k_hw_reg_read(ah, + AR5K_QUEUE_STATUS(queue)) & + AR5K_QCU_STS_FRMPENDCNT; + udelay(100); + } while (--i && pending); + + /* Clear register */ + ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); + if (pending) + return -EBUSY; + } + + /* TODO: Check for success else return error */ + return 0; +} + +/** + * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Get TX descriptor's address for a specific queue. For 5210 we ignore + * the queue number and use tx queue type since we only have 2 queues. + * We use TXDP0 for normal data queue and TXDP1 for beacon queue. + * For newer chips with QCU/DCU we just read the corresponding TXDP register. + * + * XXX: Is TXDP read and clear ? + */ +u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) +{ + u16 tx_reg; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* + * Get the transmit queue descriptor pointer from the selected queue + */ + /*5210 doesn't have QCU*/ + if (ah->ah_version == AR5K_AR5210) { + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_reg = AR5K_NOQCU_TXDP0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + tx_reg = AR5K_NOQCU_TXDP1; + break; + default: + return 0xffffffff; + } + } else { + tx_reg = AR5K_QUEUE_TXDP(queue); + } + + return ath5k_hw_reg_read(ah, tx_reg); +} + +/** + * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue + * + * @ah: The &struct ath5k_hw + * @queue: The hw queue number + * + * Set TX descriptor's address for a specific queue. For 5210 we ignore + * the queue number and we use tx queue type since we only have 2 queues + * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue. + * For newer chips with QCU/DCU we just set the corresponding TXDP register. + * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still + * active. + */ +int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) +{ + u16 tx_reg; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* + * Set the transmit queue descriptor pointer register by type + * on 5210 + */ + if (ah->ah_version == AR5K_AR5210) { + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_reg = AR5K_NOQCU_TXDP0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + tx_reg = AR5K_NOQCU_TXDP1; + break; + default: + return -EINVAL; + } + } else { + /* + * Set the transmit queue descriptor pointer for + * the selected queue on QCU for 5211+ + * (this won't work if the queue is still active) + */ + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) + return -EIO; + + tx_reg = AR5K_QUEUE_TXDP(queue); + } + + /* Set descriptor pointer */ + ath5k_hw_reg_write(ah, phys_addr, tx_reg); + + return 0; +} + +/** + * ath5k_hw_update_tx_triglevel - Update tx trigger level + * + * @ah: The &struct ath5k_hw + * @increase: Flag to force increase of trigger level + * + * This function increases/decreases the tx trigger level for the tx fifo + * buffer (aka FIFO threshold) that is used to indicate when PCU flushes + * the buffer and transmits it's data. Lowering this results sending small + * frames more quickly but can lead to tx underruns, raising it a lot can + * result other problems (i think bmiss is related). Right now we start with + * the lowest possible (64Bytes) and if we get tx underrun we increase it using + * the increase flag. Returns -EIO if we have have reached maximum/minimum. + * + * XXX: Link this with tx DMA size ? + * XXX: Use it to save interrupts ? + * TODO: Needs testing, i think it's related to bmiss... + */ +int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) +{ + u32 trigger_level, imr; + int ret = -EIO; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Disable interrupts by setting the mask + */ + imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); + + trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), + AR5K_TXCFG_TXFULL); + + if (!increase) { + if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) + goto done; + } else + trigger_level += + ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); + + /* + * Update trigger level on success + */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); + else + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_TXFULL, trigger_level); + + ret = 0; + +done: + /* + * Restore interrupt mask + */ + ath5k_hw_set_imr(ah, imr); + + return ret; +} + +/*******************\ +* Interrupt masking * +\*******************/ + +/** + * ath5k_hw_is_intr_pending - Check if we have pending interrupts + * + * @ah: The &struct ath5k_hw + * + * Check if we have pending interrupts to process. Returns 1 if we + * have pending interrupts and 0 if we haven't. + */ +bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_reg_read(ah, AR5K_INTPEND); +} + +/** + * ath5k_hw_get_isr - Get interrupt status + * + * @ah: The @struct ath5k_hw + * @interrupt_mask: Driver's interrupt mask used to filter out + * interrupts in sw. + * + * This function is used inside our interrupt handler to determine the reason + * for the interrupt by reading Primary Interrupt Status Register. Returns an + * abstract interrupt status mask which is mostly ISR with some uncommon bits + * being mapped on some standard non hw-specific positions + * (check out &ath5k_int). + * + * 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) +{ + u32 data; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Read interrupt status from the Interrupt Status register + * on 5210 + */ + if (ah->ah_version == AR5K_AR5210) { + data = ath5k_hw_reg_read(ah, AR5K_ISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } + } else { + /* + * Read interrupt status from the Read-And-Clear + * shadow register. + * Note: PISR/SISR Not available on 5210 + */ + data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + } + + /* + * Get abstract interrupt mask (driver-compatible) + */ + *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) { + /*HIU = Host Interface Unit (PCI etc)*/ + if (unlikely(data & (AR5K_ISR_HIUERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /*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 + + /* + * In case we didn't handle anything, + * print the register value. + */ + if (unlikely(*interrupt_mask == 0 && net_ratelimit())) + ATH5K_PRINTF("0x%08x\n", data); + + return 0; +} + +/** + * ath5k_hw_set_imr - Set interrupt mask + * + * @ah: The &struct ath5k_hw + * @new_mask: The new interrupt mask to be set + * + * Set the interrupt mask in hw to save interrupts. We do that by mapping + * ath5k_int bits to hw-specific bits to remove abstraction and writing + * Interrupt Mask Register. + */ +enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) +{ + enum ath5k_int old_mask, int_mask; + + /* + * Disable card interrupts to prevent any race conditions + * (they will be re-enabled afterwards). + */ + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + + old_mask = ah->ah_imr; + + /* + * Add additional, chipset-dependent interrupt mask flags + * and write them to the IMR (interrupt mask register). + */ + 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) { + 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); + } + } + + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + + /* 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); + + return old_mask; +} + diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c new file mode 100644 index 00000000000..a883839b6a9 --- /dev/null +++ b/drivers/net/wireless/ath5k/eeprom.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/*************************************\ +* EEPROM access functions and helpers * +\*************************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Read from eeprom + */ +static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) +{ + u32 status, timeout; + + ATH5K_TRACE(ah->ah_sc); + /* + * Initialize EEPROM access + */ + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); + (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); + } else { + ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); + AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, + AR5K_EEPROM_CMD_READ); + } + + for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { + status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); + if (status & AR5K_EEPROM_STAT_RDDONE) { + if (status & AR5K_EEPROM_STAT_RDERR) + return -EIO; + *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & + 0xffff); + return 0; + } + udelay(15); + } + + return -ETIMEDOUT; +} + +/* + * Translate binary channel representation in EEPROM to frequency + */ +static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, + unsigned int mode) +{ + u16 val; + + if (bin == AR5K_EEPROM_CHANNEL_DIS) + return bin; + + if (mode == AR5K_EEPROM_MODE_11A) { + if (ah->ah_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) + val = bin + 2300; + else + val = bin + 2400; + } + + return val; +} + +/* + * Read antenna infos from eeprom + */ +static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, + unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 o = *offset; + u16 val; + int ret, i = 0; + + AR5K_EEPROM_READ(o++, val); + ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; + ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; + ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + /* Get antenna modes */ + ah->ah_antenna[mode][0] = + (ee->ee_ant_control[mode][0] << 4) | 0x1; + ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = + ee->ee_ant_control[mode][1] | + (ee->ee_ant_control[mode][2] << 6) | + (ee->ee_ant_control[mode][3] << 12) | + (ee->ee_ant_control[mode][4] << 18) | + (ee->ee_ant_control[mode][5] << 24); + ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = + ee->ee_ant_control[mode][6] | + (ee->ee_ant_control[mode][7] << 6) | + (ee->ee_ant_control[mode][8] << 12) | + (ee->ee_ant_control[mode][9] << 18) | + (ee->ee_ant_control[mode][10] << 24); + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Read supported modes from eeprom + */ +static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, + unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 o = *offset; + u16 val; + int ret; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; + ee->ee_thr_62[mode] = val & 0xff; + + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; + ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; + + if ((val & 0xff) & 0x80) + ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); + else + ee->ee_noise_floor_thr[mode] = val & 0xff; + + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_noise_floor_thr[mode] = + mode == AR5K_EEPROM_MODE_11A ? -54 : -1; + + AR5K_EEPROM_READ(o++, val); + ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; + ee->ee_x_gain[mode] = (val >> 1) & 0xf; + ee->ee_xpd[mode] = val & 0x1; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) + ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(o++, val); + ee->ee_false_detect[mode] = (val >> 6) & 0x7f; + + if (mode == AR5K_EEPROM_MODE_11A) + ee->ee_xr_power[mode] = val & 0x3f; + else { + ee->ee_ob[mode][0] = val & 0x7; + ee->ee_db[mode][0] = (val >> 3) & 0x7; + } + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { + ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; + ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; + } else { + ee->ee_i_gain[mode] = (val >> 13) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_gain[mode] |= (val << 3) & 0x38; + + if (mode == AR5K_EEPROM_MODE_11G) + ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && + mode == AR5K_EEPROM_MODE_11A) { + 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_6 && + mode == AR5K_EEPROM_MODE_11G) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Initialize eeprom & capabilities structs + */ +int ath5k_eeprom_init(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + unsigned int mode, i; + int ret; + u32 offset; + 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; + } + + /* + * Get conformance test limit values + */ + offset = AR5K_EEPROM_CTL(ah->ah_ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(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; + } + + /* + * Get values for 802.11a (5GHz) + */ + mode = AR5K_EEPROM_MODE_11A; + + ee->ee_turbo_max_power[mode] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + 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; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + } + + /* + * Get values for 802.11b (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11B; + offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + 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; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + 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); + + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][2] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + /* + * Get values for 802.11g (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11G; + offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + 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; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + 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); + + AR5K_EEPROM_READ(offset++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][2] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(offset++, 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(offset++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + } + + /* + * Read 5GHz EEPROM channels + */ + + return 0; +} + +/* + * Read the MAC address from eeprom + */ +int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + u8 mac_d[ETH_ALEN]; + u32 total, offset; + u16 data; + int octet, ret; + + memset(mac, 0, ETH_ALEN); + memset(mac_d, 0, ETH_ALEN); + + ret = ath5k_hw_eeprom_read(ah, 0x20, &data); + if (ret) + return ret; + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { + ret = ath5k_hw_eeprom_read(ah, offset, &data); + if (ret) + return ret; + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + memcpy(mac, mac_d, ETH_ALEN); + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h new file mode 100644 index 00000000000..a468ecfbb18 --- /dev/null +++ b/drivers/net/wireless/ath5k/eeprom.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/* + * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) + */ +#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ +#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ +#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ +#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_INFO_BASE 0x00c0 /* EEPROM header */ +#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) +#define AR5K_EEPROM_INFO_CKSUM 0xffff +#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) + +#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ +#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ +#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_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_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_MODE_11A 0 +#define AR5K_EEPROM_MODE_11B 1 +#define AR5K_EEPROM_MODE_11G 2 + +#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ +#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) +#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) +#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) +#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_RFKILL_GPIO_SEL 0x0000001c +#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 +#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 +#define AR5K_EEPROM_RFKILL_POLARITY_S 1 + +/* Newer EEPROMs are using a different offset */ +#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ + (((_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)) + +/* 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 */ + +/* [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) + + +/* Some EEPROM defines */ +#define AR5K_EEPROM_EEP_SCALE 100 +#define AR5K_EEPROM_EEP_DELTA 10 +#define AR5K_EEPROM_N_MODES 3 +#define AR5K_EEPROM_N_5GHZ_CHAN 10 +#define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_TEST_FREQ 8 +#define AR5K_EEPROM_N_EDGES 8 +#define AR5K_EEPROM_N_INTERCEPTS 11 +#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) +#define AR5K_EEPROM_PCDAC_M 0x3f +#define AR5K_EEPROM_PCDAC_START 1 +#define AR5K_EEPROM_PCDAC_STOP 63 +#define AR5K_EEPROM_PCDAC_STEP 1 +#define AR5K_EEPROM_NON_EDGE_M 0x40 +#define AR5K_EEPROM_CHANNEL_POWER 8 +#define AR5K_EEPROM_N_OBDB 4 +#define AR5K_EEPROM_OBDB_DIS 0xffff +#define AR5K_EEPROM_CHANNEL_DIS 0xff +#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) +#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) +#define AR5K_EEPROM_MAX_CTLS 32 +#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_INTERCEPT_10_2GHZ 35 +#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 +#define AR5K_EEPROM_POWER_M 0x3f +#define AR5K_EEPROM_POWER_MIN 0 +#define AR5K_EEPROM_POWER_MAX 3150 +#define AR5K_EEPROM_POWER_STEP 50 +#define AR5K_EEPROM_POWER_TABLE_SIZE 64 +#define AR5K_EEPROM_N_POWER_LOC_11B 4 +#define AR5K_EEPROM_N_POWER_LOC_11G 6 +#define AR5K_EEPROM_I_GAIN 10 +#define AR5K_EEPROM_CCK_OFDM_DELTA 15 +#define AR5K_EEPROM_N_IQ_CAL 2 + +#define AR5K_EEPROM_READ(_o, _v) do { \ + ret = ath5k_hw_eeprom_read(ah, (_o), &(_v)); \ + if (ret) \ + return ret; \ +} while (0) + +#define AR5K_EEPROM_READ_HDR(_o, _v) \ + AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ + +/* Struct to hold EEPROM calibration data */ +struct ath5k_eeprom_info { + u16 ee_magic; + u16 ee_protect; + u16 ee_regdomain; + u16 ee_version; + u16 ee_header; + u16 ee_ant_gain; + u16 ee_misc0; + u16 ee_misc1; + u16 ee_cck_ofdm_gain_delta; + u16 ee_cck_ofdm_power_delta; + u16 ee_scaled_cck_delta; + + /* Used for tx thermal adjustment (eeprom_init, rfregs) */ + u16 ee_tx_clip; + u16 ee_pwd_84; + u16 ee_pwd_90; + u16 ee_gain_select; + + /* RF Calibration settings (reset, rfregs) */ + u16 ee_i_cal[AR5K_EEPROM_N_MODES]; + u16 ee_q_cal[AR5K_EEPROM_N_MODES]; + u16 ee_fixed_bias[AR5K_EEPROM_N_MODES]; + 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_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]; + u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; + u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; + u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; + u16 ee_thr_62[AR5K_EEPROM_N_MODES]; + u16 ee_xlna_gain[AR5K_EEPROM_N_MODES]; + u16 ee_xpd[AR5K_EEPROM_N_MODES]; + 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]; + + /* Unused */ + 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*/ + + /* Conformance test limits (Unused) */ + u16 ee_ctls; + u16 ee_ctl[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]; +}; diff --git a/drivers/net/wireless/ath5k/gpio.c b/drivers/net/wireless/ath5k/gpio.c new file mode 100644 index 00000000000..b77205adc18 --- /dev/null +++ b/drivers/net/wireless/ath5k/gpio.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/****************\ + GPIO Functions +\****************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Set led state + */ +void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) +{ + u32 led; + /*5210 has different led mode handling*/ + u32 led_5210; + + ATH5K_TRACE(ah->ah_sc); + + /*Reset led status*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); + + /* + * Some blinking values, define at your wish + */ + switch (state) { + case AR5K_LED_SCAN: + case AR5K_LED_AUTH: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; + led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; + break; + + case AR5K_LED_INIT: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; + led_5210 = AR5K_PCICFG_LED_PEND; + break; + + case AR5K_LED_ASSOC: + case AR5K_LED_RUN: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; + led_5210 = AR5K_PCICFG_LED_ASSOC; + break; + + default: + led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; + led_5210 = AR5K_PCICFG_LED_PEND; + break; + } + + /*Write new status to the register*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); +} + +/* + * Set GPIO inputs + */ +int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + ath5k_hw_reg_write(ah, + (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) + | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); + + return 0; +} + +/* + * Set GPIO outputs + */ +int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + ath5k_hw_reg_write(ah, + (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) + | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); + + return 0; +} + +/* + * Get GPIO state + */ +u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return 0xffffffff; + + /* GPIO input magic */ + return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & + 0x1; +} + +/* + * Set GPIO state + */ +int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) +{ + u32 data; + ATH5K_TRACE(ah->ah_sc); + + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + /* GPIO output magic */ + data = ath5k_hw_reg_read(ah, AR5K_GPIODO); + + data &= ~(1 << gpio); + data |= (val & 1) << gpio; + + ath5k_hw_reg_write(ah, data, AR5K_GPIODO); + + return 0; +} + +/* + * Initialize the GPIO interrupt (RFKill switch) + */ +void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, + u32 interrupt_level) +{ + u32 data; + + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return; + + /* + * Set the GPIO interrupt + */ + data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & + ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | + AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | + (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); + + ath5k_hw_reg_write(ah, interrupt_level ? data : + (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); + + ah->ah_imr |= AR5K_IMR_GPIO; + + /* Enable GPIO interrupts */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); +} + diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c deleted file mode 100644 index b987aa1e0f7..00000000000 --- a/drivers/net/wireless/ath5k/hw.c +++ /dev/null @@ -1,4492 +0,0 @@ -/* - * Copyright (c) 2004-2007 Reyk Floeter - * Copyright (c) 2006-2007 Nick Kossifidis - * Copyright (c) 2007 Matthew W. S. Bell - * Copyright (c) 2007 Luis Rodriguez - * Copyright (c) 2007 Pavel Roskin - * Copyright (c) 2007 Jiri Slaby - * - * Permission to use, copy, modify, and 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. - * - */ - -/* - * HW related functions for Atheros Wireless LAN devices. - */ - -#include -#include - -#include "reg.h" -#include "base.h" -#include "debug.h" - -/* Prototypes */ -static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); -static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); -static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int); -static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int); -static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_tx_status *); -static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int); -static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_tx_status *); -static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_rx_status *); -static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *, struct ath5k_desc *, - struct ath5k_rx_status *); -static int ath5k_hw_get_capabilities(struct ath5k_hw *); - -static int ath5k_eeprom_init(struct ath5k_hw *); -static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *); - -static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16); -static int ath5k_hw_disable_pspoll(struct ath5k_hw *); - -/* - * Enable to overwrite the country code (use "00" for debug) - */ -#if 0 -#define COUNTRYCODE "00" -#endif - -/*******************\ - General Functions -\*******************/ - -/* - * Functions used internaly - */ - -static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) -{ - return turbo ? (usec * 80) : (usec * 40); -} - -static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) -{ - return turbo ? (clock / 80) : (clock / 40); -} - -/* - * Check if a register write has been completed - */ -int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, - bool is_set) -{ - int i; - u32 data; - - for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { - data = ath5k_hw_reg_read(ah, reg); - if (is_set && (data & flag)) - break; - else if ((data & flag) == val) - break; - udelay(15); - } - - return (i <= 0) ? -EAGAIN : 0; -} - - -/***************************************\ - Attach/Detach Functions -\***************************************/ - -/* - * Power On Self Test helper function - */ -static int ath5k_hw_post(struct ath5k_hw *ah) -{ - - int i, c; - u16 cur_reg; - u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)}; - u32 var_pattern; - u32 static_pattern[4] = { - 0x55555555, 0xaaaaaaaa, - 0x66666666, 0x99999999 - }; - u32 init_val; - u32 cur_val; - - for (c = 0; c < 2; c++) { - - cur_reg = regs[c]; - - /* Save previous value */ - init_val = ath5k_hw_reg_read(ah, cur_reg); - - for (i = 0; i < 256; i++) { - var_pattern = i << 16 | i; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - cur_val = ath5k_hw_reg_read(ah, cur_reg); - - if (cur_val != var_pattern) { - ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); - return -EAGAIN; - } - - /* Found on ndiswrapper dumps */ - var_pattern = 0x0039080f; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - } - - for (i = 0; i < 4; i++) { - var_pattern = static_pattern[i]; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - cur_val = ath5k_hw_reg_read(ah, cur_reg); - - if (cur_val != var_pattern) { - ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); - return -EAGAIN; - } - - /* Found on ndiswrapper dumps */ - var_pattern = 0x003b080f; - ath5k_hw_reg_write(ah, var_pattern, cur_reg); - } - - /* Restore previous value */ - ath5k_hw_reg_write(ah, init_val, cur_reg); - - } - - return 0; - -} - -/* - * Check if the device is supported and initialize the needed structs - */ -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]; - int ret; - u32 srev; - - /*If we passed the test malloc a ath5k_hw struct*/ - ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); - if (ah == NULL) { - ret = -ENOMEM; - ATH5K_ERR(sc, "out of memory\n"); - goto err; - } - - ah->ah_sc = sc; - ah->ah_iobase = sc->iobase; - - /* - * HW information - */ - - ah->ah_op_mode = IEEE80211_IF_TYPE_STA; - ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; - ah->ah_turbo = false; - ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; - ah->ah_imr = 0; - ah->ah_atim_window = 0; - ah->ah_aifs = AR5K_TUNE_AIFS; - ah->ah_cw_min = AR5K_TUNE_CWMIN; - ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; - ah->ah_software_retry = false; - ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; - - /* - * Set the mac revision based on the pci id - */ - ah->ah_version = mac_version; - - /*Fill the ath5k_hw struct with the needed functions*/ - if (ah->ah_version == AR5K_AR5212) - ah->ah_magic = AR5K_EEPROM_MAGIC_5212; - else if (ah->ah_version == AR5K_AR5211) - ah->ah_magic = AR5K_EEPROM_MAGIC_5211; - - if (ah->ah_version == AR5K_AR5212) { - ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; - ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; - ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; - } else { - ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; - ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; - ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; - } - - if (ah->ah_version == AR5K_AR5212) - ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; - else if (ah->ah_version <= AR5K_AR5211) - ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; - - /* Bring device out of sleep and reset it's units */ - ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true); - if (ret) - goto err_free; - - /* Get MAC, PHY and RADIO revisions */ - srev = ath5k_hw_reg_read(ah, AR5K_SREV); - ah->ah_mac_srev = srev; - ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); - ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); - ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & - 0xffffffff; - ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_5GHZ); - - if (ah->ah_version == AR5K_AR5210) - ah->ah_radio_2ghz_revision = 0; - else - ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_2GHZ); - - /* Return on unsuported chips (unsupported eeprom etc) */ - if ((srev >= AR5K_SREV_VER_AR5416) && - (srev < AR5K_SREV_VER_AR2425)) { - ATH5K_ERR(sc, "Device not yet supported.\n"); - ret = -ENODEV; - goto err_free; - } else if (srev == AR5K_SREV_VER_AR2425) { - ATH5K_WARN(sc, "Support for RF2425 is under development.\n"); - } - - /* Identify single chip solutions */ - if (((srev <= AR5K_SREV_VER_AR5414) && - (srev >= AR5K_SREV_VER_AR2413)) || - (srev == AR5K_SREV_VER_AR2425)) { - ah->ah_single_chip = true; - } else { - ah->ah_single_chip = false; - } - - /* Single chip radio */ - if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision) - ah->ah_radio_2ghz_revision = 0; - - /* Identify the radio chip*/ - if (ah->ah_version == AR5K_AR5210) { - ah->ah_radio = AR5K_RF5110; - /* - * Register returns 0x0/0x04 for radio revision - * so ath5k_hw_radio_revision doesn't parse the value - * correctly. For now we are based on mac's srev to - * identify RF2425 radio. - */ - } else if (srev == AR5K_SREV_VER_AR2425) { - ah->ah_radio = AR5K_RF2425; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { - ah->ah_radio = AR5K_RF5111; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { - ah->ah_radio = AR5K_RF5112; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { - ah->ah_radio = AR5K_RF2413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) { - ah->ah_radio = AR5K_RF5413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) { - /* AR5424 */ - if (srev >= AR5K_SREV_VER_AR5424) { - ah->ah_radio = AR5K_RF5413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; - /* AR2424 */ - } else { - ah->ah_radio = AR5K_RF2413; /* For testing */ - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; - } - } - ah->ah_phy = AR5K_PHY(0); - - /* - * Write PCI-E power save settings - */ - if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { - ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080); - ath5k_hw_reg_write(ah, 0x24924924, 0x4080); - ath5k_hw_reg_write(ah, 0x28000039, 0x4080); - ath5k_hw_reg_write(ah, 0x53160824, 0x4080); - ath5k_hw_reg_write(ah, 0xe5980579, 0x4080); - ath5k_hw_reg_write(ah, 0x001defff, 0x4080); - ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080); - ath5k_hw_reg_write(ah, 0xbe105554, 0x4080); - ath5k_hw_reg_write(ah, 0x000e3007, 0x4080); - ath5k_hw_reg_write(ah, 0x00000000, 0x4084); - } - - /* - * POST - */ - ret = ath5k_hw_post(ah); - if (ret) - goto err_free; - - /* Write AR5K_PCICFG_UNK on 2112B and later chips */ - if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B || - srev > AR5K_SREV_VER_AR2413) { - ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG); - } - - /* - * Get card capabilities, values, ... - */ - ret = ath5k_eeprom_init(ah); - if (ret) { - ATH5K_ERR(sc, "unable to init EEPROM\n"); - goto err_free; - } - - /* Get misc capabilities */ - ret = ath5k_hw_get_capabilities(ah); - if (ret) { - ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", - sc->pdev->device); - goto err_free; - } - - /* Get 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; - } - - 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); - ath5k_hw_set_opmode(ah); - - ath5k_hw_set_rfgain_opt(ah); - - return ah; -err_free: - kfree(ah); -err: - return ERR_PTR(ret); -} - -/* - * Bring up MAC + PHY Chips - */ -static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) -{ - struct pci_dev *pdev = ah->ah_sc->pdev; - u32 turbo, mode, clock, bus_flags; - int ret; - - turbo = 0; - mode = 0; - clock = 0; - - ATH5K_TRACE(ah->ah_sc); - - /* Wakeup the device */ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); - return ret; - } - - if (ah->ah_version != AR5K_AR5210) { - /* - * Get channel mode flags - */ - - if (ah->ah_radio >= AR5K_RF5112) { - mode = AR5K_PHY_MODE_RAD_RF5112; - clock = AR5K_PHY_PLL_RF5112; - } else { - mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ - clock = AR5K_PHY_PLL_RF5111; /*Zero*/ - } - - if (flags & CHANNEL_2GHZ) { - mode |= AR5K_PHY_MODE_FREQ_2GHZ; - clock |= AR5K_PHY_PLL_44MHZ; - - if (flags & CHANNEL_CCK) { - mode |= AR5K_PHY_MODE_MOD_CCK; - } else if (flags & CHANNEL_OFDM) { - /* XXX Dynamic OFDM/CCK is not supported by the - * AR5211 so we set MOD_OFDM for plain g (no - * CCK headers) operation. We need to test - * this, 5211 might support ofdm-only g after - * all, there are also initial register values - * in the code for g mode (see initvals.c). */ - if (ah->ah_version == AR5K_AR5211) - mode |= AR5K_PHY_MODE_MOD_OFDM; - else - mode |= AR5K_PHY_MODE_MOD_DYN; - } else { - ATH5K_ERR(ah->ah_sc, - "invalid radio modulation mode\n"); - return -EINVAL; - } - } else if (flags & CHANNEL_5GHZ) { - mode |= AR5K_PHY_MODE_FREQ_5GHZ; - clock |= AR5K_PHY_PLL_40MHZ; - - if (flags & CHANNEL_OFDM) - mode |= AR5K_PHY_MODE_MOD_OFDM; - else { - ATH5K_ERR(ah->ah_sc, - "invalid radio modulation mode\n"); - return -EINVAL; - } - } else { - ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); - return -EINVAL; - } - - if (flags & CHANNEL_TURBO) - turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; - } else { /* Reset the device */ - - /* ...enable Atheros turbo mode if requested */ - if (flags & CHANNEL_TURBO) - ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, - AR5K_PHY_TURBO); - } - - /* reseting PCI on PCI-E cards results card to hang - * and always return 0xffff... so we ingore that flag - * for PCI-E cards */ - bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; - - /* Reset chipset */ - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_BASEBAND | bus_flags); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); - return -EIO; - } - - if (ah->ah_version == AR5K_AR5210) - udelay(2300); - - /* ...wakeup again!*/ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); - return ret; - } - - /* ...final warm reset */ - if (ath5k_hw_nic_reset(ah, 0)) { - ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); - return -EIO; - } - - if (ah->ah_version != AR5K_AR5210) { - /* ...set the PHY operating mode */ - ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); - udelay(300); - - ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); - ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); - } - - return 0; -} - -/* - * Free the ath5k_hw struct - */ -void ath5k_hw_detach(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); - - if (ah->ah_rf_banks != NULL) - kfree(ah->ah_rf_banks); - - /* assume interrupts are down */ - kfree(ah); -} - -/****************************\ - Reset function and helpers -\****************************/ - -/** - * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 - * - * @ah: the &struct ath5k_hw - * @channel: the currently set channel upon reset - * - * Write the OFDM timings for the AR5212 upon reset. This is a helper for - * ath5k_hw_reset(). This seems to tune the PLL a specified frequency - * depending on the bandwidth of the channel. - * - */ -static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - /* Get exponent and mantissa and set it */ - u32 coef_scaled, coef_exp, coef_man, - ds_coef_exp, ds_coef_man, clock; - - if (!(ah->ah_version == AR5K_AR5212) || - !(channel->hw_value & CHANNEL_OFDM)) - BUG(); - - /* Seems there are two PLLs, one for baseband sampling and one - * for tuning. Tuning basebands are 40 MHz or 80MHz when in - * turbo. */ - clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40; - coef_scaled = ((5 * (clock << 24)) / 2) / - channel->center_freq; - - for (coef_exp = 31; coef_exp > 0; coef_exp--) - if ((coef_scaled >> coef_exp) & 0x1) - break; - - if (!coef_exp) - return -EINVAL; - - coef_exp = 14 - (coef_exp - 24); - coef_man = coef_scaled + - (1 << (24 - coef_exp - 1)); - ds_coef_man = coef_man >> (24 - coef_exp); - ds_coef_exp = coef_exp - 16; - - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, - AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, - AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); - - return 0; -} - - -/* - * index into rates for control rates, we can set it up like this because - * this is only used for AR5212 and we know it supports G mode - */ -static int control_rates[] = - { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; - -/** - * ath5k_hw_write_rate_duration - set rate duration during hw resets - * - * @ah: the &struct ath5k_hw - * @mode: one of enum ath5k_driver_mode - * - * Write the rate duration table upon hw reset. This is a helper for - * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for - * the hardware for the current mode for each rate. The rates which are capable - * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another - * register for the short preamble ACK timeout calculation. - */ -static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, - unsigned int mode) -{ - struct ath5k_softc *sc = ah->ah_sc; - struct ieee80211_rate *rate; - unsigned int i; - - /* Write rate duration table */ - for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { - u32 reg; - u16 tx_time; - - rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; - - /* Set ACK timeout */ - reg = AR5K_RATE_DUR(rate->hw_value); - - /* An ACK frame consists of 10 bytes. If you add the FCS, - * which ieee80211_generic_frame_duration() adds, - * its 14 bytes. Note we use the control rate and not the - * actual rate for this rate. See mac80211 tx.c - * ieee80211_duration() for a brief description of - * what rate we should choose to TX ACKs. */ - tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, - sc->vif, 10, rate)); - - ath5k_hw_reg_write(ah, tx_time, reg); - - if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) - continue; - - /* - * We're not distinguishing short preamble here, - * This is true, all we'll get is a longer value here - * which is not necessarilly bad. We could use - * export ieee80211_frame_duration() but that needs to be - * fixed first to be properly used by mac802111 drivers: - * - * - remove erp stuff and let the routine figure ofdm - * erp rates - * - remove passing argument ieee80211_local as - * drivers don't have access to it - * - move drivers using ieee80211_generic_frame_duration() - * to this - */ - ath5k_hw_reg_write(ah, tx_time, - reg + (AR5K_SET_SHORT_PREAMBLE << 2)); - } -} - -/* - * Main reset function - */ -int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, - struct ieee80211_channel *channel, bool change_channel) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct pci_dev *pdev = ah->ah_sc->pdev; - u32 data, s_seq, s_ant, s_led[3], dma_size; - unsigned int i, mode, freq, ee_mode, ant[2]; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - s_seq = 0; - s_ant = 0; - ee_mode = 0; - freq = 0; - mode = 0; - - /* - * Save some registers before a reset - */ - /*DCU/Antenna selection not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - if (change_channel) { - /* Seq number for queue 0 -do this for all queues ? */ - s_seq = ath5k_hw_reg_read(ah, - AR5K_QUEUE_DFS_SEQNUM(0)); - /*Default antenna*/ - s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); - } - } - - /*GPIOs*/ - s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; - s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); - s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); - - if (change_channel && ah->ah_rf_banks != NULL) - ath5k_hw_get_rf_gain(ah); - - - /*Wakeup the device*/ - ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); - if (ret) - return ret; - - /* - * Initialize operating mode - */ - ah->ah_op_mode = op_mode; - - /* - * 5111/5112 Settings - * 5210 only comes with RF5110 - */ - if (ah->ah_version != AR5K_AR5210) { - if (ah->ah_radio != AR5K_RF5111 && - ah->ah_radio != AR5K_RF5112 && - ah->ah_radio != AR5K_RF5413 && - ah->ah_radio != AR5K_RF2413 && - ah->ah_radio != AR5K_RF2425) { - ATH5K_ERR(ah->ah_sc, - "invalid phy radio: %u\n", ah->ah_radio); - return -EINVAL; - } - - switch (channel->hw_value & CHANNEL_MODES) { - case CHANNEL_A: - mode = AR5K_MODE_11A; - freq = AR5K_INI_RFGAIN_5GHZ; - ee_mode = AR5K_EEPROM_MODE_11A; - break; - case CHANNEL_G: - mode = AR5K_MODE_11G; - freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11G; - break; - case CHANNEL_B: - mode = AR5K_MODE_11B; - freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11B; - break; - case CHANNEL_T: - mode = AR5K_MODE_11A_TURBO; - freq = AR5K_INI_RFGAIN_5GHZ; - ee_mode = AR5K_EEPROM_MODE_11A; - break; - /*Is this ok on 5211 too ?*/ - case CHANNEL_TG: - mode = AR5K_MODE_11G_TURBO; - freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11G; - break; - case CHANNEL_XR: - if (ah->ah_version == AR5K_AR5211) { - ATH5K_ERR(ah->ah_sc, - "XR mode not available on 5211"); - return -EINVAL; - } - mode = AR5K_MODE_XR; - freq = AR5K_INI_RFGAIN_5GHZ; - ee_mode = AR5K_EEPROM_MODE_11A; - break; - default: - ATH5K_ERR(ah->ah_sc, - "invalid channel: %d\n", channel->center_freq); - return -EINVAL; - } - - /* PHY access enable */ - ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); - - } - - ret = ath5k_hw_write_initvals(ah, mode, change_channel); - if (ret) - return ret; - - /* - * 5211/5212 Specific - */ - if (ah->ah_version != AR5K_AR5210) { - /* - * Write initial RF gain settings - * This should work for both 5111/5112 - */ - ret = ath5k_hw_rfgain(ah, freq); - if (ret) - return ret; - - mdelay(1); - - /* - * Write some more initial register settings - */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); - - if (channel->hw_value == CHANNEL_G) - if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) - ath5k_hw_reg_write(ah, 0x00f80d80, - 0x994c); - else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) - ath5k_hw_reg_write(ah, 0x00380140, - 0x994c); - else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) - ath5k_hw_reg_write(ah, 0x00fc0ec0, - 0x994c); - else /* 2425 */ - ath5k_hw_reg_write(ah, 0x00fc0fc0, - 0x994c); - else - ath5k_hw_reg_write(ah, 0x00000000, 0x994c); - - /* Some bits are disabled here, we know nothing about - * register 0xa228 yet, most of the times this ends up - * with a value 0x9b5 -haven't seen any dump with - * a different value- */ - /* Got this from decompiling binary HAL */ - data = ath5k_hw_reg_read(ah, 0xa228); - data &= 0xfffffdff; - ath5k_hw_reg_write(ah, data, 0xa228); - - data = ath5k_hw_reg_read(ah, 0xa228); - data &= 0xfffe03ff; - ath5k_hw_reg_write(ah, data, 0xa228); - data = 0; - - /* Just write 0x9b5 ? */ - /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */ - ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); - ath5k_hw_reg_write(ah, 0x00000000, 0xa254); - ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); - } - - /* Fix for first revision of the RF5112 RF chipset */ - if (ah->ah_radio >= AR5K_RF5112 && - ah->ah_radio_5ghz_revision < - AR5K_SREV_RAD_5112A) { - ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, - AR5K_PHY_CCKTXCTL); - if (channel->hw_value & CHANNEL_5GHZ) - data = 0xffb81020; - else - data = 0xffb80d20; - ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); - data = 0; - } - - /* - * Set TX power (FIXME) - */ - ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); - if (ret) - return ret; - - /* Write rate duration table only on AR5212 and if - * virtual interface has already been brought up - * XXX: rethink this after new mode changes to - * mac80211 are integrated */ - if (ah->ah_version == AR5K_AR5212 && - ah->ah_sc->vif != NULL) - ath5k_hw_write_rate_duration(ah, mode); - - /* - * Write RF registers - */ - ret = ath5k_hw_rfregs(ah, channel, mode); - if (ret) - return ret; - - /* - * Configure additional registers - */ - - /* Write OFDM timings on 5212*/ - if (ah->ah_version == AR5K_AR5212 && - channel->hw_value & CHANNEL_OFDM) { - ret = ath5k_hw_write_ofdm_timings(ah, channel); - if (ret) - return ret; - } - - /*Enable/disable 802.11b mode on 5111 - (enable 2111 frequency converter + CCK)*/ - if (ah->ah_radio == AR5K_RF5111) { - if (mode == AR5K_MODE_11B) - AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_B_MODE); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_B_MODE); - } - - /* - * Set channel and calibrate the PHY - */ - ret = ath5k_hw_channel(ah, channel); - if (ret) - return ret; - - /* Set antenna mode */ - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL, - ah->ah_antenna[ee_mode][0], 0xfffffc06); - - /* - * In case a fixed antenna was set as default - * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE - * registers. - */ - if (s_ant != 0){ - if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ - ant[0] = ant[1] = AR5K_ANT_FIXED_A; - else /* 2 - Aux */ - ant[0] = ant[1] = AR5K_ANT_FIXED_B; - } else { - ant[0] = AR5K_ANT_FIXED_A; - ant[1] = AR5K_ANT_FIXED_B; - } - - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], - AR5K_PHY_ANT_SWITCH_TABLE_0); - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], - AR5K_PHY_ANT_SWITCH_TABLE_1); - - /* Commit values from EEPROM */ - if (ah->ah_radio == AR5K_RF5111) - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, - AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); - - ath5k_hw_reg_write(ah, - AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), - AR5K_PHY_NFTHRES); - - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING, - (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, - 0xfffc0fff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, - (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | - ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), - 0xffff0000); - - ath5k_hw_reg_write(ah, - (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | - (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | - (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | - (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4); - - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3, - ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF, - (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01); - - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CORR_ENABLE | - (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | - ee->ee_q_cal[ee_mode]); - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, - AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, - ee->ee_margin_tx_rx[ee_mode]); - - } else { - mdelay(1); - /* Disable phy and wait */ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); - mdelay(1); - } - - /* - * Restore saved values - */ - /*DCU/Antenna selection not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); - ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); - } - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); - ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); - ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); - - /* - * Misc - */ - /* XXX: add ah->aid once mac80211 gives this to us */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - - ath5k_hw_set_opmode(ah); - /*PISR/SISR Not available on 5210*/ - if (ah->ah_version != AR5K_AR5210) { - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); - /* If we later allow tuning for this, store into sc structure */ - data = AR5K_TUNE_RSSI_THRES | - AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; - ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); - } - - /* - * Set Rx/Tx DMA Configuration - * - * Set maximum DMA size (512) except for PCI-E cards since - * it causes rx overruns and tx errors (tested on 5424 but since - * rx overruns also occur on 5416/5418 with madwifi we set 128 - * for all PCI-E cards to be safe). - * - * In dumps this is 128 for allchips. - * - * XXX: need to check 5210 for this - * TODO: Check out tx triger level, it's always 64 on dumps but I - * guess we can tweak it and see how it goes ;-) - */ - dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; - if (ah->ah_version != AR5K_AR5210) { - AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_SDMAMR, dma_size); - AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, - AR5K_RXCFG_SDMAMW, dma_size); - } - - /* - * Enable the PHY and wait until completion - */ - ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - - /* - * On 5211+ read activation -> rx delay - * and use it. - */ - if (ah->ah_version != AR5K_AR5210) { - data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & - AR5K_PHY_RX_DELAY_M; - data = (channel->hw_value & CHANNEL_CCK) ? - ((data << 2) / 22) : (data / 10); - - udelay(100 + (2 * data)); - data = 0; - } else { - mdelay(1); - } - - /* - * Perform ADC test (?) - */ - data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); - ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); - for (i = 0; i <= 20; i++) { - if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) - break; - udelay(200); - } - ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1); - data = 0; - - /* - * Start automatic gain calibration - * - * During AGC calibration RX path is re-routed to - * a signal detector so we don't receive anything. - * - * This method is used to calibrate some static offsets - * used together with on-the fly I/Q calibration (the - * one performed via ath5k_hw_phy_calibrate), that doesn't - * interrupt rx path. - * - * If we are in a noisy environment AGC calibration may time - * out. - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL); - - /* At the same time start I/Q calibration for QAM constellation - * -no need for CCK- */ - ah->ah_calibration = false; - if (!(mode == AR5K_MODE_11B)) { - ah->ah_calibration = true; - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_RUN); - } - - /* Wait for gain calibration to finish (we check for I/Q calibration - * during ath5k_phy_calibrate) */ - if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL, 0, false)) { - ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n", - channel->center_freq); - return -EAGAIN; - } - - /* - * Start noise floor calibration - * - * If we run NF calibration before AGC, it always times out. - * Binary HAL starts NF and AGC calibration at the same time - * and only waits for AGC to finish. I believe that's wrong because - * during NF calibration, rx path is also routed to a detector, so if - * it doesn't finish we won't have RX. - * - * XXX: Find an interval that's OK for all cards... - */ - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; - - /* - * Reset queues and start beacon timers at the end of the reset routine - */ - for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { - /*No QCU on 5210*/ - if (ah->ah_version != AR5K_AR5210) - AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); - - ret = ath5k_hw_reset_tx_queue(ah, i); - if (ret) { - ATH5K_ERR(ah->ah_sc, - "failed to reset TX queue #%d\n", i); - return ret; - } - } - - /* Pre-enable interrupts on 5211/5212*/ - if (ah->ah_version != AR5K_AR5210) - ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX | - AR5K_INT_FATAL); - - /* - * Set RF kill flags if supported by the device (read from the EEPROM) - * Disable gpio_intr for now since it results system hang. - * TODO: Handle this in ath5k_intr - */ -#if 0 - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { - ath5k_hw_set_gpio_input(ah, 0); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); - if (ah->ah_gpio[0] == 0) - ath5k_hw_set_gpio_intr(ah, 0, 1); - else - ath5k_hw_set_gpio_intr(ah, 0, 0); - } -#endif - - /* - * Set the 32MHz reference clock on 5212 phy clock sleep register - * - * TODO: Find out how to switch to external 32Khz clock to save power - */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); - ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); - ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); - ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); - ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); - ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); - - data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ; - data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ? - 0x00000f80 : 0x00001380 ; - ath5k_hw_reg_write(ah, data, AR5K_USEC_5211); - data = 0; - } - - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); - ath5k_hw_reg_write(ah, 0x00003210, 0x811c); - ath5k_hw_reg_write(ah, 0x00000052, 0x8108); - if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413) - ath5k_hw_reg_write(ah, 0x00000004, 0x8120); - } - - /* - * Disable beacons and reset the register - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | - AR5K_BEACON_RESET_TSF); - - return 0; -} - -/* - * Reset chipset - */ -static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) -{ - int ret; - u32 mask = val ? val : ~0U; - - ATH5K_TRACE(ah->ah_sc); - - /* Read-and-clear RX Descriptor Pointer*/ - ath5k_hw_reg_read(ah, AR5K_RXDP); - - /* - * Reset the device and wait until success - */ - ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); - - /* Wait at least 128 PCI clocks */ - udelay(15); - - if (ah->ah_version == AR5K_AR5210) { - val &= AR5K_RESET_CTL_CHIP; - mask &= AR5K_RESET_CTL_CHIP; - } else { - val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; - mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; - } - - ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); - - /* - * Reset configuration register (for hw byte-swap). Note that this - * is only set for big endian. We do the necessary magic in - * AR5K_INIT_CFG. - */ - if ((val & AR5K_RESET_CTL_PCU) == 0) - ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); - - return ret; -} - -/* - * Power management functions - */ - -/* - * Sleep control - */ -int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, - bool set_chip, u16 sleep_duration) -{ - unsigned int i; - u32 staid, data; - - ATH5K_TRACE(ah->ah_sc); - staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); - - switch (mode) { - case AR5K_PM_AUTO: - staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; - /* fallthrough */ - case AR5K_PM_NETWORK_SLEEP: - if (set_chip) - ath5k_hw_reg_write(ah, - AR5K_SLEEP_CTL_SLE_ALLOW | - sleep_duration, - AR5K_SLEEP_CTL); - - staid |= AR5K_STA_ID1_PWR_SV; - break; - - case AR5K_PM_FULL_SLEEP: - if (set_chip) - ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, - AR5K_SLEEP_CTL); - - staid |= AR5K_STA_ID1_PWR_SV; - break; - - case AR5K_PM_AWAKE: - - staid &= ~AR5K_STA_ID1_PWR_SV; - - if (!set_chip) - goto commit; - - /* Preserve sleep duration */ - data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); - if( data & 0xffc00000 ){ - data = 0; - } else { - data = data & 0xfffcffff; - } - - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); - udelay(15); - - for (i = 50; i > 0; i--) { - /* Check if the chip did wake up */ - if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & - AR5K_PCICFG_SPWR_DN) == 0) - break; - - /* Wait a bit and retry */ - udelay(200); - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); - } - - /* Fail if the chip didn't wake up */ - if (i <= 0) - return -EIO; - - break; - - default: - return -EINVAL; - } - -commit: - ah->ah_power_mode = mode; - ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); - - return 0; -} - -/***********************\ - DMA Related Functions -\***********************/ - -/* - * Receive functions - */ - -/* - * Start DMA receive - */ -void ath5k_hw_start_rx(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); - ath5k_hw_reg_read(ah, AR5K_CR); -} - -/* - * Stop DMA receive - */ -int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) -{ - unsigned int i; - - ATH5K_TRACE(ah->ah_sc); - ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); - - /* - * It may take some time to disable the DMA receive unit - */ - for (i = 2000; i > 0 && - (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; - i--) - udelay(10); - - return i ? 0 : -EBUSY; -} - -/* - * Get the address of the RX Descriptor - */ -u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah) -{ - return ath5k_hw_reg_read(ah, AR5K_RXDP); -} - -/* - * Set the address of the RX Descriptor - */ -void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr) -{ - ATH5K_TRACE(ah->ah_sc); - - /*TODO:Shouldn't we check if RX is enabled first ?*/ - ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); -} - -/* - * Transmit functions - */ - -/* - * Start DMA transmit for a specific queue - * (see also QCU/DCU functions) - */ -int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue) -{ - u32 tx_queue; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* Return if queue is declared inactive */ - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; - - if (ah->ah_version == AR5K_AR5210) { - tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); - - /* - * Set the queue by type on 5210 - */ - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; - break; - case AR5K_TX_QUEUE_BEACON: - tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, - AR5K_BSR); - break; - case AR5K_TX_QUEUE_CAB: - tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V | - AR5K_BCR_BDMAE, AR5K_BSR); - break; - default: - return -EINVAL; - } - /* Start queue */ - ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); - ath5k_hw_reg_read(ah, AR5K_CR); - } else { - /* Return if queue is disabled */ - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) - return -EIO; - - /* Start queue */ - AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); - } - - return 0; -} - -/* - * Stop DMA transmit for a specific queue - * (see also QCU/DCU functions) - */ -int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) -{ - unsigned int i = 100; - u32 tx_queue, pending; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* Return if queue is declared inactive */ - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; - - if (ah->ah_version == AR5K_AR5210) { - tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); - - /* - * Set by queue type - */ - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - /* XXX Fix me... */ - tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1; - ath5k_hw_reg_write(ah, 0, AR5K_BSR); - break; - default: - return -EINVAL; - } - - /* Stop queue */ - ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); - ath5k_hw_reg_read(ah, AR5K_CR); - } else { - /* - * Schedule TX disable and wait until queue is empty - */ - AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); - - /*Check for pending frames*/ - do { - pending = ath5k_hw_reg_read(ah, - AR5K_QUEUE_STATUS(queue)) & - AR5K_QCU_STS_FRMPENDCNT; - udelay(100); - } while (--i && pending); - - /* Clear register */ - ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); - if (pending) - return -EBUSY; - } - - /* TODO: Check for success else return error */ - return 0; -} - -/* - * Get the address of the TX Descriptor for a specific queue - * (see also QCU/DCU functions) - */ -u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue) -{ - u16 tx_reg; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* - * Get the transmit queue descriptor pointer from the selected queue - */ - /*5210 doesn't have QCU*/ - if (ah->ah_version == AR5K_AR5210) { - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_reg = AR5K_NOQCU_TXDP0; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - tx_reg = AR5K_NOQCU_TXDP1; - break; - default: - return 0xffffffff; - } - } else { - tx_reg = AR5K_QUEUE_TXDP(queue); - } - - return ath5k_hw_reg_read(ah, tx_reg); -} - -/* - * Set the address of the TX Descriptor for a specific queue - * (see also QCU/DCU functions) - */ -int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) -{ - u16 tx_reg; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* - * Set the transmit queue descriptor pointer register by type - * on 5210 - */ - if (ah->ah_version == AR5K_AR5210) { - switch (ah->ah_txq[queue].tqi_type) { - case AR5K_TX_QUEUE_DATA: - tx_reg = AR5K_NOQCU_TXDP0; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - tx_reg = AR5K_NOQCU_TXDP1; - break; - default: - return -EINVAL; - } - } else { - /* - * Set the transmit queue descriptor pointer for - * the selected queue on QCU for 5211+ - * (this won't work if the queue is still active) - */ - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) - return -EIO; - - tx_reg = AR5K_QUEUE_TXDP(queue); - } - - /* Set descriptor pointer */ - ath5k_hw_reg_write(ah, phys_addr, tx_reg); - - return 0; -} - -/* - * Update tx trigger level - */ -int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) -{ - u32 trigger_level, imr; - int ret = -EIO; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Disable interrupts by setting the mask - */ - imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); - - /*TODO: Boundary check on trigger_level*/ - trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), - AR5K_TXCFG_TXFULL); - - if (!increase) { - if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) - goto done; - } else - trigger_level += - ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); - - /* - * Update trigger level on success - */ - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); - else - AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, - AR5K_TXCFG_TXFULL, trigger_level); - - ret = 0; - -done: - /* - * Restore interrupt mask - */ - ath5k_hw_set_intr(ah, imr); - - return ret; -} - -/* - * Interrupt handling - */ - -/* - * Check if we have pending interrupts - */ -bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_INTPEND); -} - -/* - * Get interrupt mask (ISR) - */ -int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) -{ - u32 data; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Read interrupt status from the Interrupt Status register - * on 5210 - */ - if (ah->ah_version == AR5K_AR5210) { - data = ath5k_hw_reg_read(ah, AR5K_ISR); - if (unlikely(data == AR5K_INT_NOCARD)) { - *interrupt_mask = data; - return -ENODEV; - } - } else { - /* - * Read interrupt status from the Read-And-Clear shadow register - * Note: PISR/SISR Not available on 5210 - */ - data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); - } - - /* - * Get abstract interrupt mask (driver-compatible) - */ - *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) { - /*HIU = Host Interface Unit (PCI etc)*/ - if (unlikely(data & (AR5K_ISR_HIUERR))) - *interrupt_mask |= AR5K_INT_FATAL; - - /*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 - - /* - * In case we didn't handle anything, - * print the register value. - */ - if (unlikely(*interrupt_mask == 0 && net_ratelimit())) - ATH5K_PRINTF("0x%08x\n", data); - - return 0; -} - -/* - * Set interrupt mask - */ -enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) -{ - enum ath5k_int old_mask, int_mask; - - /* - * Disable card interrupts to prevent any race conditions - * (they will be re-enabled afterwards). - */ - ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - - old_mask = ah->ah_imr; - - /* - * Add additional, chipset-dependent interrupt mask flags - * and write them to the IMR (interrupt mask register). - */ - 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) { - 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); - } - } - - ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); - - /* 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); - - return old_mask; -} - - -/*************************\ - EEPROM access functions -\*************************/ - -/* - * Read from eeprom - */ -static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) -{ - u32 status, timeout; - - ATH5K_TRACE(ah->ah_sc); - /* - * Initialize EEPROM access - */ - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); - (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); - } else { - ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); - AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, - AR5K_EEPROM_CMD_READ); - } - - for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { - status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); - if (status & AR5K_EEPROM_STAT_RDDONE) { - if (status & AR5K_EEPROM_STAT_RDERR) - return -EIO; - *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & - 0xffff); - return 0; - } - udelay(15); - } - - return -ETIMEDOUT; -} - -/* - * Write to eeprom - currently disabled, use at your own risk - */ -#if 0 -static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data) -{ - - u32 status, timeout; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Initialize eeprom access - */ - - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); - } else { - AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, - AR5K_EEPROM_CMD_RESET); - } - - /* - * Write data to data register - */ - - if (ah->ah_version == AR5K_AR5210) { - ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset)); - } else { - ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); - ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA); - AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, - AR5K_EEPROM_CMD_WRITE); - } - - /* - * Check status - */ - - for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { - status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); - if (status & AR5K_EEPROM_STAT_WRDONE) { - if (status & AR5K_EEPROM_STAT_WRERR) - return EIO; - return 0; - } - udelay(15); - } - - ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!"); - return -EIO; -} -#endif - -/* - * Translate binary channel representation in EEPROM to frequency - */ -static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode) -{ - u16 val; - - if (bin == AR5K_EEPROM_CHANNEL_DIS) - return bin; - - if (mode == AR5K_EEPROM_MODE_11A) { - if (ah->ah_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) - val = bin + 2300; - else - val = bin + 2400; - } - - return val; -} - -/* - * Read antenna infos from eeprom - */ -static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, - unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 o = *offset; - u16 val; - int ret, i = 0; - - AR5K_EEPROM_READ(o++, val); - ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; - ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; - ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; - ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; - ee->ee_ant_control[mode][i++] = val & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; - ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; - ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; - ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; - ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; - ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; - - AR5K_EEPROM_READ(o++, val); - ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; - ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; - ee->ee_ant_control[mode][i++] = val & 0x3f; - - /* Get antenna modes */ - ah->ah_antenna[mode][0] = - (ee->ee_ant_control[mode][0] << 4) | 0x1; - ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = - ee->ee_ant_control[mode][1] | - (ee->ee_ant_control[mode][2] << 6) | - (ee->ee_ant_control[mode][3] << 12) | - (ee->ee_ant_control[mode][4] << 18) | - (ee->ee_ant_control[mode][5] << 24); - ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = - ee->ee_ant_control[mode][6] | - (ee->ee_ant_control[mode][7] << 6) | - (ee->ee_ant_control[mode][8] << 12) | - (ee->ee_ant_control[mode][9] << 18) | - (ee->ee_ant_control[mode][10] << 24); - - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Read supported modes from eeprom - */ -static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, - unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 o = *offset; - u16 val; - int ret; - - AR5K_EEPROM_READ(o++, val); - ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; - ee->ee_thr_62[mode] = val & 0xff; - - if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) - ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; - - AR5K_EEPROM_READ(o++, val); - ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; - ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; - - AR5K_EEPROM_READ(o++, val); - ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; - - if ((val & 0xff) & 0x80) - ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); - else - ee->ee_noise_floor_thr[mode] = val & 0xff; - - if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) - ee->ee_noise_floor_thr[mode] = - mode == AR5K_EEPROM_MODE_11A ? -54 : -1; - - AR5K_EEPROM_READ(o++, val); - ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; - ee->ee_x_gain[mode] = (val >> 1) & 0xf; - ee->ee_xpd[mode] = val & 0x1; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) - ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { - AR5K_EEPROM_READ(o++, val); - ee->ee_false_detect[mode] = (val >> 6) & 0x7f; - - if (mode == AR5K_EEPROM_MODE_11A) - ee->ee_xr_power[mode] = val & 0x3f; - else { - ee->ee_ob[mode][0] = val & 0x7; - ee->ee_db[mode][0] = (val >> 3) & 0x7; - } - } - - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { - ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; - ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; - } else { - ee->ee_i_gain[mode] = (val >> 13) & 0x7; - - AR5K_EEPROM_READ(o++, val); - ee->ee_i_gain[mode] |= (val << 3) & 0x38; - - if (mode == AR5K_EEPROM_MODE_11G) - ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; - } - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && - mode == AR5K_EEPROM_MODE_11A) { - 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_6 && - mode == AR5K_EEPROM_MODE_11G) - ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; - - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Initialize eeprom & capabilities structs - */ -static int ath5k_eeprom_init(struct ath5k_hw *ah) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - unsigned int mode, i; - int ret; - u32 offset; - 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; - } - - /* - * Get conformance test limit values - */ - offset = AR5K_EEPROM_CTL(ah->ah_ee_version); - ee->ee_ctls = AR5K_EEPROM_N_CTLS(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; - } - - /* - * Get values for 802.11a (5GHz) - */ - mode = AR5K_EEPROM_MODE_11A; - - ee->ee_turbo_max_power[mode] = - AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); - - offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - 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; - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_margin_tx_rx[mode] = val & 0x3f; - } - - /* - * Get values for 802.11b (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11B; - offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - 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; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; - - 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); - - AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - } - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; - - /* - * Get values for 802.11g (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11G; - offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); - - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; - - 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; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; - - 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); - - AR5K_EEPROM_READ(offset++, val); - ee->ee_turbo_max_power[mode] = val & 0x7f; - ee->ee_xr_power[mode] = (val >> 7) & 0x3f; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; - - AR5K_EEPROM_READ(offset++, 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(offset++, val); - ee->ee_cck_ofdm_gain_delta = val & 0xff; - } - } - - /* - * Read 5GHz EEPROM channels - */ - - return 0; -} - -/* - * Read the MAC address from eeprom - */ -static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) -{ - u8 mac_d[ETH_ALEN]; - u32 total, offset; - u16 data; - int octet, ret; - - memset(mac, 0, ETH_ALEN); - memset(mac_d, 0, ETH_ALEN); - - ret = ath5k_hw_eeprom_read(ah, 0x20, &data); - if (ret) - return ret; - - for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - ret = ath5k_hw_eeprom_read(ah, offset, &data); - if (ret) - return ret; - - total += data; - mac_d[octet + 1] = data & 0xff; - mac_d[octet] = data >> 8; - octet += 2; - } - - memcpy(mac, mac_d, ETH_ALEN); - - if (!total || total == 3 * 0xffff) - return -EINVAL; - - return 0; -} - -/* - * Fill the capabilities struct - */ -static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) -{ - u16 ee_header; - - ATH5K_TRACE(ah->ah_sc); - /* Capabilities stored in the EEPROM */ - ee_header = ah->ah_capabilities.cap_eeprom.ee_header; - - if (ah->ah_version == AR5K_AR5210) { - /* - * Set radio capabilities - * (The AR5110 only supports the middle 5GHz band) - */ - ah->ah_capabilities.cap_range.range_5ghz_min = 5120; - ah->ah_capabilities.cap_range.range_5ghz_max = 5430; - ah->ah_capabilities.cap_range.range_2ghz_min = 0; - ah->ah_capabilities.cap_range.range_2ghz_max = 0; - - /* Set supported modes */ - __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); - __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode); - } else { - /* - * XXX The tranceiver supports frequencies from 4920 to 6100GHz - * XXX and from 2312 to 2732GHz. There are problems with the - * XXX current ieee80211 implementation because the IEEE - * XXX channel mapping does not support negative channel - * XXX numbers (2312MHz is channel -19). Of course, this - * XXX doesn't matter because these channels are out of range - * XXX but some regulation domains like MKK (Japan) will - * XXX support frequencies somewhere around 4.8GHz. - */ - - /* - * Set radio capabilities - */ - - if (AR5K_EEPROM_HDR_11A(ee_header)) { - ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */ - ah->ah_capabilities.cap_range.range_5ghz_max = 6100; - - /* Set supported modes */ - __set_bit(AR5K_MODE_11A, - ah->ah_capabilities.cap_mode); - __set_bit(AR5K_MODE_11A_TURBO, - ah->ah_capabilities.cap_mode); - if (ah->ah_version == AR5K_AR5212) - __set_bit(AR5K_MODE_11G_TURBO, - ah->ah_capabilities.cap_mode); - } - - /* Enable 802.11b if a 2GHz capable radio (2111/5112) is - * connected */ - if (AR5K_EEPROM_HDR_11B(ee_header) || - AR5K_EEPROM_HDR_11G(ee_header)) { - ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */ - ah->ah_capabilities.cap_range.range_2ghz_max = 2732; - - if (AR5K_EEPROM_HDR_11B(ee_header)) - __set_bit(AR5K_MODE_11B, - ah->ah_capabilities.cap_mode); - - if (AR5K_EEPROM_HDR_11G(ee_header)) - __set_bit(AR5K_MODE_11G, - ah->ah_capabilities.cap_mode); - } - } - - /* GPIO */ - ah->ah_gpio_npins = AR5K_NUM_GPIO; - - /* Set number of supported TX queues */ - if (ah->ah_version == AR5K_AR5210) - ah->ah_capabilities.cap_queues.q_tx_num = - AR5K_NUM_TX_QUEUES_NOQCU; - else - ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; - - return 0; -} - -/*********************************\ - Protocol Control Unit Functions -\*********************************/ - -/* - * Set Operation mode - */ -int ath5k_hw_set_opmode(struct ath5k_hw *ah) -{ - u32 pcu_reg, beacon_reg, low_id, high_id; - - pcu_reg = 0; - beacon_reg = 0; - - ATH5K_TRACE(ah->ah_sc); - - switch (ah->ah_op_mode) { - case IEEE80211_IF_TYPE_IBSS: - pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); - beacon_reg |= AR5K_BCR_ADHOC; - break; - - case IEEE80211_IF_TYPE_AP: - case IEEE80211_IF_TYPE_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); - beacon_reg |= AR5K_BCR_AP; - break; - - case IEEE80211_IF_TYPE_STA: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_PWR_SV : 0); - case IEEE80211_IF_TYPE_MNTR: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); - break; - - default: - return -EINVAL; - } - - /* - * Set PCU registers - */ - low_id = AR5K_LOW_ID(ah->ah_sta_id); - high_id = AR5K_HIGH_ID(ah->ah_sta_id); - ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); - ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); - - /* - * Set Beacon Control Register on 5210 - */ - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); - - return 0; -} - -/* - * BSSID Functions - */ - -/* - * Get station id - */ -void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) -{ - ATH5K_TRACE(ah->ah_sc); - memcpy(mac, ah->ah_sta_id, ETH_ALEN); -} - -/* - * Set station id - */ -int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) -{ - u32 low_id, high_id; - - ATH5K_TRACE(ah->ah_sc); - /* Set new station ID */ - memcpy(ah->ah_sta_id, mac, ETH_ALEN); - - 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); - - return 0; -} - -/* - * Set BSSID - */ -void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) -{ - u32 low_id, high_id; - u16 tim_offset = 0; - - /* - * 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); - } - - /* - * Set BSSID which triggers the "SME Join" operation - */ - low_id = AR5K_LOW_ID(bssid); - high_id = AR5K_HIGH_ID(bssid); - ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); - ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << - AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); - - if (assoc_id == 0) { - ath5k_hw_disable_pspoll(ah); - return; - } - - AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, - tim_offset ? tim_offset + 4 : 0); - - ath5k_hw_enable_pspoll(ah, NULL, 0); -} -/** - * ath5k_hw_set_bssid_mask - set common bits we should listen to - * - * The bssid_mask is a utility used by AR5212 hardware to inform the hardware - * which bits of the interface's MAC address should be looked at when trying - * to decide which packets to ACK. In station mode every bit matters. In AP - * mode with a single BSS every bit matters as well. In AP mode with - * multiple BSSes not every bit matters. - * - * @ah: the &struct ath5k_hw - * @mask: the bssid_mask, a u8 array of size ETH_ALEN - * - * Note that this is a simple filter and *does* not filter out all - * relevant frames. Some non-relevant frames will get through, probability - * jocks are welcomed to compute. - * - * When handling multiple BSSes (or VAPs) you can get the BSSID mask by - * computing the set of: - * - * ~ ( MAC XOR BSSID ) - * - * When you do this you are essentially computing the common bits. Later it - * is assumed the harware will "and" (&) the BSSID mask with the MAC address - * to obtain the relevant bits which should match on the destination frame. - * - * Simple example: on your card you have have two BSSes you have created with - * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. - * There is another BSSID-03 but you are not part of it. For simplicity's sake, - * assuming only 4 bits for a mac address and for BSSIDs you can then have: - * - * \ - * MAC: 0001 | - * BSSID-01: 0100 | --> Belongs to us - * BSSID-02: 1001 | - * / - * ------------------- - * BSSID-03: 0110 | --> External - * ------------------- - * - * Our bssid_mask would then be: - * - * On loop iteration for BSSID-01: - * ~(0001 ^ 0100) -> ~(0101) - * -> 1010 - * bssid_mask = 1010 - * - * On loop iteration for BSSID-02: - * bssid_mask &= ~(0001 ^ 1001) - * bssid_mask = (1010) & ~(0001 ^ 1001) - * bssid_mask = (1010) & ~(1001) - * bssid_mask = (1010) & (0110) - * bssid_mask = 0010 - * - * A bssid_mask of 0010 means "only pay attention to the second least - * significant bit". This is because its the only bit common - * amongst the MAC and all BSSIDs we support. To findout what the real - * common bit is we can simply "&" the bssid_mask now with any BSSID we have - * or our MAC address (we assume the hardware uses the MAC address). - * - * Now, suppose there's an incoming frame for BSSID-03: - * - * IFRAME-01: 0110 - * - * An easy eye-inspeciton of this already should tell you that this frame - * will not pass our check. This is beacuse the bssid_mask tells the - * hardware to only look at the second least significant bit and the - * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB - * as 1, which does not match 0. - * - * So with IFRAME-01 we *assume* the hardware will do: - * - * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; - * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; - * --> allow = (0010) == 0000 ? 1 : 0; - * --> allow = 0 - * - * Lets now test a frame that should work: - * - * IFRAME-02: 0001 (we should allow) - * - * allow = (0001 & 1010) == 1010 - * - * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; - * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; - * --> allow = (0010) == (0010) - * --> allow = 1 - * - * Other examples: - * - * IFRAME-03: 0100 --> allowed - * IFRAME-04: 1001 --> allowed - * IFRAME-05: 1101 --> allowed but its not for us!!! - * - */ -int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) -{ - u32 low_id, high_id; - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5212) { - low_id = AR5K_LOW_ID(mask); - high_id = AR5K_HIGH_ID(mask); - - ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); - - return 0; - } - - return -EIO; -} - -/* - * Receive start/stop functions - */ - -/* - * Start receive on PCU - */ -void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); - - /* TODO: ANI Support */ -} - -/* - * Stop receive on PCU - */ -void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); - - /* TODO: ANI Support */ -} - -/* - * RX Filter functions - */ - -/* - * Set multicast filter - */ -void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) -{ - ATH5K_TRACE(ah->ah_sc); - /* Set the multicat filter */ - ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); - ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); -} - -/* - * Set multicast filter by index - */ -int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index) -{ - - ATH5K_TRACE(ah->ah_sc); - if (index >= 64) - return -EINVAL; - else if (index >= 32) - AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, - (1 << (index - 32))); - else - AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); - - return 0; -} - -/* - * Clear Multicast filter by index - */ -int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) -{ - - ATH5K_TRACE(ah->ah_sc); - if (index >= 64) - return -EINVAL; - else if (index >= 32) - AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, - (1 << (index - 32))); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); - - return 0; -} - -/* - * Get current rx filter - */ -u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) -{ - u32 data, filter = 0; - - ATH5K_TRACE(ah->ah_sc); - filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); - - /*Radar detection for 5212*/ - if (ah->ah_version == AR5K_AR5212) { - data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); - - if (data & AR5K_PHY_ERR_FIL_RADAR) - filter |= AR5K_RX_FILTER_RADARERR; - if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) - filter |= AR5K_RX_FILTER_PHYERR; - } - - return filter; -} - -/* - * Set rx filter - */ -void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) -{ - u32 data = 0; - - ATH5K_TRACE(ah->ah_sc); - - /* Set PHY error filter register on 5212*/ - if (ah->ah_version == AR5K_AR5212) { - if (filter & AR5K_RX_FILTER_RADARERR) - data |= AR5K_PHY_ERR_FIL_RADAR; - if (filter & AR5K_RX_FILTER_PHYERR) - data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; - } - - /* - * The AR5210 uses promiscous mode to detect radar activity - */ - if (ah->ah_version == AR5K_AR5210 && - (filter & AR5K_RX_FILTER_RADARERR)) { - filter &= ~AR5K_RX_FILTER_RADARERR; - filter |= AR5K_RX_FILTER_PROM; - } - - /*Zero length DMA*/ - if (data) - AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); - - /*Write RX Filter register*/ - ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); - - /*Write PHY error filter register on 5212*/ - if (ah->ah_version == AR5K_AR5212) - ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); - -} - -/* - * Beacon related functions - */ - -/* - * Get a 32bit TSF - */ -u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_TSF_L32); -} - -/* - * Get the full 64bit TSF - */ -u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) -{ - u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); - ATH5K_TRACE(ah->ah_sc); - - return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); -} - -/* - * Force a TSF reset - */ -void ath5k_hw_reset_tsf(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF); -} - -/* - * Initialize beacon timers - */ -void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) -{ - u32 timer1, timer2, timer3; - - ATH5K_TRACE(ah->ah_sc); - /* - * Set the additional timers by mode - */ - switch (ah->ah_op_mode) { - case IEEE80211_IF_TYPE_STA: - if (ah->ah_version == AR5K_AR5210) { - timer1 = 0xffffffff; - timer2 = 0xffffffff; - } else { - timer1 = 0x0000ffff; - timer2 = 0x0007ffff; - } - break; - - default: - timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; - timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; - } - - 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); - ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); - ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); - ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); - - ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | - AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), - AR5K_BEACON); -} - -#if 0 -/* - * Set beacon timers - */ -int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, - const struct ath5k_beacon_state *state) -{ - u32 cfp_period, next_cfp, dtim, interval, next_beacon; - - /* - * TODO: should be changed through *state - * review struct ath5k_beacon_state struct - * - * XXX: These are used for cfp period bellow, are they - * ok ? Is it O.K. for tsf here to be 0 or should we use - * get_tsf ? - */ - u32 dtim_count = 0; /* XXX */ - u32 cfp_count = 0; /* XXX */ - u32 tsf = 0; /* XXX */ - - ATH5K_TRACE(ah->ah_sc); - /* Return on an invalid beacon state */ - if (state->bs_interval < 1) - return -EINVAL; - - interval = state->bs_interval; - dtim = state->bs_dtim_period; - - /* - * PCF support? - */ - if (state->bs_cfp_period > 0) { - /* - * Enable PCF mode and set the CFP - * (Contention Free Period) and timer registers - */ - cfp_period = state->bs_cfp_period * state->bs_dtim_period * - state->bs_interval; - next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * - state->bs_interval; - - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_PCF); - ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); - ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, - AR5K_CFP_DUR); - ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : - next_cfp)) << 3, AR5K_TIMER2); - } else { - /* Disable PCF mode */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_PCF); - } - - /* - * Enable the beacon timer register - */ - ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); - - /* - * Start the beacon timers - */ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~ - (AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | - AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, - AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, - AR5K_BEACON_PERIOD), AR5K_BEACON); - - /* - * Write new beacon miss threshold, if it appears to be valid - * XXX: Figure out right values for min <= bs_bmiss_threshold <= max - * and return if its not in range. We can test this by reading value and - * setting value to a largest value and seeing which values register. - */ - - AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, - state->bs_bmiss_threshold); - - /* - * Set sleep control register - * XXX: Didn't find this in 5210 code but since this register - * exists also in ar5k's 5210 headers i leave it as common code. - */ - AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, - (state->bs_sleep_duration - 3) << 3); - - /* - * Set enhanced sleep registers on 5212 - */ - if (ah->ah_version == AR5K_AR5212) { - if (state->bs_sleep_duration > state->bs_interval && - roundup(state->bs_sleep_duration, interval) == - state->bs_sleep_duration) - interval = state->bs_sleep_duration; - - if (state->bs_sleep_duration > dtim && (dtim == 0 || - roundup(state->bs_sleep_duration, dtim) == - state->bs_sleep_duration)) - dtim = state->bs_sleep_duration; - - if (interval > dtim) - return -EINVAL; - - next_beacon = interval == dtim ? state->bs_next_dtim : - state->bs_next_beacon; - - ath5k_hw_reg_write(ah, - AR5K_REG_SM((state->bs_next_dtim - 3) << 3, - AR5K_SLEEP0_NEXT_DTIM) | - AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | - AR5K_SLEEP0_ENH_SLEEP_EN | - AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); - - ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, - AR5K_SLEEP1_NEXT_TIM) | - AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); - - ath5k_hw_reg_write(ah, - AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | - AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); - } - - return 0; -} - -/* - * Reset beacon timers - */ -void ath5k_hw_reset_beacon(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - /* - * Disable beacon timer - */ - ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); - - /* - * Disable some beacon register values - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); - ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); -} - -/* - * Wait for beacon queue to finish - */ -int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) -{ - unsigned int i; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - /* 5210 doesn't have QCU*/ - if (ah->ah_version == AR5K_AR5210) { - /* - * Wait for beaconn queue to finish by checking - * Control Register and Beacon Status Register. - */ - for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { - if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) - || - !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) - break; - udelay(10); - } - - /* Timeout... */ - if (i <= 0) { - /* - * Re-schedule the beacon queue - */ - ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, - AR5K_BCR); - - return -EIO; - } - ret = 0; - } else { - /*5211/5212*/ - ret = ath5k_hw_register_timeout(ah, - AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), - AR5K_QCU_STS_FRMPENDCNT, 0, false); - - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) - return -EIO; - } - - return ret; -} -#endif - -/* - * Update mib counters (statistics) - */ -void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, - struct ieee80211_low_level_stats *stats) -{ - ATH5K_TRACE(ah->ah_sc); - - /* Read-And-Clear */ - stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); - stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); - stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); - stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); - - /* XXX: Should we use this to track beacon count ? - * -we read it anyway to clear the register */ - ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); - - /* Reset profile count registers on 5212*/ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); - } -} - -/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs - * - * @ah: the &struct ath5k_hw - * @high: determines if to use low bit rate or now - */ -void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) -{ - if (ah->ah_version != AR5K_AR5212) - return; - else { - u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; - if (high) - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); - } -} - - -/* - * ACK/CTS Timeouts - */ - -/* - * Set ACK timeout on PCU - */ -int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) -{ - ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), - ah->ah_turbo) <= timeout) - return -EINVAL; - - AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, - ath5k_hw_htoclock(timeout, ah->ah_turbo)); - - return 0; -} - -/* - * Read the ACK timeout from PCU - */ -unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); -} - -/* - * Set CTS timeout on PCU - */ -int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) -{ - ATH5K_TRACE(ah->ah_sc); - if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), - ah->ah_turbo) <= timeout) - return -EINVAL; - - AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, - ath5k_hw_htoclock(timeout, ah->ah_turbo)); - - return 0; -} - -/* - * Read CTS timeout from PCU - */ -unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); -} - -/* - * Key table (WEP) functions - */ - -int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) -{ - unsigned int i; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); - - /* - * Set NULL encryption on AR5212+ - * - * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) - * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 - * - * Note2: Windows driver (ndiswrapper) sets this to - * 0x00000714 instead of 0x00000007 - */ - if (ah->ah_version > AR5K_AR5211) - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(entry)); - - return 0; -} - -int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - /* Check the validation flag at the end of the entry */ - return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & - AR5K_KEYTABLE_VALID; -} - -int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, - const struct ieee80211_key_conf *key, const u8 *mac) -{ - unsigned int i; - __le32 key_v[5] = {}; - u32 keytype; - - ATH5K_TRACE(ah->ah_sc); - - /* key->keylen comes in from mac80211 in bytes */ - - if (key->keylen > AR5K_KEYTABLE_SIZE / 8) - 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; - - /* 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; - - default: - return -EINVAL; /* shouldn't happen */ - } - - for (i = 0; i < ARRAY_SIZE(key_v); i++) - ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), - AR5K_KEYTABLE_OFF(entry, i)); - - ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); - - return ath5k_hw_set_key_lladdr(ah, entry, mac); -} - -int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) -{ - u32 low_id, high_id; - - ATH5K_TRACE(ah->ah_sc); - /* Invalid entry (key table overflow) */ - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - /* MAC may be NULL if it's a broadcast key. In this case no need to - * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ - if (unlikely(mac == NULL)) { - low_id = 0xffffffff; - high_id = 0xffff | AR5K_KEYTABLE_VALID; - } else { - low_id = AR5K_LOW_ID(mac); - high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; - } - - ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); - ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); - - return 0; -} - - -/********************************************\ -Queue Control Unit, DFS Control Unit Functions -\********************************************/ - -/* - * Initialize a transmit queue - */ -int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, - struct ath5k_txq_info *queue_info) -{ - unsigned int queue; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - /* - * Get queue by type - */ - /*5210 only has 2 queues*/ - if (ah->ah_version == AR5K_AR5210) { - switch (queue_type) { - case AR5K_TX_QUEUE_DATA: - queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; - break; - case AR5K_TX_QUEUE_BEACON: - case AR5K_TX_QUEUE_CAB: - queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON; - break; - default: - return -EINVAL; - } - } else { - switch (queue_type) { - case AR5K_TX_QUEUE_DATA: - for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; - ah->ah_txq[queue].tqi_type != - AR5K_TX_QUEUE_INACTIVE; queue++) { - - if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) - return -EINVAL; - } - break; - case AR5K_TX_QUEUE_UAPSD: - queue = AR5K_TX_QUEUE_ID_UAPSD; - break; - case AR5K_TX_QUEUE_BEACON: - queue = AR5K_TX_QUEUE_ID_BEACON; - break; - case AR5K_TX_QUEUE_CAB: - queue = AR5K_TX_QUEUE_ID_CAB; - break; - case AR5K_TX_QUEUE_XR_DATA: - if (ah->ah_version != AR5K_AR5212) - ATH5K_ERR(ah->ah_sc, - "XR data queues only supported in" - " 5212!\n"); - queue = AR5K_TX_QUEUE_ID_XR_DATA; - break; - default: - return -EINVAL; - } - } - - /* - * Setup internal queue structure - */ - memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info)); - ah->ah_txq[queue].tqi_type = queue_type; - - if (queue_info != NULL) { - queue_info->tqi_type = queue_type; - ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info); - if (ret) - return ret; - } - /* - * We use ah_txq_status to hold a temp value for - * the Secondary interrupt mask registers on 5211+ - * check out ath5k_hw_reset_tx_queue - */ - AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue); - - return queue; -} - -/* - * Setup a transmit queue - */ -int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, - const struct ath5k_txq_info *queue_info) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return -EIO; - - memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); - - /*XXX: Is this supported on 5210 ?*/ - if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && - ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || - (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || - queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) - ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; - - return 0; -} - -/* - * Get properties for a specific transmit queue - */ -int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, - struct ath5k_txq_info *queue_info) -{ - ATH5K_TRACE(ah->ah_sc); - memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); - return 0; -} - -/* - * Set a transmit queue inactive - */ -void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) -{ - ATH5K_TRACE(ah->ah_sc); - if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) - return; - - /* This queue will be skipped in further operations */ - ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; - /*For SIMR setup*/ - AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); -} - -/* - * Set DFS params for a transmit queue - */ -int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) -{ - u32 cw_min, cw_max, retry_lg, retry_sh; - struct ath5k_txq_info *tq = &ah->ah_txq[queue]; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - tq = &ah->ah_txq[queue]; - - if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) - return 0; - - if (ah->ah_version == AR5K_AR5210) { - /* Only handle data queues, others will be ignored */ - if (tq->tqi_type != AR5K_TX_QUEUE_DATA) - return 0; - - /* Set Slot time */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, - AR5K_SLOT_TIME); - /* Set ACK_CTS timeout */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : - AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); - /* Set Transmit Latency */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_TRANSMIT_LATENCY_TURBO : - AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); - /* Set IFS0 */ - if (ah->ah_turbo) - ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + - (ah->ah_aifs + tq->tqi_aifs) * - AR5K_INIT_SLOT_TIME_TURBO) << - AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, - AR5K_IFS0); - else - ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + - (ah->ah_aifs + tq->tqi_aifs) * - AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | - AR5K_INIT_SIFS, AR5K_IFS0); - - /* Set IFS1 */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - AR5K_INIT_PROTO_TIME_CNTRL_TURBO : - AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); - /* Set AR5K_PHY_SETTLING */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) - | 0x38 : - (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) - | 0x1C, - AR5K_PHY_SETTLING); - /* Set Frame Control Register */ - ath5k_hw_reg_write(ah, ah->ah_turbo ? - (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | - AR5K_PHY_TURBO_SHORT | 0x2020) : - (AR5K_PHY_FRAME_CTL_INI | 0x1020), - AR5K_PHY_FRAME_CTL_5210); - } - - /* - * Calculate cwmin/max by channel mode - */ - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; - ah->ah_aifs = AR5K_TUNE_AIFS; - /*XR is only supported on 5212*/ - if (IS_CHAN_XR(ah->ah_current_channel) && - ah->ah_version == AR5K_AR5212) { - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; - ah->ah_aifs = AR5K_TUNE_AIFS_XR; - /*B mode is not supported on 5210*/ - } else if (IS_CHAN_B(ah->ah_current_channel) && - ah->ah_version != AR5K_AR5210) { - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; - ah->ah_aifs = AR5K_TUNE_AIFS_11B; - } - - cw_min = 1; - while (cw_min < ah->ah_cw_min) - cw_min = (cw_min << 1) | 1; - - cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : - ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); - cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : - ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); - - /* - * Calculate and set retry limits - */ - if (ah->ah_software_retry) { - /* XXX Need to test this */ - retry_lg = ah->ah_limit_tx_retries; - retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? - AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; - } else { - retry_lg = AR5K_INIT_LG_RETRY; - retry_sh = AR5K_INIT_SH_RETRY; - } - - /*No QCU/DCU [5210]*/ - if (ah->ah_version == AR5K_AR5210) { - ath5k_hw_reg_write(ah, - (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) - | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_NODCU_RETRY_LMT_SLG_RETRY) - | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_NODCU_RETRY_LMT_SSH_RETRY) - | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) - | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), - AR5K_NODCU_RETRY_LMT); - } else { - /*QCU/DCU [5211+]*/ - ath5k_hw_reg_write(ah, - AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_DCU_RETRY_LMT_SLG_RETRY) | - AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_DCU_RETRY_LMT_SSH_RETRY) | - AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | - AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), - AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); - - /*===Rest is also for QCU/DCU only [5211+]===*/ - - /* - * Set initial content window (cw_min/cw_max) - * and arbitrated interframe space (aifs)... - */ - ath5k_hw_reg_write(ah, - AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | - AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | - AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, - AR5K_DCU_LCL_IFS_AIFS), - AR5K_QUEUE_DFS_LOCAL_IFS(queue)); - - /* - * Set misc registers - */ - ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY, - AR5K_QUEUE_MISC(queue)); - - if (tq->tqi_cbr_period) { - ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, - AR5K_QCU_CBRCFG_INTVAL) | - AR5K_REG_SM(tq->tqi_cbr_overflow_limit, - AR5K_QCU_CBRCFG_ORN_THRES), - AR5K_QUEUE_CBRCFG(queue)); - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_CBR); - if (tq->tqi_cbr_overflow_limit) - AR5K_REG_ENABLE_BITS(ah, - AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_CBR_THRES_ENABLE); - } - - if (tq->tqi_ready_time) - ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, - AR5K_QCU_RDYTIMECFG_INTVAL) | - AR5K_QCU_RDYTIMECFG_ENABLE, - AR5K_QUEUE_RDYTIMECFG(queue)); - - if (tq->tqi_burst_time) { - ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, - AR5K_DCU_CHAN_TIME_DUR) | - AR5K_DCU_CHAN_TIME_ENABLE, - AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) - AR5K_REG_ENABLE_BITS(ah, - AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_RDY_VEOL_POLICY); - } - - if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) - ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, - AR5K_QUEUE_DFS_MISC(queue)); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) - ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, - AR5K_QUEUE_DFS_MISC(queue)); - - /* - * Set registers by queue type - */ - switch (tq->tqi_type) { - case AR5K_TX_QUEUE_BEACON: - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | - AR5K_QCU_MISC_CBREXP_BCN | - AR5K_QCU_MISC_BCN_ENABLE); - - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), - (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << - AR5K_DCU_MISC_ARBLOCK_CTL_S) | - AR5K_DCU_MISC_POST_FR_BKOFF_DIS | - AR5K_DCU_MISC_BCN_ENABLE); - - ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - - (AR5K_TUNE_SW_BEACON_RESP - - AR5K_TUNE_DMA_BEACON_RESP) - - AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | - AR5K_QCU_RDYTIMECFG_ENABLE, - AR5K_QUEUE_RDYTIMECFG(queue)); - break; - - case AR5K_TX_QUEUE_CAB: - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | - AR5K_QCU_MISC_CBREXP | - AR5K_QCU_MISC_CBREXP_BCN); - - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), - (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << - AR5K_DCU_MISC_ARBLOCK_CTL_S)); - break; - - case AR5K_TX_QUEUE_UAPSD: - AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_CBREXP); - break; - - case AR5K_TX_QUEUE_DATA: - default: - break; - } - - /* - * Enable interrupts for this tx queue - * in the secondary interrupt mask registers - */ - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); - - if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) - AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); - - - /* Update secondary interrupt mask registers */ - 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; - - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, - AR5K_SIMR0_QCU_TXOK) | - AR5K_REG_SM(ah->ah_txq_imr_txdesc, - AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, - 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); - } - - return 0; -} - -/* - * Get number of pending frames - * for a specific queue [5211+] - */ -u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - - /* Return if queue is declared inactive */ - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) - return false; - - /* XXX: How about AR5K_CFG_TXCNT ? */ - if (ah->ah_version == AR5K_AR5210) - return false; - - return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT; -} - -/* - * Set slot time - */ -int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) -{ - ATH5K_TRACE(ah->ah_sc); - if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) - return -EINVAL; - - if (ah->ah_version == AR5K_AR5210) - ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, - ah->ah_turbo), AR5K_SLOT_TIME); - else - ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); - - return 0; -} - -/* - * Get slot time - */ -unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_version == AR5K_AR5210) - return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, - AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); - else - return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; -} - - -/******************************\ - Hardware Descriptor Functions -\******************************/ - -/* - * TX Descriptor - */ - -/* - * Initialize the 2-word tx descriptor on 5210/5211 - */ -static int -ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, - unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, - unsigned int key_index, unsigned int antenna_mode, unsigned int flags, - unsigned int rtscts_rate, unsigned int rtscts_duration) -{ - u32 frame_type; - struct ath5k_hw_2w_tx_ctl *tx_ctl; - unsigned int frame_len; - - tx_ctl = &desc->ud.ds_tx5210.tx_ctl; - - /* - * Validate input - * - Zero retries don't make sense. - * - A zero rate will put the HW into a mode where it continously sends - * noise on the channel, so it is important to avoid this. - */ - if (unlikely(tx_tries0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero retries\n"); - WARN_ON(1); - return -EINVAL; - } - if (unlikely(tx_rate0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero rate\n"); - WARN_ON(1); - return -EINVAL; - } - - /* Clear descriptor */ - memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); - - /* Setup control descriptor */ - - /* Verify and set frame length */ - - /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; - - if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) - return -EINVAL; - - tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; - - /* Verify and set buffer length */ - - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - if(type == AR5K_PKT_TYPE_BEACON) - pkt_len = roundup(pkt_len, 4); - - if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) - return -EINVAL; - - tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; - - /* - * Verify and set header length - * XXX: I only found that on 5210 code, does it work on 5211 ? - */ - if (ah->ah_version == AR5K_AR5210) { - if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) - return -EINVAL; - tx_ctl->tx_control_0 |= - AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); - } - - /*Diferences between 5210-5211*/ - if (ah->ah_version == AR5K_AR5210) { - switch (type) { - case AR5K_PKT_TYPE_BEACON: - case AR5K_PKT_TYPE_PROBE_RESP: - frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; - case AR5K_PKT_TYPE_PIFS: - frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; - default: - frame_type = type /*<< 2 ?*/; - } - - tx_ctl->tx_control_0 |= - AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | - AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); - } else { - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | - AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= - AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); - } -#define _TX_FLAGS(_c, _flag) \ - if (flags & AR5K_TXDESC_##_flag) \ - tx_ctl->tx_control_##_c |= \ - AR5K_2W_TX_DESC_CTL##_c##_##_flag - - _TX_FLAGS(0, CLRDMASK); - _TX_FLAGS(0, VEOL); - _TX_FLAGS(0, INTREQ); - _TX_FLAGS(0, RTSENA); - _TX_FLAGS(1, NOACK); - -#undef _TX_FLAGS - - /* - * WEP crap - */ - if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= - AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= - AR5K_REG_SM(key_index, - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); - } - - /* - * RTS/CTS Duration [5210 ?] - */ - if ((ah->ah_version == AR5K_AR5210) && - (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) - tx_ctl->tx_control_1 |= rtscts_duration & - AR5K_2W_TX_DESC_CTL1_RTS_DURATION; - - return 0; -} - -/* - * Initialize the 4-word tx descriptor on 5212 - */ -static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, - struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, - enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, - unsigned int tx_tries0, unsigned int key_index, - unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, - unsigned int rtscts_duration) -{ - struct ath5k_hw_4w_tx_ctl *tx_ctl; - unsigned int frame_len; - - ATH5K_TRACE(ah->ah_sc); - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; - - /* - * Validate input - * - Zero retries don't make sense. - * - A zero rate will put the HW into a mode where it continously sends - * noise on the channel, so it is important to avoid this. - */ - if (unlikely(tx_tries0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero retries\n"); - WARN_ON(1); - return -EINVAL; - } - if (unlikely(tx_rate0 == 0)) { - ATH5K_ERR(ah->ah_sc, "zero rate\n"); - WARN_ON(1); - return -EINVAL; - } - - /* Clear descriptor */ - memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); - - /* Setup control descriptor */ - - /* Verify and set frame length */ - - /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; - - if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) - return -EINVAL; - - tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; - - /* Verify and set buffer length */ - - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - if(type == AR5K_PKT_TYPE_BEACON) - pkt_len = roundup(pkt_len, 4); - - if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) - return -EINVAL; - - tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; - - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | - AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= AR5K_REG_SM(type, - AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); - tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - -#define _TX_FLAGS(_c, _flag) \ - if (flags & AR5K_TXDESC_##_flag) \ - tx_ctl->tx_control_##_c |= \ - AR5K_4W_TX_DESC_CTL##_c##_##_flag - - _TX_FLAGS(0, CLRDMASK); - _TX_FLAGS(0, VEOL); - _TX_FLAGS(0, INTREQ); - _TX_FLAGS(0, RTSENA); - _TX_FLAGS(0, CTSENA); - _TX_FLAGS(1, NOACK); - -#undef _TX_FLAGS - - /* - * WEP crap - */ - if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, - AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); - } - - /* - * RTS/CTS - */ - if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { - if ((flags & AR5K_TXDESC_RTSENA) && - (flags & AR5K_TXDESC_CTSENA)) - return -EINVAL; - tx_ctl->tx_control_2 |= rtscts_duration & - AR5K_4W_TX_DESC_CTL2_RTS_DURATION; - tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, - AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); - } - - return 0; -} - -/* - * Initialize a 4-word multirate tx descriptor on 5212 - */ -static int -ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, - unsigned int tx_rate3, u_int tx_tries3) -{ - struct ath5k_hw_4w_tx_ctl *tx_ctl; - - /* - * Rates can be 0 as long as the retry count is 0 too. - * A zero rate and nonzero retry count will put the HW into a mode where - * it continously sends noise on the channel, so it is important to - * avoid this. - */ - if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || - (tx_rate2 == 0 && tx_tries2 != 0) || - (tx_rate3 == 0 && tx_tries3 != 0))) { - ATH5K_ERR(ah->ah_sc, "zero rate\n"); - WARN_ON(1); - return -EINVAL; - } - - if (ah->ah_version == AR5K_AR5212) { - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; - -#define _XTX_TRIES(_n) \ - if (tx_tries##_n) { \ - tx_ctl->tx_control_2 |= \ - AR5K_REG_SM(tx_tries##_n, \ - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ - tx_ctl->tx_control_3 |= \ - AR5K_REG_SM(tx_rate##_n, \ - AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ - } - - _XTX_TRIES(1); - _XTX_TRIES(2); - _XTX_TRIES(3); - -#undef _XTX_TRIES - - return 1; - } - - return 0; -} - -/* - * Proccess the tx status descriptor on 5210/5211 - */ -static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_tx_status *ts) -{ - struct ath5k_hw_2w_tx_ctl *tx_ctl; - struct ath5k_hw_tx_status *tx_status; - - ATH5K_TRACE(ah->ah_sc); - - tx_ctl = &desc->ud.ds_tx5210.tx_ctl; - tx_status = &desc->ud.ds_tx5210.tx_stat; - - /* No frame has been send or error */ - if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) - return -EINPROGRESS; - - /* - * Get descriptor status - */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - /*TODO: ts->ts_virtcol + test*/ - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = 1; - ts->ts_status = 0; - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, - AR5K_2W_TX_DESC_CTL0_XMIT_RATE); - - if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) - ts->ts_status |= AR5K_TXERR_XRETRY; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) - ts->ts_status |= AR5K_TXERR_FIFO; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) - ts->ts_status |= AR5K_TXERR_FILT; - } - - return 0; -} - -/* - * Proccess a tx descriptor on 5212 - */ -static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_tx_status *ts) -{ - struct ath5k_hw_4w_tx_ctl *tx_ctl; - struct ath5k_hw_tx_status *tx_status; - - ATH5K_TRACE(ah->ah_sc); - - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; - tx_status = &desc->ud.ds_tx5212.tx_stat; - - /* No frame has been send or error */ - if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) - return -EINPROGRESS; - - /* - * Get descriptor status - */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, - AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = (tx_status->tx_status_1 & - AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; - ts->ts_status = 0; - - switch (AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { - case 0: - ts->ts_rate = tx_ctl->tx_control_3 & - AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - break; - case 1: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - break; - case 2: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); - break; - case 3: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); - break; - } - - if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) - ts->ts_status |= AR5K_TXERR_XRETRY; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) - ts->ts_status |= AR5K_TXERR_FIFO; - - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) - ts->ts_status |= AR5K_TXERR_FILT; - } - - return 0; -} - -/* - * RX Descriptor - */ - -/* - * Initialize an rx descriptor - */ -int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - u32 size, unsigned int flags) -{ - struct ath5k_hw_rx_ctl *rx_ctl; - - ATH5K_TRACE(ah->ah_sc); - rx_ctl = &desc->ud.ds_rx.rx_ctl; - - /* - * Clear the descriptor - * If we don't clean the status descriptor, - * while scanning we get too many results, - * most of them virtual, after some secs - * of scanning system hangs. M.F. - */ - memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); - - /* Setup descriptor */ - rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; - if (unlikely(rx_ctl->rx_control_1 != size)) - return -EINVAL; - - if (flags & AR5K_RXDESC_INTREQ) - rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; - - return 0; -} - -/* - * Proccess the rx status descriptor on 5210/5211 - */ -static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_rx_status *rs) -{ - struct ath5k_hw_rx_status *rx_status; - - rx_status = &desc->ud.ds_rx.u.rx_stat; - - /* No frame received / not ready */ - if (unlikely((rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE) - == 0)) - return -EINPROGRESS; - - /* - * Frame receive status - */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5210_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = rx_status->rx_status_0 & - AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA; - rs->rs_more = rx_status->rx_status_0 & - AR5K_5210_RX_DESC_STATUS0_MORE; - /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - rs->rs_status = 0; - rs->rs_phyerr = 0; - - /* - * Key table status - */ - if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5210_RX_DESC_STATUS1_KEY_INDEX); - else - rs->rs_keyix = AR5K_RXKEYIX_INVALID; - - /* - * Receive/descriptor errors - */ - if ((rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_CRC; - - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) - rs->rs_status |= AR5K_RXERR_FIFO; - - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { - rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); - } - - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_DECRYPT; - } - - return 0; -} - -/* - * Proccess the rx status descriptor on 5212 - */ -static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_rx_status *rs) -{ - struct ath5k_hw_rx_status *rx_status; - struct ath5k_hw_rx_error *rx_err; - - ATH5K_TRACE(ah->ah_sc); - rx_status = &desc->ud.ds_rx.u.rx_stat; - - /* Overlay on error */ - rx_err = &desc->ud.ds_rx.u.rx_err; - - /* No frame received / not ready */ - if (unlikely((rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE) - == 0)) - return -EINPROGRESS; - - /* - * Frame receive status - */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA; - rs->rs_more = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_MORE; - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - rs->rs_status = 0; - rs->rs_phyerr = 0; - - /* - * Key table status - */ - if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); - else - rs->rs_keyix = AR5K_RXKEYIX_INVALID; - - /* - * Receive/descriptor errors - */ - if ((rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_CRC; - - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { - rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, - AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); - } - - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) - rs->rs_status |= AR5K_RXERR_DECRYPT; - - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) - rs->rs_status |= AR5K_RXERR_MIC; - } - - return 0; -} - - -/****************\ - GPIO Functions -\****************/ - -/* - * Set led state - */ -void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) -{ - u32 led; - /*5210 has different led mode handling*/ - u32 led_5210; - - ATH5K_TRACE(ah->ah_sc); - - /*Reset led status*/ - if (ah->ah_version != AR5K_AR5210) - AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, - AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); - - /* - * Some blinking values, define at your wish - */ - switch (state) { - case AR5K_LED_SCAN: - case AR5K_LED_AUTH: - led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; - led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; - break; - - case AR5K_LED_INIT: - led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; - led_5210 = AR5K_PCICFG_LED_PEND; - break; - - case AR5K_LED_ASSOC: - case AR5K_LED_RUN: - led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; - led_5210 = AR5K_PCICFG_LED_ASSOC; - break; - - default: - led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; - led_5210 = AR5K_PCICFG_LED_PEND; - break; - } - - /*Write new status to the register*/ - if (ah->ah_version != AR5K_AR5210) - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); - else - AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); -} - -/* - * Set GPIO outputs - */ -int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) -{ - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return -EINVAL; - - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ - AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); - - return 0; -} - -/* - * Set GPIO inputs - */ -int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) -{ - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return -EINVAL; - - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ - AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); - - return 0; -} - -/* - * Get GPIO state - */ -u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) -{ - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return 0xffffffff; - - /* GPIO input magic */ - return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & - 0x1; -} - -/* - * Set GPIO state - */ -int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) -{ - u32 data; - ATH5K_TRACE(ah->ah_sc); - - if (gpio > AR5K_NUM_GPIO) - return -EINVAL; - - /* GPIO output magic */ - data = ath5k_hw_reg_read(ah, AR5K_GPIODO); - - data &= ~(1 << gpio); - data |= (val & 1) << gpio; - - ath5k_hw_reg_write(ah, data, AR5K_GPIODO); - - return 0; -} - -/* - * Initialize the GPIO interrupt (RFKill switch) - */ -void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, - u32 interrupt_level) -{ - u32 data; - - ATH5K_TRACE(ah->ah_sc); - if (gpio > AR5K_NUM_GPIO) - return; - - /* - * Set the GPIO interrupt - */ - data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & - ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | - AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | - (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); - - ath5k_hw_reg_write(ah, interrupt_level ? data : - (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); - - ah->ah_imr |= AR5K_IMR_GPIO; - - /* Enable GPIO interrupts */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); -} - - - - -/****************\ - Misc functions -\****************/ - -int ath5k_hw_get_capability(struct ath5k_hw *ah, - enum ath5k_capability_type cap_type, - u32 capability, u32 *result) -{ - ATH5K_TRACE(ah->ah_sc); - - switch (cap_type) { - case AR5K_CAP_NUM_TXQUEUES: - if (result) { - if (ah->ah_version == AR5K_AR5210) - *result = AR5K_NUM_TX_QUEUES_NOQCU; - else - *result = AR5K_NUM_TX_QUEUES; - goto yes; - } - case AR5K_CAP_VEOL: - goto yes; - case AR5K_CAP_COMPRESSION: - if (ah->ah_version == AR5K_AR5212) - goto yes; - else - goto no; - case AR5K_CAP_BURST: - goto yes; - case AR5K_CAP_TPC: - goto yes; - case AR5K_CAP_BSSIDMASK: - if (ah->ah_version == AR5K_AR5212) - goto yes; - else - goto no; - case AR5K_CAP_XR: - if (ah->ah_version == AR5K_AR5212) - goto yes; - else - goto no; - default: - goto no; - } - -no: - return -EINVAL; -yes: - return 0; -} - -static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, - u16 assoc_id) -{ - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); - return 0; - } - - return -EIO; -} - -static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5210) { - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); - return 0; - } - - return -EIO; -} diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h deleted file mode 100644 index 64fca8dcb38..00000000000 --- a/drivers/net/wireless/ath5k/hw.h +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (c) 2004-2007 Reyk Floeter - * Copyright (c) 2006-2007 Nick Kossifidis - * Copyright (c) 2007 Matthew W. S. Bell - * Copyright (c) 2007 Luis Rodriguez - * - * Permission to use, copy, modify, and 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 - -/* - * Gain settings - */ - -enum ath5k_rfgain { - AR5K_RFGAIN_INACTIVE = 0, - AR5K_RFGAIN_READ_REQUESTED, - AR5K_RFGAIN_NEED_CHANGE, -}; - -#define AR5K_GAIN_CRN_FIX_BITS_5111 4 -#define AR5K_GAIN_CRN_FIX_BITS_5112 7 -#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112 -#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15 -#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20 -#define AR5K_GAIN_CCK_PROBE_CORR 5 -#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15 -#define AR5K_GAIN_STEP_COUNT 10 -#define AR5K_GAIN_PARAM_TX_CLIP 0 -#define AR5K_GAIN_PARAM_PD_90 1 -#define AR5K_GAIN_PARAM_PD_84 2 -#define AR5K_GAIN_PARAM_GAIN_SEL 3 -#define AR5K_GAIN_PARAM_MIX_ORN 0 -#define AR5K_GAIN_PARAM_PD_138 1 -#define AR5K_GAIN_PARAM_PD_137 2 -#define AR5K_GAIN_PARAM_PD_136 3 -#define AR5K_GAIN_PARAM_PD_132 4 -#define AR5K_GAIN_PARAM_PD_131 5 -#define AR5K_GAIN_PARAM_PD_130 6 -#define AR5K_GAIN_CHECK_ADJUST(_g) \ - ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) - -struct ath5k_gain_opt_step { - s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; - s32 gos_gain; -}; - -struct ath5k_gain { - u32 g_step_idx; - u32 g_current; - u32 g_target; - u32 g_low; - u32 g_high; - u32 g_f_corr; - u32 g_active; - const struct ath5k_gain_opt_step *g_step; -}; - - -/* - * HW SPECIFIC STRUCTS - */ - -/* Some EEPROM defines */ -#define AR5K_EEPROM_EEP_SCALE 100 -#define AR5K_EEPROM_EEP_DELTA 10 -#define AR5K_EEPROM_N_MODES 3 -#define AR5K_EEPROM_N_5GHZ_CHAN 10 -#define AR5K_EEPROM_N_2GHZ_CHAN 3 -#define AR5K_EEPROM_MAX_CHAN 10 -#define AR5K_EEPROM_N_PCDAC 11 -#define AR5K_EEPROM_N_TEST_FREQ 8 -#define AR5K_EEPROM_N_EDGES 8 -#define AR5K_EEPROM_N_INTERCEPTS 11 -#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) -#define AR5K_EEPROM_PCDAC_M 0x3f -#define AR5K_EEPROM_PCDAC_START 1 -#define AR5K_EEPROM_PCDAC_STOP 63 -#define AR5K_EEPROM_PCDAC_STEP 1 -#define AR5K_EEPROM_NON_EDGE_M 0x40 -#define AR5K_EEPROM_CHANNEL_POWER 8 -#define AR5K_EEPROM_N_OBDB 4 -#define AR5K_EEPROM_OBDB_DIS 0xffff -#define AR5K_EEPROM_CHANNEL_DIS 0xff -#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) -#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) -#define AR5K_EEPROM_MAX_CTLS 32 -#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_INTERCEPT_10_2GHZ 35 -#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 -#define AR5K_EEPROM_POWER_M 0x3f -#define AR5K_EEPROM_POWER_MIN 0 -#define AR5K_EEPROM_POWER_MAX 3150 -#define AR5K_EEPROM_POWER_STEP 50 -#define AR5K_EEPROM_POWER_TABLE_SIZE 64 -#define AR5K_EEPROM_N_POWER_LOC_11B 4 -#define AR5K_EEPROM_N_POWER_LOC_11G 6 -#define AR5K_EEPROM_I_GAIN 10 -#define AR5K_EEPROM_CCK_OFDM_DELTA 15 -#define AR5K_EEPROM_N_IQ_CAL 2 - -/* Struct to hold EEPROM calibration data */ -struct ath5k_eeprom_info { - u16 ee_magic; - u16 ee_protect; - u16 ee_regdomain; - u16 ee_version; - u16 ee_header; - u16 ee_ant_gain; - u16 ee_misc0; - u16 ee_misc1; - u16 ee_cck_ofdm_gain_delta; - u16 ee_cck_ofdm_power_delta; - u16 ee_scaled_cck_delta; - - /* Used for tx thermal adjustment (eeprom_init, rfregs) */ - u16 ee_tx_clip; - u16 ee_pwd_84; - u16 ee_pwd_90; - u16 ee_gain_select; - - /* RF Calibration settings (reset, rfregs) */ - u16 ee_i_cal[AR5K_EEPROM_N_MODES]; - u16 ee_q_cal[AR5K_EEPROM_N_MODES]; - u16 ee_fixed_bias[AR5K_EEPROM_N_MODES]; - 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_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]; - u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; - u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; - u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; - u16 ee_thr_62[AR5K_EEPROM_N_MODES]; - u16 ee_xlna_gain[AR5K_EEPROM_N_MODES]; - u16 ee_xpd[AR5K_EEPROM_N_MODES]; - 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]; - - /* Unused */ - 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*/ - - /* Conformance test limits (Unused) */ - u16 ee_ctls; - u16 ee_ctl[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]; -}; - -/* - * Internal RX/TX descriptor structures - * (rX: reserved fields possibily used by future versions of the ar5k chipset) - */ - -/* - * common hardware RX control descriptor - */ -struct ath5k_hw_rx_ctl { - u32 rx_control_0; /* RX control word 0 */ - -#define AR5K_DESC_RX_CTL0 0x00000000 - - u32 rx_control_1; /* RX control word 1 */ - -#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff -#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 -} __packed; - -/* - * common hardware RX status descriptor - * 5210/11 and 5212 differ only in the flags defined below - */ -struct ath5k_hw_rx_status { - u32 rx_status_0; /* RX status word 0 */ - u32 rx_status_1; /* RX status word 1 */ -} __packed; - -/* 5210/5211 */ -#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff -#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 -#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 -#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 -#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 -#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 -#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 -#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 -#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 -#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 -#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 - -/* 5212 */ -#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff -#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 -#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 -#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 -#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 -#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 -#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 -#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 -#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 -#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 -#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 - -/* - * common hardware RX error descriptor - */ -struct ath5k_hw_rx_error { - u32 rx_error_0; /* RX error word 0 */ - -#define AR5K_RX_DESC_ERROR0 0x00000000 - - u32 rx_error_1; /* RX error word 1 */ - -#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 -#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 -} __packed; - -#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 -#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 -#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 -#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 -#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 -#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 -#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 -#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 - -/* - * 5210/5211 hardware 2-word TX control descriptor - */ -struct ath5k_hw_2w_tx_ctl { - u32 tx_control_0; /* TX control word 0 */ - -#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff -#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/ -#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12 -#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 -#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 -#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 -#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 -#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ -#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ -#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26 -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT (ah->ah_version == AR5K_AR5210 ? \ - AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ - AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 -#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 -#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 - - u32 tx_control_1; /* TX control word 1 */ - -#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff -#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000 -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000 -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX (ah->ah_version == AR5K_AR5210 ? \ - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 -#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20 -#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/ -} __packed; - -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 - -/* - * 5212 hardware 4-word TX control descriptor - */ -struct ath5k_hw_4w_tx_ctl { - u32 tx_control_0; /* TX control word 0 */ - -#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff -#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 -#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 -#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 -#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 -#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 -#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 -#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 -#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 -#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 -#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 - - u32 tx_control_1; /* TX control word 1 */ - -#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff -#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 -#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 -#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 -#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 -#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 -#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 -#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 -#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 - - u32 tx_control_2; /* TX control word 2 */ - -#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff -#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 - - u32 tx_control_3; /* TX control word 3 */ - -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 -#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 -#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 -} __packed; - -/* - * Common TX status descriptor - */ -struct ath5k_hw_tx_status { - u32 tx_status_0; /* TX status word 0 */ - -#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 -#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 -#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 -#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 -/*??? -#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 -#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 -*/ -#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 -#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 -/*??? -#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 -#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 -*/ -#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 -#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 -#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 -#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 -#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 -#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 - - u32 tx_status_1; /* TX status word 1 */ - -#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 -#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe -#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1 -#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 -#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 -#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 -#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21 -#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000 -#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000 -} __packed; - - -/* - * 5210/5211 hardware TX descriptor - */ -struct ath5k_hw_5210_tx_desc { - struct ath5k_hw_2w_tx_ctl tx_ctl; - struct ath5k_hw_tx_status tx_stat; -} __packed; - -/* - * 5212 hardware TX descriptor - */ -struct ath5k_hw_5212_tx_desc { - struct ath5k_hw_4w_tx_ctl tx_ctl; - struct ath5k_hw_tx_status tx_stat; -} __packed; - -/* - * common hardware RX descriptor - */ -struct ath5k_hw_all_rx_desc { - struct ath5k_hw_rx_ctl rx_ctl; - union { - struct ath5k_hw_rx_status rx_stat; - struct ath5k_hw_rx_error rx_err; - } u; -} __packed; - - -/* - * AR5K REGISTER ACCESS - */ - -/*Swap RX/TX Descriptor for big endian archs*/ -#if defined(__BIG_ENDIAN) -#define AR5K_INIT_CFG ( \ - AR5K_CFG_SWTD | AR5K_CFG_SWRD \ -) -#else -#define AR5K_INIT_CFG 0x00000000 -#endif - -/*#define AR5K_REG_READ(_reg) ath5k_hw_reg_read(ah, _reg) - -#define AR5K_REG_WRITE(_reg, _val) ath5k_hw_reg_write(ah, _val, _reg)*/ - -#define AR5K_REG_SM(_val, _flags) \ - (((_val) << _flags##_S) & (_flags)) - -#define AR5K_REG_MS(_val, _flags) \ - (((_val) & (_flags)) >> _flags##_S) - -/* Some registers can hold multiple values of interest. For this - * reason when we want to write to these registers we must first - * retrieve the values which we do not want to clear (lets call this - * old_data) and then set the register with this and our new_value: - * ( old_data | new_value) */ -#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \ - (((_val) << _flags##_S) & (_flags)), _reg) - -#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \ - (_mask)) | (_flags), _reg) - -#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \ - ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg) - -#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ - ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) - -#define AR5K_PHY_WRITE(ah, _reg, _val) \ - ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) - -#define AR5K_PHY_READ(ah, _reg) \ - ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) - -#define AR5K_REG_WAIT(_i) do { \ - if (_i % 64) \ - udelay(1); \ -} while (0) - -#define AR5K_EEPROM_READ(_o, _v) do { \ - if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0) \ - return (ret); \ -} while (0) - -#define AR5K_EEPROM_READ_HDR(_o, _v) \ - AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ - -/* Read status of selected queue */ -#define AR5K_REG_READ_Q(ah, _reg, _queue) \ - (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ - -#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \ - ath5k_hw_reg_write(ah, (1 << _queue), _reg) - -#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \ - _reg |= 1 << _queue; \ -} while (0) - -#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \ - _reg &= ~(1 << _queue); \ -} while (0) - -#define AR5K_LOW_ID(_a)( \ -(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ -) - -#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) - -/* - * Initial register values - */ - -/* - * Common initial register values - */ -#define AR5K_INIT_MODE CHANNEL_B - -#define AR5K_INIT_TX_LATENCY 502 -#define AR5K_INIT_USEC 39 -#define AR5K_INIT_USEC_TURBO 79 -#define AR5K_INIT_USEC_32 31 -#define AR5K_INIT_CARR_SENSE_EN 1 -#define AR5K_INIT_PROG_IFS 920 -#define AR5K_INIT_PROG_IFS_TURBO 960 -#define AR5K_INIT_EIFS 3440 -#define AR5K_INIT_EIFS_TURBO 6880 -#define AR5K_INIT_SLOT_TIME 396 -#define AR5K_INIT_SLOT_TIME_TURBO 480 -#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 -#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 -#define AR5K_INIT_SIFS 560 -#define AR5K_INIT_SIFS_TURBO 480 -#define AR5K_INIT_SH_RETRY 10 -#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY -#define AR5K_INIT_SSH_RETRY 32 -#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY -#define AR5K_INIT_TX_RETRY 10 -#define AR5K_INIT_TOPS 8 -#define AR5K_INIT_RXNOFRM 8 -#define AR5K_INIT_RPGTO 0 -#define AR5K_INIT_TXNOFRM 0 -#define AR5K_INIT_BEACON_PERIOD 65535 -#define AR5K_INIT_TIM_OFFSET 0 -#define AR5K_INIT_BEACON_EN 0 -#define AR5K_INIT_RESET_TSF 0 - -#define AR5K_INIT_TRANSMIT_LATENCY ( \ - (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ - (AR5K_INIT_USEC) \ -) -#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ - (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ - (AR5K_INIT_USEC_TURBO) \ -) -#define AR5K_INIT_PROTO_TIME_CNTRL ( \ - (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ - (AR5K_INIT_PROG_IFS) \ -) -#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ - (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \ - (AR5K_INIT_PROG_IFS_TURBO) \ -) -#define AR5K_INIT_BEACON_CONTROL ( \ - (AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) | \ - (AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD) \ -) - -/* - * Non-common initial register values which have to be loaded into the - * card at boot time and after each reset. - */ - -/* Register dumps are done per operation mode */ -#define AR5K_INI_RFGAIN_5GHZ 0 -#define AR5K_INI_RFGAIN_2GHZ 1 - -#define AR5K_INI_VAL_11A 0 -#define AR5K_INI_VAL_11A_TURBO 1 -#define AR5K_INI_VAL_11B 2 -#define AR5K_INI_VAL_11G 3 -#define AR5K_INI_VAL_11G_TURBO 4 -#define AR5K_INI_VAL_XR 0 -#define AR5K_INI_VAL_MAX 5 - -#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS -#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS - -static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) -{ - u32 retval = 0, bit, i; - - for (i = 0; i < bits; i++) { - bit = (val >> i) & 1; - retval = (retval << 1) | bit; - } - - return retval; -} diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index 2806b21bf90..ea2e1a20b49 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -1,9 +1,9 @@ /* * Initial register settings functions * - * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter - * Copyright (c) 2006, 2007 Nick Kossifidis - * Copyright (c) 2007 Jiri Slaby + * Copyright (c) 2004-2007 Reyk Floeter + * Copyright (c) 2006-2007 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,13 +20,9 @@ */ #include "ath5k.h" -#include "base.h" #include "reg.h" - -/* - * MAC/PHY REGISTERS - */ - +#include "debug.h" +#include "base.h" /* * Mode-independent initial register writes @@ -65,10 +61,10 @@ static const struct ath5k_ini ar5210_ini[] = { { AR5K_TXCFG, AR5K_DMASIZE_128B }, { AR5K_RXCFG, AR5K_DMASIZE_128B }, { AR5K_CFG, AR5K_INIT_CFG }, - { AR5K_TOPS, AR5K_INIT_TOPS }, - { AR5K_RXNOFRM, AR5K_INIT_RXNOFRM }, - { AR5K_RPGTO, AR5K_INIT_RPGTO }, - { AR5K_TXNOFRM, AR5K_INIT_TXNOFRM }, + { AR5K_TOPS, 8 }, + { AR5K_RXNOFRM, 8 }, + { AR5K_RPGTO, 0 }, + { AR5K_TXNOFRM, 0 }, { AR5K_SFR, 0 }, { AR5K_MIBC, 0 }, { AR5K_MISC, 0 }, diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c new file mode 100644 index 00000000000..5a896d1e2a2 --- /dev/null +++ b/drivers/net/wireless/ath5k/pcu.c @@ -0,0 +1,1002 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Matthew W. S. Bell + * Copyright (c) 2007-2008 Luis Rodriguez + * Copyright (c) 2007-2008 Pavel Roskin + * Copyright (c) 2007-2008 Jiri Slaby + * + * Permission to use, copy, modify, and 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. + * + */ + +/*********************************\ +* Protocol Control Unit Functions * +\*********************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/*******************\ +* Generic functions * +\*******************/ + +/** + * ath5k_hw_set_opmode - Set PCU operating mode + * + * @ah: The &struct ath5k_hw + * + * Initialize PCU for the various operating modes (AP/STA etc) + * + * NOTE: ah->ah_op_mode must be set before calling this. + */ +int ath5k_hw_set_opmode(struct ath5k_hw *ah) +{ + u32 pcu_reg, beacon_reg, low_id, high_id; + + pcu_reg = 0; + beacon_reg = 0; + + ATH5K_TRACE(ah->ah_sc); + + switch (ah->ah_op_mode) { + case IEEE80211_IF_TYPE_IBSS: + pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + beacon_reg |= AR5K_BCR_ADHOC; + break; + + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_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); + beacon_reg |= AR5K_BCR_AP; + break; + + case IEEE80211_IF_TYPE_STA: + pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_PWR_SV : 0); + case IEEE80211_IF_TYPE_MNTR: + pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + break; + + default: + return -EINVAL; + } + + /* + * Set PCU registers + */ + low_id = AR5K_LOW_ID(ah->ah_sta_id); + high_id = AR5K_HIGH_ID(ah->ah_sta_id); + ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); + ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); + + /* + * Set Beacon Control Register on 5210 + */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); + + return 0; +} + +/** + * ath5k_hw_update - Update mib counters (mac layer statistics) + * + * @ah: The &struct ath5k_hw + * @stats: The &struct ieee80211_low_level_stats we use to track + * statistics on the driver + * + * Reads MIB counters from PCU and updates sw statistics. Must be + * called after a MIB interrupt. + */ +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, + struct ieee80211_low_level_stats *stats) +{ + ATH5K_TRACE(ah->ah_sc); + + /* Read-And-Clear */ + stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); + stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); + stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); + stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); + + /* XXX: Should we use this to track beacon count ? + * -we read it anyway to clear the register */ + ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); + + /* Reset profile count registers on 5212*/ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); + } +} + +/** + * ath5k_hw_set_ack_bitrate - set bitrate for ACKs + * + * @ah: The &struct ath5k_hw + * @high: Flag to determine if we want to use high transmition rate + * for ACKs or not + * + * If high flag is set, we tell hw to use a set of control rates based on + * the current transmition rate (check out control_rates array inside reset.c). + * If not hw just uses the lowest rate available for the current modulation + * scheme being used (1Mbit for CCK and 6Mbits for OFDM). + */ +void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) +{ + if (ah->ah_version != AR5K_AR5212) + return; + else { + u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; + if (high) + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); + } +} + + +/******************\ +* ACK/CTS Timeouts * +\******************/ + +/** + * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); +} + +/** + * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU + * + * @ah: The &struct ath5k_hw + * @timeout: Timeout in usec + */ +int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) +{ + ATH5K_TRACE(ah->ah_sc); + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), + ah->ah_turbo) <= timeout) + return -EINVAL; + + AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, + ath5k_hw_htoclock(timeout, ah->ah_turbo)); + + return 0; +} + +/** + * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec + * + * @ah: The &struct ath5k_hw + */ +unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); +} + +/** + * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU + * + * @ah: The &struct ath5k_hw + * @timeout: Timeout in usec + */ +int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) +{ + ATH5K_TRACE(ah->ah_sc); + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), + ah->ah_turbo) <= timeout) + return -EINVAL; + + AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, + ath5k_hw_htoclock(timeout, ah->ah_turbo)); + + return 0; +} + + +/****************\ +* BSSID handling * +\****************/ + +/** + * ath5k_hw_get_lladdr - Get station id + * + * @ah: The &struct ath5k_hw + * @mac: The card's mac address + * + * Initialize ah->ah_sta_id using the mac address provided + * (just a memcpy). + * + * TODO: Remove it once we merge ath5k_softc and ath5k_hw + */ +void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) +{ + ATH5K_TRACE(ah->ah_sc); + memcpy(mac, ah->ah_sta_id, ETH_ALEN); +} + +/** + * ath5k_hw_set_lladdr - Set station id + * + * @ah: The &struct ath5k_hw + * @mac: The card's mac address + * + * Set station id on hw using the provided mac address + */ +int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) +{ + u32 low_id, high_id; + + ATH5K_TRACE(ah->ah_sc); + /* Set new station ID */ + memcpy(ah->ah_sta_id, mac, ETH_ALEN); + + 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); + + return 0; +} + +/** + * ath5k_hw_set_associd - Set BSSID for association + * + * @ah: The &struct ath5k_hw + * @bssid: BSSID + * @assoc_id: Assoc id + * + * Sets the BSSID which trigers the "SME Join" operation + */ +void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) +{ + u32 low_id, high_id; + u16 tim_offset = 0; + + /* + * 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); + } + + /* + * Set BSSID which triggers the "SME Join" operation + */ + low_id = AR5K_LOW_ID(bssid); + high_id = AR5K_HIGH_ID(bssid); + ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); + ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << + AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); + + if (assoc_id == 0) { + ath5k_hw_disable_pspoll(ah); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, + tim_offset ? tim_offset + 4 : 0); + + ath5k_hw_enable_pspoll(ah, NULL, 0); +} + +/** + * ath5k_hw_set_bssid_mask - filter out bssids we listen + * + * @ah: the &struct ath5k_hw + * @mask: the bssid_mask, a u8 array of size ETH_ALEN + * + * BSSID masking is a method used by AR5212 and newer hardware to inform PCU + * which bits of the interface's MAC address should be looked at when trying + * to decide which packets to ACK. In station mode and AP mode with a single + * BSS every bit matters since we lock to only one BSS. In AP mode with + * multiple BSSes (virtual interfaces) not every bit matters because hw must + * accept frames for all BSSes and so we tweak some bits of our mac address + * in order to have multiple BSSes. + * + * NOTE: This is a simple filter and does *not* filter out all + * relevant frames. Some frames that are not for us might get ACKed from us + * by PCU because they just match the mask. + * + * When handling multiple BSSes you can get the BSSID mask by computing the + * set of ~ ( MAC XOR BSSID ) for all bssids we handle. + * + * When you do this you are essentially computing the common bits of all your + * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with + * the MAC address to obtain the relevant bits and compare the result with + * (frame's BSSID & mask) to see if they match. + */ +/* + * Simple example: on your card you have have two BSSes you have created with + * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. + * There is another BSSID-03 but you are not part of it. For simplicity's sake, + * assuming only 4 bits for a mac address and for BSSIDs you can then have: + * + * \ + * MAC: 0001 | + * BSSID-01: 0100 | --> Belongs to us + * BSSID-02: 1001 | + * / + * ------------------- + * BSSID-03: 0110 | --> External + * ------------------- + * + * Our bssid_mask would then be: + * + * On loop iteration for BSSID-01: + * ~(0001 ^ 0100) -> ~(0101) + * -> 1010 + * bssid_mask = 1010 + * + * On loop iteration for BSSID-02: + * bssid_mask &= ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(1001) + * bssid_mask = (1010) & (0110) + * bssid_mask = 0010 + * + * A bssid_mask of 0010 means "only pay attention to the second least + * significant bit". This is because its the only bit common + * amongst the MAC and all BSSIDs we support. To findout what the real + * common bit is we can simply "&" the bssid_mask now with any BSSID we have + * or our MAC address (we assume the hardware uses the MAC address). + * + * Now, suppose there's an incoming frame for BSSID-03: + * + * IFRAME-01: 0110 + * + * An easy eye-inspeciton of this already should tell you that this frame + * will not pass our check. This is beacuse the bssid_mask tells the + * hardware to only look at the second least significant bit and the + * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB + * as 1, which does not match 0. + * + * So with IFRAME-01 we *assume* the hardware will do: + * + * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; + * --> allow = (0010) == 0000 ? 1 : 0; + * --> allow = 0 + * + * Lets now test a frame that should work: + * + * IFRAME-02: 0001 (we should allow) + * + * allow = (0001 & 1010) == 1010 + * + * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; + * --> allow = (0010) == (0010) + * --> allow = 1 + * + * Other examples: + * + * IFRAME-03: 0100 --> allowed + * IFRAME-04: 1001 --> allowed + * IFRAME-05: 1101 --> allowed but its not for us!!! + * + */ +int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) +{ + u32 low_id, high_id; + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5212) { + low_id = AR5K_LOW_ID(mask); + high_id = AR5K_HIGH_ID(mask); + + ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); + + return 0; + } + + return -EIO; +} + + +/************\ +* RX Control * +\************/ + +/** + * ath5k_hw_start_rx_pcu - Start RX engine + * + * @ah: The &struct ath5k_hw + * + * Starts RX engine on PCU so that hw can process RXed frames + * (ACK etc). + * + * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma + * TODO: Init ANI here + */ +void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); +} + +/** + * at5k_hw_stop_rx_pcu - Stop RX engine + * + * @ah: The &struct ath5k_hw + * + * Stops RX engine on PCU + * + * TODO: Detach ANI here + */ +void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); +} + +/* + * Set multicast filter + */ +void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) +{ + ATH5K_TRACE(ah->ah_sc); + /* Set the multicat filter */ + ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); + ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); +} + +/* + * Set multicast filter by index + */ +int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index) +{ + + ATH5K_TRACE(ah->ah_sc); + if (index >= 64) + return -EINVAL; + else if (index >= 32) + AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, + (1 << (index - 32))); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); + + return 0; +} + +/* + * Clear Multicast filter by index + */ +int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) +{ + + ATH5K_TRACE(ah->ah_sc); + if (index >= 64) + return -EINVAL; + else if (index >= 32) + AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, + (1 << (index - 32))); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); + + return 0; +} + +/** + * ath5k_hw_get_rx_filter - Get current rx filter + * + * @ah: The &struct ath5k_hw + * + * Returns the RX filter by reading rx filter and + * phy error filter registers. RX filter is used + * to set the allowed frame types that PCU will accept + * and pass to the driver. For a list of frame types + * check out reg.h. + */ +u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) +{ + u32 data, filter = 0; + + ATH5K_TRACE(ah->ah_sc); + filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); + + /*Radar detection for 5212*/ + if (ah->ah_version == AR5K_AR5212) { + data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); + + if (data & AR5K_PHY_ERR_FIL_RADAR) + filter |= AR5K_RX_FILTER_RADARERR; + if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) + filter |= AR5K_RX_FILTER_PHYERR; + } + + return filter; +} + +/** + * ath5k_hw_set_rx_filter - Set rx filter + * + * @ah: The &struct ath5k_hw + * @filter: RX filter mask (see reg.h) + * + * Sets RX filter register and also handles PHY error filter + * register on 5212 and newer chips so that we have proper PHY + * error reporting. + */ +void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) +{ + u32 data = 0; + + ATH5K_TRACE(ah->ah_sc); + + /* Set PHY error filter register on 5212*/ + if (ah->ah_version == AR5K_AR5212) { + if (filter & AR5K_RX_FILTER_RADARERR) + data |= AR5K_PHY_ERR_FIL_RADAR; + if (filter & AR5K_RX_FILTER_PHYERR) + data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; + } + + /* + * The AR5210 uses promiscous mode to detect radar activity + */ + if (ah->ah_version == AR5K_AR5210 && + (filter & AR5K_RX_FILTER_RADARERR)) { + filter &= ~AR5K_RX_FILTER_RADARERR; + filter |= AR5K_RX_FILTER_PROM; + } + + /*Zero length DMA*/ + if (data) + AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); + + /*Write RX Filter register*/ + ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); + + /*Write PHY error filter register on 5212*/ + if (ah->ah_version == AR5K_AR5212) + ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); + +} + + +/****************\ +* Beacon control * +\****************/ + +/** + * ath5k_hw_get_tsf32 - Get a 32bit TSF + * + * @ah: The &struct ath5k_hw + * + * Returns lower 32 bits of current TSF + */ +u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_reg_read(ah, AR5K_TSF_L32); +} + +/** + * ath5k_hw_get_tsf64 - Get the full 64bit TSF + * + * @ah: The &struct ath5k_hw + * + * Returns the current TSF + */ +u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) +{ + u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + ATH5K_TRACE(ah->ah_sc); + + return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); +} + +/** + * ath5k_hw_reset_tsf - Force a TSF reset + * + * @ah: The &struct ath5k_hw + * + * Forces a TSF reset on PCU + */ +void ath5k_hw_reset_tsf(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF); +} + +/* + * Initialize beacon timers + */ +void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) +{ + u32 timer1, timer2, timer3; + + ATH5K_TRACE(ah->ah_sc); + /* + * Set the additional timers by mode + */ + switch (ah->ah_op_mode) { + case IEEE80211_IF_TYPE_STA: + if (ah->ah_version == AR5K_AR5210) { + timer1 = 0xffffffff; + timer2 = 0xffffffff; + } else { + timer1 = 0x0000ffff; + timer2 = 0x0007ffff; + } + break; + + default: + timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; + timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + } + + 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); + ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); + ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); + ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); + + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | + AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), + AR5K_BEACON); +} + +#if 0 +/* + * Set beacon timers + */ +int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, + const struct ath5k_beacon_state *state) +{ + u32 cfp_period, next_cfp, dtim, interval, next_beacon; + + /* + * TODO: should be changed through *state + * review struct ath5k_beacon_state struct + * + * XXX: These are used for cfp period bellow, are they + * ok ? Is it O.K. for tsf here to be 0 or should we use + * get_tsf ? + */ + u32 dtim_count = 0; /* XXX */ + u32 cfp_count = 0; /* XXX */ + u32 tsf = 0; /* XXX */ + + ATH5K_TRACE(ah->ah_sc); + /* Return on an invalid beacon state */ + if (state->bs_interval < 1) + return -EINVAL; + + interval = state->bs_interval; + dtim = state->bs_dtim_period; + + /* + * PCF support? + */ + if (state->bs_cfp_period > 0) { + /* + * Enable PCF mode and set the CFP + * (Contention Free Period) and timer registers + */ + cfp_period = state->bs_cfp_period * state->bs_dtim_period * + state->bs_interval; + next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * + state->bs_interval; + + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_PCF); + ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); + ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, + AR5K_CFP_DUR); + ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : + next_cfp)) << 3, AR5K_TIMER2); + } else { + /* Disable PCF mode */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_PCF); + } + + /* + * Enable the beacon timer register + */ + ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); + + /* + * Start the beacon timers + */ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) & + ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | + AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, + AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, + AR5K_BEACON_PERIOD), AR5K_BEACON); + + /* + * Write new beacon miss threshold, if it appears to be valid + * XXX: Figure out right values for min <= bs_bmiss_threshold <= max + * and return if its not in range. We can test this by reading value and + * setting value to a largest value and seeing which values register. + */ + + AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, + state->bs_bmiss_threshold); + + /* + * Set sleep control register + * XXX: Didn't find this in 5210 code but since this register + * exists also in ar5k's 5210 headers i leave it as common code. + */ + AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, + (state->bs_sleep_duration - 3) << 3); + + /* + * Set enhanced sleep registers on 5212 + */ + if (ah->ah_version == AR5K_AR5212) { + if (state->bs_sleep_duration > state->bs_interval && + roundup(state->bs_sleep_duration, interval) == + state->bs_sleep_duration) + interval = state->bs_sleep_duration; + + if (state->bs_sleep_duration > dtim && (dtim == 0 || + roundup(state->bs_sleep_duration, dtim) == + state->bs_sleep_duration)) + dtim = state->bs_sleep_duration; + + if (interval > dtim) + return -EINVAL; + + next_beacon = interval == dtim ? state->bs_next_dtim : + state->bs_next_beacon; + + ath5k_hw_reg_write(ah, + AR5K_REG_SM((state->bs_next_dtim - 3) << 3, + AR5K_SLEEP0_NEXT_DTIM) | + AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | + AR5K_SLEEP0_ENH_SLEEP_EN | + AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); + + ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, + AR5K_SLEEP1_NEXT_TIM) | + AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); + + ath5k_hw_reg_write(ah, + AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | + AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); + } + + return 0; +} + +/* + * Reset beacon timers + */ +void ath5k_hw_reset_beacon(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /* + * Disable beacon timer + */ + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + + /* + * Disable some beacon register values + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); + ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); +} + +/* + * Wait for beacon queue to finish + */ +int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) +{ + unsigned int i; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + /* 5210 doesn't have QCU*/ + if (ah->ah_version == AR5K_AR5210) { + /* + * Wait for beaconn queue to finish by checking + * Control Register and Beacon Status Register. + */ + for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { + if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) + || + !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) + break; + udelay(10); + } + + /* Timeout... */ + if (i <= 0) { + /* + * Re-schedule the beacon queue + */ + ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, + AR5K_BCR); + + return -EIO; + } + ret = 0; + } else { + /*5211/5212*/ + ret = ath5k_hw_register_timeout(ah, + AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), + AR5K_QCU_STS_FRMPENDCNT, 0, false); + + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) + return -EIO; + } + + return ret; +} +#endif + + +/*********************\ +* Key table functions * +\*********************/ + +/* + * Reset a key entry on the table + */ +int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) +{ + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + + /* + * Set NULL encryption on AR5212+ + * + * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) + * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 + * + * Note2: Windows driver (ndiswrapper) sets this to + * 0x00000714 instead of 0x00000007 + */ + if (ah->ah_version > AR5K_AR5211) + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(entry)); + + return 0; +} + +/* + * Check if a table entry is valid + */ +int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + /* Check the validation flag at the end of the entry */ + return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & + AR5K_KEYTABLE_VALID; +} + +/* + * Set a key entry on the table + */ +int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, + const struct ieee80211_key_conf *key, const u8 *mac) +{ + unsigned int i; + __le32 key_v[5] = {}; + u32 keytype; + + ATH5K_TRACE(ah->ah_sc); + + /* key->keylen comes in from mac80211 in bytes */ + + if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + 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; + + /* 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; + + default: + return -EINVAL; /* shouldn't happen */ + } + + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(entry, i)); + + ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); + + return ath5k_hw_set_key_lladdr(ah, entry, mac); +} + +int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) +{ + u32 low_id, high_id; + + ATH5K_TRACE(ah->ah_sc); + /* Invalid entry (key table overflow) */ + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + /* MAC may be NULL if it's a broadcast key. In this case no need to + * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ + if (unlikely(mac == NULL)) { + low_id = 0xffffffff; + high_id = 0xffff | AR5K_KEYTABLE_VALID; + } else { + low_id = AR5K_LOW_ID(mac); + high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; + } + + ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); + ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index fa0d47faf57..1ea8ed962d2 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1,9 +1,9 @@ /* * PHY functions * - * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter - * Copyright (c) 2006, 2007 Nick Kossifidis - * Copyright (c) 2007 Jiri Slaby + * Copyright (c) 2004-2007 Reyk Floeter + * Copyright (c) 2006-2007 Nick Kossifidis + * Copyright (c) 2007-2008 Jiri Slaby * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,8 @@ * */ +#define _ATH5K_PHY + #include #include "ath5k.h" @@ -2501,3 +2503,5 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power) return ath5k_hw_txpower(ah, channel, power); } + +#undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c new file mode 100644 index 00000000000..2e20f7816ca --- /dev/null +++ b/drivers/net/wireless/ath5k/qcu.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * + * Permission to use, copy, modify, and 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. + * + */ + +/********************************************\ +Queue Control Unit, DFS Control Unit Functions +\********************************************/ + +#include "ath5k.h" +#include "reg.h" +#include "debug.h" +#include "base.h" + +/* + * Get properties for a transmit queue + */ +int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, + struct ath5k_txq_info *queue_info) +{ + ATH5K_TRACE(ah->ah_sc); + memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); + return 0; +} + +/* + * Set properties for a transmit queue + */ +int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, + const struct ath5k_txq_info *queue_info) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); + + /*XXX: Is this supported on 5210 ?*/ + if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && + ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || + (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || + queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) + ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; + + return 0; +} + +/* + * Initialize a transmit queue + */ +int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, + struct ath5k_txq_info *queue_info) +{ + unsigned int queue; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Get queue by type + */ + /*5210 only has 2 queues*/ + if (ah->ah_version == AR5K_AR5210) { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: + queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON; + break; + default: + return -EINVAL; + } + } else { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: + for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; + ah->ah_txq[queue].tqi_type != + AR5K_TX_QUEUE_INACTIVE; queue++) { + + if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) + return -EINVAL; + } + break; + case AR5K_TX_QUEUE_UAPSD: + queue = AR5K_TX_QUEUE_ID_UAPSD; + break; + case AR5K_TX_QUEUE_BEACON: + queue = AR5K_TX_QUEUE_ID_BEACON; + break; + case AR5K_TX_QUEUE_CAB: + queue = AR5K_TX_QUEUE_ID_CAB; + break; + case AR5K_TX_QUEUE_XR_DATA: + if (ah->ah_version != AR5K_AR5212) + ATH5K_ERR(ah->ah_sc, + "XR data queues only supported in" + " 5212!\n"); + queue = AR5K_TX_QUEUE_ID_XR_DATA; + break; + default: + return -EINVAL; + } + } + + /* + * Setup internal queue structure + */ + memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info)); + ah->ah_txq[queue].tqi_type = queue_type; + + if (queue_info != NULL) { + queue_info->tqi_type = queue_type; + ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info); + if (ret) + return ret; + } + + /* + * We use ah_txq_status to hold a temp value for + * the Secondary interrupt mask registers on 5211+ + * check out ath5k_hw_reset_tx_queue + */ + AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue); + + return queue; +} + +/* + * Get number of pending frames + * for a specific queue [5211+] + */ +u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return false; + + /* XXX: How about AR5K_CFG_TXCNT ? */ + if (ah->ah_version == AR5K_AR5210) + return false; + + return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT; +} + +/* + * Set a transmit queue inactive + */ +void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) +{ + ATH5K_TRACE(ah->ah_sc); + if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) + return; + + /* This queue will be skipped in further operations */ + ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; + /*For SIMR setup*/ + AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); +} + +/* + * Set DFS properties for a transmit queue on DCU + */ +int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) +{ + u32 cw_min, cw_max, retry_lg, retry_sh; + struct ath5k_txq_info *tq = &ah->ah_txq[queue]; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + tq = &ah->ah_txq[queue]; + + if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) + return 0; + + if (ah->ah_version == AR5K_AR5210) { + /* Only handle data queues, others will be ignored */ + if (tq->tqi_type != AR5K_TX_QUEUE_DATA) + return 0; + + /* Set Slot time */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, + AR5K_SLOT_TIME); + /* Set ACK_CTS timeout */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : + AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); + /* Set Transmit Latency */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_TRANSMIT_LATENCY_TURBO : + AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); + + /* Set IFS0 */ + if (ah->ah_turbo) { + ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + + (ah->ah_aifs + tq->tqi_aifs) * + AR5K_INIT_SLOT_TIME_TURBO) << + AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, + AR5K_IFS0); + } else { + ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + + (ah->ah_aifs + tq->tqi_aifs) * + AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | + AR5K_INIT_SIFS, AR5K_IFS0); + } + + /* Set IFS1 */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + AR5K_INIT_PROTO_TIME_CNTRL_TURBO : + AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); + /* Set AR5K_PHY_SETTLING */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) + | 0x38 : + (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) + | 0x1C, + AR5K_PHY_SETTLING); + /* Set Frame Control Register */ + ath5k_hw_reg_write(ah, ah->ah_turbo ? + (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | + AR5K_PHY_TURBO_SHORT | 0x2020) : + (AR5K_PHY_FRAME_CTL_INI | 0x1020), + AR5K_PHY_FRAME_CTL_5210); + } + + /* + * Calculate cwmin/max by channel mode + */ + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; + ah->ah_aifs = AR5K_TUNE_AIFS; + /*XR is only supported on 5212*/ + if (IS_CHAN_XR(ah->ah_current_channel) && + ah->ah_version == AR5K_AR5212) { + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; + ah->ah_aifs = AR5K_TUNE_AIFS_XR; + /*B mode is not supported on 5210*/ + } else if (IS_CHAN_B(ah->ah_current_channel) && + ah->ah_version != AR5K_AR5210) { + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; + ah->ah_aifs = AR5K_TUNE_AIFS_11B; + } + + cw_min = 1; + while (cw_min < ah->ah_cw_min) + cw_min = (cw_min << 1) | 1; + + cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : + ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); + cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : + ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); + + /* + * Calculate and set retry limits + */ + if (ah->ah_software_retry) { + /* XXX Need to test this */ + retry_lg = ah->ah_limit_tx_retries; + retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? + AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; + } else { + retry_lg = AR5K_INIT_LG_RETRY; + retry_sh = AR5K_INIT_SH_RETRY; + } + + /*No QCU/DCU [5210]*/ + if (ah->ah_version == AR5K_AR5210) { + ath5k_hw_reg_write(ah, + (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) + | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, + AR5K_NODCU_RETRY_LMT_SLG_RETRY) + | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, + AR5K_NODCU_RETRY_LMT_SSH_RETRY) + | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) + | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), + AR5K_NODCU_RETRY_LMT); + } else { + /*QCU/DCU [5211+]*/ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(AR5K_INIT_SLG_RETRY, + AR5K_DCU_RETRY_LMT_SLG_RETRY) | + AR5K_REG_SM(AR5K_INIT_SSH_RETRY, + AR5K_DCU_RETRY_LMT_SSH_RETRY) | + AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | + AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), + AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); + + /*===Rest is also for QCU/DCU only [5211+]===*/ + + /* + * Set initial content window (cw_min/cw_max) + * and arbitrated interframe space (aifs)... + */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | + AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | + AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, + AR5K_DCU_LCL_IFS_AIFS), + AR5K_QUEUE_DFS_LOCAL_IFS(queue)); + + /* + * Set misc registers + */ + ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY, + AR5K_QUEUE_MISC(queue)); + + if (tq->tqi_cbr_period) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, + AR5K_QCU_CBRCFG_INTVAL) | + AR5K_REG_SM(tq->tqi_cbr_overflow_limit, + AR5K_QCU_CBRCFG_ORN_THRES), + AR5K_QUEUE_CBRCFG(queue)); + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_CBR); + if (tq->tqi_cbr_overflow_limit) + AR5K_REG_ENABLE_BITS(ah, + AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_CBR_THRES_ENABLE); + } + + if (tq->tqi_ready_time) + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, + AR5K_QCU_RDYTIMECFG_INTVAL) | + AR5K_QCU_RDYTIMECFG_ENABLE, + AR5K_QUEUE_RDYTIMECFG(queue)); + + if (tq->tqi_burst_time) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, + AR5K_DCU_CHAN_TIME_DUR) | + AR5K_DCU_CHAN_TIME_ENABLE, + AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); + + if (tq->tqi_flags + & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) + AR5K_REG_ENABLE_BITS(ah, + AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_RDY_VEOL_POLICY); + } + + if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) + ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, + AR5K_QUEUE_DFS_MISC(queue)); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) + ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, + AR5K_QUEUE_DFS_MISC(queue)); + + /* + * Set registers by queue type + */ + switch (tq->tqi_type) { + case AR5K_TX_QUEUE_BEACON: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_CBREXP_BCN | + AR5K_QCU_MISC_BCN_ENABLE); + + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << + AR5K_DCU_MISC_ARBLOCK_CTL_S) | + AR5K_DCU_MISC_POST_FR_BKOFF_DIS | + AR5K_DCU_MISC_BCN_ENABLE); + + ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - + (AR5K_TUNE_SW_BEACON_RESP - + AR5K_TUNE_DMA_BEACON_RESP) - + AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | + AR5K_QCU_RDYTIMECFG_ENABLE, + AR5K_QUEUE_RDYTIMECFG(queue)); + break; + + case AR5K_TX_QUEUE_CAB: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_CBREXP | + AR5K_QCU_MISC_CBREXP_BCN); + + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << + AR5K_DCU_MISC_ARBLOCK_CTL_S)); + break; + + case AR5K_TX_QUEUE_UAPSD: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_CBREXP); + break; + + case AR5K_TX_QUEUE_DATA: + default: + break; + } + + /* + * Enable interrupts for this tx queue + * in the secondary interrupt mask registers + */ + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); + + + /* Update secondary interrupt mask registers */ + 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; + + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, + AR5K_SIMR0_QCU_TXOK) | + AR5K_REG_SM(ah->ah_txq_imr_txdesc, + AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, + 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); + } + + return 0; +} + +/* + * Get slot time from DCU + */ +unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + if (ah->ah_version == AR5K_AR5210) + return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, + AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); + else + return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; +} + +/* + * Set slot time on DCU + */ +int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) +{ + ATH5K_TRACE(ah->ah_sc); + if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) + return -EINVAL; + + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, + ah->ah_turbo), AR5K_SLOT_TIME); + else + ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); + + return 0; +} + diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 7562bf173d3..a9883236444 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2007 Nick Kossifidis - * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter - * Copyright (c) 2007 Michael Taylor + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2007-2008 Michael Taylor * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -976,98 +976,6 @@ */ #define AR5K_EEPROM_BASE 0x6000 -/* - * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) - */ -#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ -#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ -#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ -#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_INFO_BASE 0x00c0 /* EEPROM header */ -#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) -#define AR5K_EEPROM_INFO_CKSUM 0xffff -#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) - -#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ -#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ -#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_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_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_MODE_11A 0 -#define AR5K_EEPROM_MODE_11B 1 -#define AR5K_EEPROM_MODE_11G 2 - -#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ -#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) -#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) -#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) -#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_RFKILL_GPIO_SEL 0x0000001c -#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 -#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 -#define AR5K_EEPROM_RFKILL_POLARITY_S 1 - -/* Newer EEPROMs are using a different offset */ -#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ - (((_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)) - -/* 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 */ - -/* [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) - /* * EEPROM data register */ @@ -1950,13 +1858,13 @@ #define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */ /* - * Desired size register + * Desired ADC/PGA size register * (for more infos read ANI patent) */ #define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */ #define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* Mask for ADC desired size */ #define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* Mask for PGA desired size */ -#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size (?) */ +#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size */ /* * PHY signal register diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c new file mode 100644 index 00000000000..d260fba0180 --- /dev/null +++ b/drivers/net/wireless/ath5k/reset.c @@ -0,0 +1,925 @@ +/* + * Copyright (c) 2004-2008 Reyk Floeter + * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2007-2008 Luis Rodriguez + * Copyright (c) 2007-2008 Pavel Roskin + * Copyright (c) 2007-2008 Jiri Slaby + * + * Permission to use, copy, modify, and 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. + * + */ + +#define _ATH5K_RESET + +/*****************************\ + Reset functions and helpers +\*****************************/ + +#include +#include "ath5k.h" +#include "reg.h" +#include "base.h" +#include "debug.h" + +/** + * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 + * + * @ah: the &struct ath5k_hw + * @channel: the currently set channel upon reset + * + * Write the OFDM timings for the AR5212 upon reset. This is a helper for + * ath5k_hw_reset(). This seems to tune the PLL a specified frequency + * depending on the bandwidth of the channel. + * + */ +static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + /* Get exponent and mantissa and set it */ + u32 coef_scaled, coef_exp, coef_man, + ds_coef_exp, ds_coef_man, clock; + + if (!(ah->ah_version == AR5K_AR5212) || + !(channel->hw_value & CHANNEL_OFDM)) + BUG(); + + /* Seems there are two PLLs, one for baseband sampling and one + * for tuning. Tuning basebands are 40 MHz or 80MHz when in + * turbo. */ + clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40; + coef_scaled = ((5 * (clock << 24)) / 2) / + channel->center_freq; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + if (!coef_exp) + return -EINVAL; + + coef_exp = 14 - (coef_exp - 24); + coef_man = coef_scaled + + (1 << (24 - coef_exp - 1)); + ds_coef_man = coef_man >> (24 - coef_exp); + ds_coef_exp = coef_exp - 16; + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, + AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, + AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); + + return 0; +} + + +/* + * index into rates for control rates, we can set it up like this because + * this is only used for AR5212 and we know it supports G mode + */ +static int control_rates[] = + { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; + +/** + * ath5k_hw_write_rate_duration - set rate duration during hw resets + * + * @ah: the &struct ath5k_hw + * @mode: one of enum ath5k_driver_mode + * + * Write the rate duration table upon hw reset. This is a helper for + * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for + * the hardware for the current mode for each rate. The rates which are capable + * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another + * register for the short preamble ACK timeout calculation. + */ +static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, + unsigned int mode) +{ + struct ath5k_softc *sc = ah->ah_sc; + struct ieee80211_rate *rate; + unsigned int i; + + /* Write rate duration table */ + for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { + u32 reg; + u16 tx_time; + + rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; + + /* Set ACK timeout */ + reg = AR5K_RATE_DUR(rate->hw_value); + + /* An ACK frame consists of 10 bytes. If you add the FCS, + * which ieee80211_generic_frame_duration() adds, + * its 14 bytes. Note we use the control rate and not the + * actual rate for this rate. See mac80211 tx.c + * ieee80211_duration() for a brief description of + * what rate we should choose to TX ACKs. */ + tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, + sc->vif, 10, rate)); + + ath5k_hw_reg_write(ah, tx_time, reg); + + if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) + continue; + + /* + * We're not distinguishing short preamble here, + * This is true, all we'll get is a longer value here + * which is not necessarilly bad. We could use + * export ieee80211_frame_duration() but that needs to be + * fixed first to be properly used by mac802111 drivers: + * + * - remove erp stuff and let the routine figure ofdm + * erp rates + * - remove passing argument ieee80211_local as + * drivers don't have access to it + * - move drivers using ieee80211_generic_frame_duration() + * to this + */ + ath5k_hw_reg_write(ah, tx_time, + reg + (AR5K_SET_SHORT_PREAMBLE << 2)); + } +} + +/* + * Reset chipset + */ +static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) +{ + int ret; + u32 mask = val ? val : ~0U; + + ATH5K_TRACE(ah->ah_sc); + + /* Read-and-clear RX Descriptor Pointer*/ + ath5k_hw_reg_read(ah, AR5K_RXDP); + + /* + * Reset the device and wait until success + */ + ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); + + /* Wait at least 128 PCI clocks */ + udelay(15); + + if (ah->ah_version == AR5K_AR5210) { + val &= AR5K_RESET_CTL_CHIP; + mask &= AR5K_RESET_CTL_CHIP; + } else { + val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; + mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; + } + + ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); + + /* + * Reset configuration register (for hw byte-swap). Note that this + * is only set for big endian. We do the necessary magic in + * AR5K_INIT_CFG. + */ + if ((val & AR5K_RESET_CTL_PCU) == 0) + ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); + + return ret; +} + +/* + * Sleep control + */ +int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, + bool set_chip, u16 sleep_duration) +{ + unsigned int i; + u32 staid, data; + + ATH5K_TRACE(ah->ah_sc); + staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); + + switch (mode) { + case AR5K_PM_AUTO: + staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; + /* fallthrough */ + case AR5K_PM_NETWORK_SLEEP: + if (set_chip) + ath5k_hw_reg_write(ah, + AR5K_SLEEP_CTL_SLE_ALLOW | + sleep_duration, + AR5K_SLEEP_CTL); + + staid |= AR5K_STA_ID1_PWR_SV; + break; + + case AR5K_PM_FULL_SLEEP: + if (set_chip) + ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, + AR5K_SLEEP_CTL); + + staid |= AR5K_STA_ID1_PWR_SV; + break; + + case AR5K_PM_AWAKE: + + staid &= ~AR5K_STA_ID1_PWR_SV; + + if (!set_chip) + goto commit; + + /* Preserve sleep duration */ + data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); + if (data & 0xffc00000) + data = 0; + else + data = data & 0xfffcffff; + + ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + udelay(15); + + for (i = 50; i > 0; i--) { + /* Check if the chip did wake up */ + if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & + AR5K_PCICFG_SPWR_DN) == 0) + break; + + /* Wait a bit and retry */ + udelay(200); + ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + } + + /* Fail if the chip didn't wake up */ + if (i <= 0) + return -EIO; + + break; + + default: + return -EINVAL; + } + +commit: + ah->ah_power_mode = mode; + ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); + + return 0; +} + +/* + * Bring up MAC + PHY Chips + */ +int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) +{ + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 turbo, mode, clock, bus_flags; + int ret; + + turbo = 0; + mode = 0; + clock = 0; + + ATH5K_TRACE(ah->ah_sc); + + /* Wakeup the device */ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); + return ret; + } + + if (ah->ah_version != AR5K_AR5210) { + /* + * Get channel mode flags + */ + + if (ah->ah_radio >= AR5K_RF5112) { + mode = AR5K_PHY_MODE_RAD_RF5112; + clock = AR5K_PHY_PLL_RF5112; + } else { + mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ + clock = AR5K_PHY_PLL_RF5111; /*Zero*/ + } + + if (flags & CHANNEL_2GHZ) { + mode |= AR5K_PHY_MODE_FREQ_2GHZ; + clock |= AR5K_PHY_PLL_44MHZ; + + if (flags & CHANNEL_CCK) { + mode |= AR5K_PHY_MODE_MOD_CCK; + } else if (flags & CHANNEL_OFDM) { + /* XXX Dynamic OFDM/CCK is not supported by the + * AR5211 so we set MOD_OFDM for plain g (no + * CCK headers) operation. We need to test + * this, 5211 might support ofdm-only g after + * all, there are also initial register values + * in the code for g mode (see initvals.c). */ + if (ah->ah_version == AR5K_AR5211) + mode |= AR5K_PHY_MODE_MOD_OFDM; + else + mode |= AR5K_PHY_MODE_MOD_DYN; + } else { + ATH5K_ERR(ah->ah_sc, + "invalid radio modulation mode\n"); + return -EINVAL; + } + } else if (flags & CHANNEL_5GHZ) { + mode |= AR5K_PHY_MODE_FREQ_5GHZ; + clock |= AR5K_PHY_PLL_40MHZ; + + if (flags & CHANNEL_OFDM) + mode |= AR5K_PHY_MODE_MOD_OFDM; + else { + ATH5K_ERR(ah->ah_sc, + "invalid radio modulation mode\n"); + return -EINVAL; + } + } else { + ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); + return -EINVAL; + } + + if (flags & CHANNEL_TURBO) + turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; + } else { /* Reset the device */ + + /* ...enable Atheros turbo mode if requested */ + if (flags & CHANNEL_TURBO) + ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, + AR5K_PHY_TURBO); + } + + /* reseting PCI on PCI-E cards results card to hang + * and always return 0xffff... so we ingore that flag + * for PCI-E cards */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + /* Reset chipset */ + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); + return -EIO; + } + + if (ah->ah_version == AR5K_AR5210) + udelay(2300); + + /* ...wakeup again!*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); + return ret; + } + + /* ...final warm reset */ + if (ath5k_hw_nic_reset(ah, 0)) { + ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); + return -EIO; + } + + if (ah->ah_version != AR5K_AR5210) { + /* ...set the PHY operating mode */ + ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); + udelay(300); + + ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); + ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); + } + + return 0; +} + +/* + * Main reset function + */ +int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, + struct ieee80211_channel *channel, bool change_channel) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 data, s_seq, s_ant, s_led[3], dma_size; + unsigned int i, mode, freq, ee_mode, ant[2]; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + s_seq = 0; + s_ant = 0; + ee_mode = 0; + freq = 0; + mode = 0; + + /* + * Save some registers before a reset + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + if (change_channel) { + /* Seq number for queue 0 -do this for all queues ? */ + s_seq = ath5k_hw_reg_read(ah, + AR5K_QUEUE_DFS_SEQNUM(0)); + /*Default antenna*/ + s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + } + } + + /*GPIOs*/ + s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; + s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); + s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); + + if (change_channel && ah->ah_rf_banks != NULL) + ath5k_hw_get_rf_gain(ah); + + + /*Wakeup the device*/ + ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); + if (ret) + return ret; + + /* + * Initialize operating mode + */ + ah->ah_op_mode = op_mode; + + /* + * 5111/5112 Settings + * 5210 only comes with RF5110 + */ + if (ah->ah_version != AR5K_AR5210) { + if (ah->ah_radio != AR5K_RF5111 && + ah->ah_radio != AR5K_RF5112 && + ah->ah_radio != AR5K_RF5413 && + ah->ah_radio != AR5K_RF2413 && + ah->ah_radio != AR5K_RF2425) { + ATH5K_ERR(ah->ah_sc, + "invalid phy radio: %u\n", ah->ah_radio); + return -EINVAL; + } + + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + mode = AR5K_MODE_11A; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + mode = AR5K_MODE_11G; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_B: + mode = AR5K_MODE_11B; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11B; + break; + case CHANNEL_T: + mode = AR5K_MODE_11A_TURBO; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + break; + /*Is this ok on 5211 too ?*/ + case CHANNEL_TG: + mode = AR5K_MODE_11G_TURBO; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_XR: + if (ah->ah_version == AR5K_AR5211) { + ATH5K_ERR(ah->ah_sc, + "XR mode not available on 5211"); + return -EINVAL; + } + mode = AR5K_MODE_XR; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->center_freq); + return -EINVAL; + } + + /* PHY access enable */ + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + + } + + ret = ath5k_hw_write_initvals(ah, mode, change_channel); + if (ret) + return ret; + + /* + * 5211/5212 Specific + */ + if (ah->ah_version != AR5K_AR5210) { + /* + * Write initial RF gain settings + * This should work for both 5111/5112 + */ + ret = ath5k_hw_rfgain(ah, freq); + if (ret) + return ret; + + mdelay(1); + + /* + * Write some more initial register settings + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); + + if (channel->hw_value == CHANNEL_G) + if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) + ath5k_hw_reg_write(ah, 0x00f80d80, + 0x994c); + else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) + ath5k_hw_reg_write(ah, 0x00380140, + 0x994c); + else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) + ath5k_hw_reg_write(ah, 0x00fc0ec0, + 0x994c); + else /* 2425 */ + ath5k_hw_reg_write(ah, 0x00fc0fc0, + 0x994c); + else + ath5k_hw_reg_write(ah, 0x00000000, 0x994c); + + /* Some bits are disabled here, we know nothing about + * register 0xa228 yet, most of the times this ends up + * with a value 0x9b5 -haven't seen any dump with + * a different value- */ + /* Got this from decompiling binary HAL */ + data = ath5k_hw_reg_read(ah, 0xa228); + data &= 0xfffffdff; + ath5k_hw_reg_write(ah, data, 0xa228); + + data = ath5k_hw_reg_read(ah, 0xa228); + data &= 0xfffe03ff; + ath5k_hw_reg_write(ah, data, 0xa228); + data = 0; + + /* Just write 0x9b5 ? */ + /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */ + ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); + ath5k_hw_reg_write(ah, 0x00000000, 0xa254); + ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); + } + + /* Fix for first revision of the RF5112 RF chipset */ + if (ah->ah_radio >= AR5K_RF5112 && + ah->ah_radio_5ghz_revision < + AR5K_SREV_RAD_5112A) { + ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, + AR5K_PHY_CCKTXCTL); + if (channel->hw_value & CHANNEL_5GHZ) + data = 0xffb81020; + else + data = 0xffb80d20; + ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); + data = 0; + } + + /* + * Set TX power (FIXME) + */ + ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); + if (ret) + return ret; + + /* Write rate duration table only on AR5212 and if + * virtual interface has already been brought up + * XXX: rethink this after new mode changes to + * mac80211 are integrated */ + if (ah->ah_version == AR5K_AR5212 && + ah->ah_sc->vif != NULL) + ath5k_hw_write_rate_duration(ah, mode); + + /* + * Write RF registers + */ + ret = ath5k_hw_rfregs(ah, channel, mode); + if (ret) + return ret; + + /* + * Configure additional registers + */ + + /* Write OFDM timings on 5212*/ + if (ah->ah_version == AR5K_AR5212 && + channel->hw_value & CHANNEL_OFDM) { + ret = ath5k_hw_write_ofdm_timings(ah, channel); + if (ret) + return ret; + } + + /*Enable/disable 802.11b mode on 5111 + (enable 2111 frequency converter + CCK)*/ + if (ah->ah_radio == AR5K_RF5111) { + if (mode == AR5K_MODE_11B) + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_B_MODE); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_B_MODE); + } + + /* + * Set channel and calibrate the PHY + */ + ret = ath5k_hw_channel(ah, channel); + if (ret) + return ret; + + /* Set antenna mode */ + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL, + ah->ah_antenna[ee_mode][0], 0xfffffc06); + + /* + * In case a fixed antenna was set as default + * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE + * registers. + */ + if (s_ant != 0) { + if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ + ant[0] = ant[1] = AR5K_ANT_FIXED_A; + else /* 2 - Aux */ + ant[0] = ant[1] = AR5K_ANT_FIXED_B; + } else { + ant[0] = AR5K_ANT_FIXED_A; + ant[1] = AR5K_ANT_FIXED_B; + } + + ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], + AR5K_PHY_ANT_SWITCH_TABLE_0); + ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], + AR5K_PHY_ANT_SWITCH_TABLE_1); + + /* Commit values from EEPROM */ + if (ah->ah_radio == AR5K_RF5111) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, + AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); + + ath5k_hw_reg_write(ah, + AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), + AR5K_PHY_NFTHRES); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING, + (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, + 0xfffc0fff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, + (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | + ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), + 0xffff0000); + + ath5k_hw_reg_write(ah, + (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | + (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | + (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | + (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3, + ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF, + (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CORR_ENABLE | + (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | + ee->ee_q_cal[ee_mode]); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, + AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, + ee->ee_margin_tx_rx[ee_mode]); + + } else { + mdelay(1); + /* Disable phy and wait */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); + mdelay(1); + } + + /* + * Restore saved values + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); + ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); + } + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); + ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); + ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); + + /* + * Misc + */ + /* XXX: add ah->aid once mac80211 gives this to us */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + + ath5k_hw_set_opmode(ah); + /*PISR/SISR Not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); + /* If we later allow tuning for this, store into sc structure */ + data = AR5K_TUNE_RSSI_THRES | + AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; + ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); + } + + /* + * Set Rx/Tx DMA Configuration + * + * Set maximum DMA size (512) except for PCI-E cards since + * it causes rx overruns and tx errors (tested on 5424 but since + * rx overruns also occur on 5416/5418 with madwifi we set 128 + * for all PCI-E cards to be safe). + * + * In dumps this is 128 for allchips. + * + * XXX: need to check 5210 for this + * TODO: Check out tx triger level, it's always 64 on dumps but I + * guess we can tweak it and see how it goes ;-) + */ + dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B; + if (ah->ah_version != AR5K_AR5210) { + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_SDMAMR, dma_size); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, + AR5K_RXCFG_SDMAMW, dma_size); + } + + /* + * Enable the PHY and wait until completion + */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + + /* + * On 5211+ read activation -> rx delay + * and use it. + */ + if (ah->ah_version != AR5K_AR5210) { + data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & + AR5K_PHY_RX_DELAY_M; + data = (channel->hw_value & CHANNEL_CCK) ? + ((data << 2) / 22) : (data / 10); + + udelay(100 + (2 * data)); + data = 0; + } else { + mdelay(1); + } + + /* + * Perform ADC test (?) + */ + data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); + ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); + for (i = 0; i <= 20; i++) { + if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) + break; + udelay(200); + } + ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1); + data = 0; + + /* + * Start automatic gain calibration + * + * During AGC calibration RX path is re-routed to + * a signal detector so we don't receive anything. + * + * This method is used to calibrate some static offsets + * used together with on-the fly I/Q calibration (the + * one performed via ath5k_hw_phy_calibrate), that doesn't + * interrupt rx path. + * + * If we are in a noisy environment AGC calibration may time + * out. + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL); + + /* At the same time start I/Q calibration for QAM constellation + * -no need for CCK- */ + ah->ah_calibration = false; + if (!(mode == AR5K_MODE_11B)) { + ah->ah_calibration = true; + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_RUN); + } + + /* Wait for gain calibration to finish (we check for I/Q calibration + * during ath5k_phy_calibrate) */ + if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL, 0, false)) { + ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n", + channel->center_freq); + return -EAGAIN; + } + + /* + * Start noise floor calibration + * + * If we run NF calibration before AGC, it always times out. + * Binary HAL starts NF and AGC calibration at the same time + * and only waits for AGC to finish. I believe that's wrong because + * during NF calibration, rx path is also routed to a detector, so if + * it doesn't finish we won't have RX. + * + * XXX: Find an interval that's OK for all cards... + */ + ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + if (ret) + return ret; + + /* + * Reset queues and start beacon timers at the end of the reset routine + */ + for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { + /*No QCU on 5210*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); + + ret = ath5k_hw_reset_tx_queue(ah, i); + if (ret) { + ATH5K_ERR(ah->ah_sc, + "failed to reset TX queue #%d\n", i); + return ret; + } + } + + /* 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); + + /* + * Set RF kill flags if supported by the device (read from the EEPROM) + * Disable gpio_intr for now since it results system hang. + * TODO: Handle this in ath5k_intr + */ +#if 0 + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_hw_set_gpio_input(ah, 0); + ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); + if (ah->ah_gpio[0] == 0) + ath5k_hw_set_gpio_intr(ah, 0, 1); + else + ath5k_hw_set_gpio_intr(ah, 0, 0); + } +#endif + + /* + * Set the 32MHz reference clock on 5212 phy clock sleep register + * + * TODO: Find out how to switch to external 32Khz clock to save power + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); + ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); + ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); + ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); + ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); + ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); + + data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ; + data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ? + 0x00000f80 : 0x00001380 ; + ath5k_hw_reg_write(ah, data, AR5K_USEC_5211); + data = 0; + } + + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); + ath5k_hw_reg_write(ah, 0x00003210, 0x811c); + ath5k_hw_reg_write(ah, 0x00000052, 0x8108); + if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413) + ath5k_hw_reg_write(ah, 0x00000004, 0x8120); + } + + /* + * Disable beacons and reset the register + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | + AR5K_BEACON_RESET_TSF); + + return 0; +} + +#undef _ATH5K_RESET -- cgit v1.2.3 From f59ac0481660e66cec67f1d6b024e78b9dc715fe Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 29 Aug 2008 16:26:43 -0700 Subject: cfg80211: keep track of supported interface modes It is obviously good for userspace to know up front which interface modes a given piece of hardware might support (even if adding such an interface might fail later because of concurrency issues), so let's make cfg80211 aware of that. For good measure, disallow adding interfaces in all other modes so drivers don't forget to announce support for one mode when they add it. Signed-off-by: Johannes Berg Signed-off-by: Stephen Blackheath Signed-off-by: Ivo van Doorn Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 1 + drivers/net/wireless/ath5k/base.c | 6 ++++++ drivers/net/wireless/ath9k/main.c | 5 +++++ drivers/net/wireless/b43/main.c | 7 +++++++ drivers/net/wireless/b43legacy/main.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-core.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +++++ drivers/net/wireless/mac80211_hwsim.c | 3 +++ drivers/net/wireless/p54/p54common.c | 3 +++ drivers/net/wireless/rt2x00/rt2x00dev.c | 5 +++++ drivers/net/wireless/rtl8187_dev.c | 2 ++ drivers/net/wireless/zd1211rw/zd_mac.c | 5 +++++ 12 files changed, 51 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 3333d4596b8..c6a55cd12db 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1884,6 +1884,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; dev->max_signal = 100; /* FIXME: find better value */ diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 7989ab5c2bb..85260c39aa2 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -485,6 +485,12 @@ ath5k_pci_probe(struct pci_dev *pdev, hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + hw->extra_tx_headroom = 2; hw->channel_change_time = 5000; sc = hw->priv; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index dc45eef3289..39a4a70d013 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1482,6 +1482,11 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 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); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 63bafc2f3f0..2d915c1a82a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4569,6 +4569,13 @@ static int b43_wireless_init(struct ssb_device *dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_WDS) | + BIT(NL80211_IFTYPE_ADHOC); + hw->queues = b43_modparam_qos ? 4 : 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1cb77db5c29..68f63f5093a 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3704,6 +3704,11 @@ static int b43legacy_wireless_init(struct ssb_device *dev) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_WDS) | + BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index fbf75a62958..0a511ef8e35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -819,6 +819,10 @@ int iwl_setup_mac(struct iwl_priv *priv) /* 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); /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a622fc33590..cee3045f160 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7888,6 +7888,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e 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); + /* 4 EDCA QOS priorities */ hw->queues = 4; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 732429d4912..6ba50f087f7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -447,6 +447,9 @@ static int __init init_mac80211_hwsim(void) hw->channel_change_time = 1; hw->queues = 4; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP); hw->ampdu_queues = 1; memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 17e06bbc996..6da98e6e6a9 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1072,6 +1072,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_UNSPEC; + + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + dev->channel_change_time = 1000; /* TODO: find actual value */ dev->max_signal = 127; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 369b0b2d864..2f3bfc60688 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1052,6 +1052,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); + rt2x00dev->hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + /* * Let the driver probe the device to detect the capabilities. */ diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 060a2650535..8a42bfa6d4f 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -1184,6 +1184,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->max_signal = 65; } + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) printk(KERN_INFO "rtl8187: inconsistency between id with OEM" " info!\n"); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 4d7b98b0503..e019102b228 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -937,6 +937,11 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DB; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + hw->max_signal = 100; hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); -- cgit v1.2.3 From 99c4a780624da24d20309f2be5abe5ef8d20fcc0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 30 Aug 2008 02:09:08 +0200 Subject: b43: Move remaining code from phy.c to phy_a.c This moves the remaining code from phy.c to phy_a.c phy.c is removed. No functional change. Just moving code and removing dead code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy.c | 489 --------------------------------------- drivers/net/wireless/b43/phy_a.c | 85 ++++++- drivers/net/wireless/b43/phy_a.h | 8 + drivers/net/wireless/b43/phy_g.h | 2 + 4 files changed, 94 insertions(+), 490 deletions(-) delete mode 100644 drivers/net/wireless/b43/phy.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c deleted file mode 100644 index 02ae450beb0..00000000000 --- a/drivers/net/wireless/b43/phy.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - - Broadcom B43 wireless driver - - Copyright (c) 2005 Martin Langer , - Copyright (c) 2005-2007 Stefano Brivio - Copyright (c) 2005, 2006 Michael Buesch - Copyright (c) 2005, 2006 Danny van Dyk - Copyright (c) 2005, 2006 Andreas Jaggi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include -#include -#include -#include - -#include "b43.h" -#include "phy.h" -#include "nphy.h" -#include "main.h" -#include "tables.h" -#include "lo.h" -#include "wa.h" - - -static void b43_shm_clear_tssi(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - switch (phy->type) { - case B43_PHYTYPE_A: - b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F); - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); - break; - } -} - -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut - * This function converts a TSSI value to dBm in Q5.2 - */ -static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) -{ - struct b43_phy *phy = &dev->phy; - s8 dbm = 0; - s32 tmp; - - tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); - - switch (phy->type) { - case B43_PHYTYPE_A: - tmp += 0x80; - tmp = clamp_val(tmp, 0x00, 0xFF); - dbm = phy->tssi2dbm[tmp]; - //TODO: There's a FIXME on the specs - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - tmp = clamp_val(tmp, 0x00, 0x3F); - dbm = phy->tssi2dbm[tmp]; - break; - default: - B43_WARN_ON(1); - } - - return dbm; -} - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt) -{ - int rfatt = *_rfatt; - int bbatt = *_bbatt; - struct b43_txpower_lo_control *lo = dev->phy.lo_control; - - /* Get baseband and radio attenuation values into their permitted ranges. - * Radio attenuation affects power level 4 times as much as baseband. */ - - /* Range constants */ - const int rf_min = lo->rfatt_list.min_val; - const int rf_max = lo->rfatt_list.max_val; - const int bb_min = lo->bbatt_list.min_val; - const int bb_max = lo->bbatt_list.max_val; - - while (1) { - if (rfatt > rf_max && bbatt > bb_max - 4) - break; /* Can not get it into ranges */ - if (rfatt < rf_min && bbatt < bb_min + 4) - break; /* Can not get it into ranges */ - if (bbatt > bb_max && rfatt > rf_max - 1) - break; /* Can not get it into ranges */ - if (bbatt < bb_min && rfatt < rf_min + 1) - break; /* Can not get it into ranges */ - - if (bbatt > bb_max) { - bbatt -= 4; - rfatt += 1; - continue; - } - if (bbatt < bb_min) { - bbatt += 4; - rfatt -= 1; - continue; - } - if (rfatt > rf_max) { - rfatt -= 1; - bbatt += 4; - continue; - } - if (rfatt < rf_min) { - rfatt += 1; - bbatt -= 4; - continue; - } - break; - } - - *_rfatt = clamp_val(rfatt, rf_min, rf_max); - *_bbatt = clamp_val(bbatt, bb_min, bb_max); -} - -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ -void b43_phy_xmitpower(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - if (phy->cur_idle_tssi == 0) - return; - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; -#ifdef CONFIG_B43_DEBUG - if (phy->manual_txpower_control) - return; -#endif - - switch (phy->type) { - case B43_PHYTYPE_A:{ - - //TODO: Nothing for A PHYs yet :-/ - - break; - } - case B43_PHYTYPE_B: - case B43_PHYTYPE_G:{ - u16 tmp; - s8 v0, v1, v2, v3; - s8 average; - int max_pwr; - int desired_pwr, estimated_pwr, pwr_adjust; - int rfatt_delta, bbatt_delta; - int rfatt, bbatt; - u8 tx_control; - - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - tmp = 0; - - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) { - tmp = - b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = - b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) - return; - v0 = (v0 + 0x20) & 0x3F; - v1 = (v1 + 0x20) & 0x3F; - v2 = (v2 + 0x20) & 0x3F; - v3 = (v3 + 0x20) & 0x3F; - tmp = 1; - } - b43_shm_clear_tssi(dev); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp - && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & - 0x8)) - average -= 13; - - estimated_pwr = - b43_phy_estimate_power_out(dev, average); - - max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.boardflags_lo - & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) - max_pwr -= 0x3; - if (unlikely(max_pwr <= 0)) { - b43warn(dev->wl, - "Invalid max-TX-power value in SPROM.\n"); - max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.maxpwr_bg = max_pwr; - } - - /*TODO: - max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - /* Get desired power (in Q5.2) */ - desired_pwr = INT_TO_Q52(phy->power_level); - /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = clamp_val(desired_pwr, 0, max_pwr); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, - "Current TX power output: " Q52_FMT - " dBm, " "Desired TX power output: " - Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), - Q52_ARG(desired_pwr)); - } - - /* Calculate the adjustment delta. */ - pwr_adjust = desired_pwr - estimated_pwr; - - /* RF attenuation delta. */ - rfatt_delta = ((pwr_adjust + 7) / 8); - /* Lower attenuation => Bigger power output. Negate it. */ - rfatt_delta = -rfatt_delta; - - /* Baseband attenuation delta. */ - bbatt_delta = pwr_adjust / 2; - /* Lower attenuation => Bigger power output. Negate it. */ - bbatt_delta = -bbatt_delta; - /* RF att affects power level 4 times as much as - * Baseband attennuation. Subtract it. */ - bbatt_delta -= 4 * rfatt_delta; - - /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) - return; - - /* Calculate the new attenuation values. */ - bbatt = phy->bbatt.att; - bbatt += bbatt_delta; - rfatt = phy->rfatt.att; - rfatt += rfatt_delta; - - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - tx_control = phy->tx_control; - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { - if (rfatt <= 1) { - if (tx_control == 0) { - tx_control = - B43_TXCTL_PA2DB | - B43_TXCTL_TXMIX; - rfatt += 2; - bbatt += 2; - } else if (dev->dev->bus->sprom. - boardflags_lo & - B43_BFL_PACTRL) { - bbatt += 4 * (rfatt - 2); - rfatt = 2; - } - } else if (rfatt > 4 && tx_control) { - tx_control = 0; - if (bbatt < 3) { - rfatt -= 3; - bbatt += 2; - } else { - rfatt -= 2; - bbatt -= 2; - } - } - } - /* Save the control values */ - phy->tx_control = tx_control; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - phy->rfatt.att = rfatt; - phy->bbatt.att = bbatt; - - /* Adjust the hardware */ - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, - phy->tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - break; - } - case B43_PHYTYPE_N: - b43_nphy_xmitpower(dev); - break; - default: - B43_WARN_ON(1); - } -} - -static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) -{ - if (num < 0) - return num / den; - else - return (num + den / 2) / den; -} - -static inline - s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) -{ - s32 m1, m2, f = 256, q, delta; - s8 i = 0; - - m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); - m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); - do { - if (i > 15) - return -EINVAL; - q = b43_tssi2dbm_ad(f * 4096 - - b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); - delta = abs(q - f); - f = q; - i++; - } while (delta >= 2); - entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s16 pab0, pab1, pab2; - u8 idx; - s8 *dyn_tssi2dbm; - - if (phy->type == B43_PHYTYPE_A) { - pab0 = (s16) (dev->dev->bus->sprom.pa1b0); - pab1 = (s16) (dev->dev->bus->sprom.pa1b1); - pab2 = (s16) (dev->dev->bus->sprom.pa1b2); - } else { - pab0 = (s16) (dev->dev->bus->sprom.pa0b0); - pab1 = (s16) (dev->dev->bus->sprom.pa0b1); - pab2 = (s16) (dev->dev->bus->sprom.pa0b2); - } - - if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - return 0; - } - - if (pab0 != 0 && pab1 != 0 && pab2 != 0 && - pab0 != -1 && pab1 != -1 && pab2 != -1) { - /* The pabX values are set in SPROM. Use them. */ - if (phy->type == B43_PHYTYPE_A) { - if ((s8) dev->dev->bus->sprom.itssi_a != 0 && - (s8) dev->dev->bus->sprom.itssi_a != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_a); - else - phy->tgt_idle_tssi = 62; - } else { - if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && - (s8) dev->dev->bus->sprom.itssi_bg != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_bg); - else - phy->tgt_idle_tssi = 62; - } - dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); - if (dyn_tssi2dbm == NULL) { - b43err(dev->wl, "Could not allocate memory " - "for tssi2dbm table\n"); - return -ENOMEM; - } - for (idx = 0; idx < 64; idx++) - if (b43_tssi2dbm_entry - (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate " - "tssi2dBm table\n"); - kfree(dyn_tssi2dbm); - return -ENODEV; - } - phy->tssi2dbm = dyn_tssi2dbm; - phy->dyn_tssi_tbl = 1; - } else { - /* pabX values not set in SPROM. */ - switch (phy->type) { - case B43_PHYTYPE_A: - /* APHY needs a generated table. */ - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate tssi2dBm " - "table (wrong SPROM info)!\n"); - return -ENODEV; - case B43_PHYTYPE_B: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - break; - case B43_PHYTYPE_G: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_g_table; - break; - } - } - - return 0; -} - -void b43_radio_turn_on(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - int err; - u8 channel; - - might_sleep(); - - if (phy->radio_on) - return; - - switch (phy->type) { - case B43_PHYTYPE_A: - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); - b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); - b43_radio_init2060(dev); - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - //XXX - break; - case B43_PHYTYPE_N: - b43_nphy_radio_turn_on(dev); - break; - default: - B43_WARN_ON(1); - } - phy->radio_on = 1; -} - -void b43_radio_turn_off(struct b43_wldev *dev, bool force) -{ - struct b43_phy *phy = &dev->phy; - - if (!phy->radio_on && !force) - return; - - switch (phy->type) { - case B43_PHYTYPE_N: - b43_nphy_radio_turn_off(dev); - break; - case B43_PHYTYPE_A: - b43_radio_write16(dev, 0x0004, 0x00FF); - b43_radio_write16(dev, 0x0005, 0x00FB); - b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); - b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); - break; - case B43_PHYTYPE_G: { - //XXX - break; - } - default: - B43_WARN_ON(1); - } - phy->radio_on = 0; -} diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 4d7d59e3096..2ca8353aa9a 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -58,6 +58,25 @@ static inline u16 freq_r3A_value(u16 frequency) return value; } +#if 0 +/* This function converts a TSSI value to dBm in Q5.2 */ +static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + s8 dbm = 0; + s32 tmp; + + tmp = (aphy->tgt_idle_tssi - aphy->cur_idle_tssi + tssi); + tmp += 0x80; + tmp = clamp_val(tmp, 0x00, 0xFF); + dbm = aphy->tssi2dbm[tmp]; + //TODO: There's a FIXME on the specs + + return dbm; +} +#endif + void b43_radio_set_tx_iq(struct b43_wldev *dev) { static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; @@ -326,9 +345,46 @@ void b43_phy_inita(struct b43_wldev *dev) } } +/* Initialise the TSSI->dBm lookup table */ +static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + s16 pab0, pab1, pab2; + + pab0 = (s16) (dev->dev->bus->sprom.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.pa1b2); + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8) dev->dev->bus->sprom.itssi_a != 0 && + (s8) dev->dev->bus->sprom.itssi_a != -1) + aphy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_a); + else + aphy->tgt_idle_tssi = 62; + aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, + pab1, pab2); + if (!aphy->tssi2dbm) + return -ENOMEM; + } else { + /* pabX values not set in SPROM, + * but APHY needs a generated table. */ + aphy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + } + + return 0; +} + static int b43_aphy_op_allocate(struct b43_wldev *dev) { struct b43_phy_a *aphy; + int err; aphy = kzalloc(sizeof(*aphy), GFP_KERNEL); if (!aphy) @@ -337,7 +393,17 @@ static int b43_aphy_op_allocate(struct b43_wldev *dev) //TODO init struct b43_phy_a + err = b43_aphy_init_tssi2dbm_table(dev); + if (err) + goto err_free_aphy; + return 0; + +err_free_aphy: + kfree(aphy); + dev->phy.a = NULL; + + return err; } static int b43_aphy_op_init(struct b43_wldev *dev) @@ -359,6 +425,7 @@ static void b43_aphy_op_exit(struct b43_wldev *dev) aphy->initialised = 0; } //TODO + kfree(aphy->tssi2dbm); kfree(aphy); dev->phy.a = NULL; } @@ -430,7 +497,23 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) -{//TODO +{ + struct b43_phy *phy = &dev->phy; + + if (state == RFKILL_STATE_UNBLOCKED) { + if (phy->radio_on) + return; + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); + b43_radio_init2060(dev); + } else { + b43_radio_write16(dev, 0x0004, 0x00FF); + b43_radio_write16(dev, 0x0005, 0x00FB); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); + } } static int b43_aphy_op_switch_channel(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h index e8640f7312b..583da0e416e 100644 --- a/drivers/net/wireless/b43/phy_a.h +++ b/drivers/net/wireless/b43/phy_a.h @@ -105,6 +105,14 @@ void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, struct b43_phy_a { bool initialised; + /* Pointer to the table used to convert a + * TSSI value to dBm-Q5.2 */ + const s8 *tssi2dbm; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi;//FIXME value currently not set + /* A-PHY TX Power control value. */ u16 txpwr_offset; diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 7f95edea1c6..913eb13e8fb 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -202,6 +202,8 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, void b43_gphy_channel_switch(struct b43_wldev *dev, unsigned int channel, bool synthetic_pu_workaround); +u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, + s16 pab0, s16 pab1, s16 pab2); struct b43_phy_operations; extern const struct b43_phy_operations b43_phyops_g; -- cgit v1.2.3 From 3d0da7516441d41dbfcc2b2667d9b792d580e50b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 30 Aug 2008 02:27:19 +0200 Subject: b43: Move code from nphy.* to phy_n.* Sourcecode files for PHY code are named by phy_XXX.{c,h} where XXX is the PHY type. Move the N-PHY code to match the other files. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Makefile | 2 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/nphy.c | 624 ---------------------- drivers/net/wireless/b43/nphy.h | 932 --------------------------------- drivers/net/wireless/b43/phy_common.c | 2 +- drivers/net/wireless/b43/phy_n.c | 624 ++++++++++++++++++++++ drivers/net/wireless/b43/phy_n.h | 932 +++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/tables_nphy.c | 2 +- 8 files changed, 1560 insertions(+), 1560 deletions(-) delete mode 100644 drivers/net/wireless/b43/nphy.c delete mode 100644 drivers/net/wireless/b43/nphy.h create mode 100644 drivers/net/wireless/b43/phy_n.c create mode 100644 drivers/net/wireless/b43/phy_n.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index fb6ffce03f0..7fe49034ff2 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -4,7 +4,7 @@ b43-$(CONFIG_B43_NPHY) += tables_nphy.o b43-y += phy_common.o b43-y += phy_g.o b43-y += phy_a.o -b43-$(CONFIG_B43_NPHY) += nphy.o +b43-$(CONFIG_B43_NPHY) += phy_n.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2d915c1a82a..fda9492d588 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -46,7 +46,7 @@ #include "debugfs.h" #include "phy_common.h" #include "phy_g.h" -#include "nphy.h" +#include "phy_n.h" #include "dma.h" #include "pio.h" #include "sysfs.h" diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c deleted file mode 100644 index 4cfeab8560f..00000000000 --- a/drivers/net/wireless/b43/nphy.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - - Broadcom B43 wireless driver - IEEE 802.11n PHY support - - Copyright (c) 2008 Michael Buesch - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include -#include - -#include "b43.h" -#include "nphy.h" -#include "tables_nphy.h" - - -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) -{//TODO -} - -static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) -{//TODO -} - -static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, - bool ignore_tssi) -{//TODO - return B43_TXPWR_RES_DONE; -} - -static void b43_chantab_radio_upload(struct b43_wldev *dev, - const struct b43_nphy_channeltab_entry *e) -{ - b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref); - b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0); - b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1); - b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail); - b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1); - b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2); - b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1); - b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1); - b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2); - b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf); - b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1); - b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2); - b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune); - b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune); - b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1); - b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn); - b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim); - b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune); - b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune); - b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1); - b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn); - b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim); -} - -static void b43_chantab_phy_upload(struct b43_wldev *dev, - const struct b43_nphy_channeltab_entry *e) -{ - b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a); - b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2); - b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3); - b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4); - b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5); - b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6); -} - -static void b43_nphy_tx_power_fix(struct b43_wldev *dev) -{ - //TODO -} - -/* Tune the hardware to a new channel. */ -static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel) -{ - const struct b43_nphy_channeltab_entry *tabent; - - tabent = b43_nphy_get_chantabent(dev, channel); - if (!tabent) - return -ESRCH; - - //FIXME enable/disable band select upper20 in RXCTL - if (0 /*FIXME 5Ghz*/) - b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20); - else - b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50); - b43_chantab_radio_upload(dev, tabent); - udelay(50); - b43_radio_write16(dev, B2055_VCO_CAL10, 5); - b43_radio_write16(dev, B2055_VCO_CAL10, 45); - b43_radio_write16(dev, B2055_VCO_CAL10, 65); - udelay(300); - if (0 /*FIXME 5Ghz*/) - b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); - else - b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); - b43_chantab_phy_upload(dev, tabent); - b43_nphy_tx_power_fix(dev); - - return 0; -} - -static void b43_radio_init2055_pre(struct b43_wldev *dev) -{ - b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, - ~B43_NPHY_RFCTL_CMD_PORFORCE); - b43_phy_set(dev, B43_NPHY_RFCTL_CMD, - B43_NPHY_RFCTL_CMD_CHIP0PU | - B43_NPHY_RFCTL_CMD_OEPORFORCE); - b43_phy_set(dev, B43_NPHY_RFCTL_CMD, - B43_NPHY_RFCTL_CMD_PORFORCE); -} - -static void b43_radio_init2055_post(struct b43_wldev *dev) -{ - struct ssb_sprom *sprom = &(dev->dev->bus->sprom); - struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo); - int i; - u16 val; - - b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); - msleep(1); - if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) { - if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) || - (binfo->type != 0x46D) || - (binfo->rev < 0x41)) { - b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); - b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); - msleep(1); - } - } - b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C); - msleep(1); - b43_radio_write16(dev, B2055_CAL_MISC, 0x3C); - msleep(1); - b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE); - msleep(1); - b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80); - msleep(1); - b43_radio_set(dev, B2055_CAL_MISC, 0x1); - msleep(1); - b43_radio_set(dev, B2055_CAL_MISC, 0x40); - msleep(1); - for (i = 0; i < 100; i++) { - val = b43_radio_read16(dev, B2055_CAL_COUT2); - if (val & 0x80) - break; - udelay(10); - } - msleep(1); - b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); - msleep(1); - nphy_channel_switch(dev, dev->phy.channel); - b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); - b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); - b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); - b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83); -} - -/* Initialize a Broadcom 2055 N-radio */ -static void b43_radio_init2055(struct b43_wldev *dev) -{ - b43_radio_init2055_pre(dev); - if (b43_status(dev) < B43_STAT_INITIALIZED) - b2055_upload_inittab(dev, 0, 1); - else - b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0); - b43_radio_init2055_post(dev); -} - -void b43_nphy_radio_turn_on(struct b43_wldev *dev) -{ - b43_radio_init2055(dev); -} - -void b43_nphy_radio_turn_off(struct b43_wldev *dev) -{ - b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, - ~B43_NPHY_RFCTL_CMD_EN); -} - -#define ntab_upload(dev, offset, data) do { \ - unsigned int i; \ - for (i = 0; i < (offset##_SIZE); i++) \ - b43_ntab_write(dev, (offset) + i, (data)[i]); \ - } while (0) - -/* Upload the N-PHY tables. */ -static void b43_nphy_tables_init(struct b43_wldev *dev) -{ - /* Static tables */ - ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); - ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); - ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); - ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); - ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); - ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); - ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); - ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); - ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); - ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); - ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); - ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); - ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); - ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); - - /* Volatile tables */ - ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); - ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); - ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); - ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); - ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); - ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); - ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); - ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); - ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); - ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); - ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); - ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); -} - -static void b43_nphy_workarounds(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - unsigned int i; - - b43_phy_set(dev, B43_NPHY_IQFLIP, - B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); - if (1 /* FIXME band is 2.4GHz */) { - b43_phy_set(dev, B43_NPHY_CLASSCTL, - B43_NPHY_CLASSCTL_CCKEN); - } else { - b43_phy_mask(dev, B43_NPHY_CLASSCTL, - ~B43_NPHY_CLASSCTL_CCKEN); - } - b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); - b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8); - - /* Fixup some tables */ - b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA); - b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA); - b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); - b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); - b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0); - b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0); - b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); - b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); - b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800); - b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800); - - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); - - //TODO set RF sequence - - /* Set narrowband clip threshold */ - b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66); - b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66); - - /* Set wideband clip 2 threshold */ - b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, - ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, - 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, - ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, - 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT); - - /* Set Clip 2 detect */ - b43_phy_set(dev, B43_NPHY_C1_CGAINI, - B43_NPHY_C1_CGAINI_CL2DETECT); - b43_phy_set(dev, B43_NPHY_C2_CGAINI, - B43_NPHY_C2_CGAINI_CL2DETECT); - - if (0 /*FIXME*/) { - /* Set dwell lengths */ - b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43); - b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43); - b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9); - b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9); - - /* Set gain backoff */ - b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, - ~B43_NPHY_C1_CGAINI_GAINBKOFF, - 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, - ~B43_NPHY_C2_CGAINI_GAINBKOFF, - 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT); - - /* Set HPVGA2 index */ - b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, - ~B43_NPHY_C1_INITGAIN_HPVGA2, - 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, - ~B43_NPHY_C2_INITGAIN_HPVGA2, - 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); - - //FIXME verify that the specs really mean to use autoinc here. - for (i = 0; i < 3; i++) - b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673); - } - - /* Set minimum gain value */ - b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, - ~B43_NPHY_C1_MINGAIN, - 23 << B43_NPHY_C1_MINGAIN_SHIFT); - b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, - ~B43_NPHY_C2_MINGAIN, - 23 << B43_NPHY_C2_MINGAIN_SHIFT); - - if (phy->rev < 2) { - b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, - ~B43_NPHY_SCRAM_SIGCTL_SCM); - } - - /* Set phase track alpha and beta */ - b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); - b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); - b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); - b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); - b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); - b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); -} - -static void b43_nphy_reset_cca(struct b43_wldev *dev) -{ - u16 bbcfg; - - ssb_write32(dev->dev, SSB_TMSLOW, - ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); - bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); - b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); - b43_phy_write(dev, B43_NPHY_BBCFG, - bbcfg & ~B43_NPHY_BBCFG_RSTCCA); - ssb_write32(dev->dev, SSB_TMSLOW, - ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); -} - -enum b43_nphy_rf_sequence { - B43_RFSEQ_RX2TX, - B43_RFSEQ_TX2RX, - B43_RFSEQ_RESET2RX, - B43_RFSEQ_UPDATE_GAINH, - B43_RFSEQ_UPDATE_GAINL, - B43_RFSEQ_UPDATE_GAINU, -}; - -static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, - enum b43_nphy_rf_sequence seq) -{ - static const u16 trigger[] = { - [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX, - [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX, - [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX, - [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH, - [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL, - [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, - }; - int i; - - B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); - - b43_phy_set(dev, B43_NPHY_RFSEQMODE, - B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER); - b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]); - for (i = 0; i < 200; i++) { - if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq])) - goto ok; - msleep(1); - } - b43err(dev->wl, "RF sequence status timeout\n"); -ok: - b43_phy_mask(dev, B43_NPHY_RFSEQMODE, - ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); -} - -static void b43_nphy_bphy_init(struct b43_wldev *dev) -{ - unsigned int i; - u16 val; - - val = 0x1E1F; - for (i = 0; i < 14; i++) { - b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); - val -= 0x202; - } - val = 0x3E3F; - for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); - val -= 0x202; - } - b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); -} - -/* RSSI Calibration */ -static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) -{ - //TODO -} - -int b43_phy_initn(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 tmp; - - //TODO: Spectral management - b43_nphy_tables_init(dev); - - /* Clear all overrides */ - b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); - b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); - b43_phy_mask(dev, B43_NPHY_RFSEQMODE, - ~(B43_NPHY_RFSEQMODE_CAOVER | - B43_NPHY_RFSEQMODE_TROVER)); - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); - - tmp = (phy->rev < 2) ? 64 : 59; - b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, - ~B43_NPHY_BPHY_CTL3_SCALE, - tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); - - b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); - b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); - - b43_phy_write(dev, B43_NPHY_TXREALFD, 184); - b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); - b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); - b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); - - //TODO MIMO-Config - //TODO Update TX/RX chain - - if (phy->rev < 2) { - b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); - b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); - } - b43_nphy_workarounds(dev); - b43_nphy_reset_cca(dev); - - ssb_write32(dev->dev, SSB_TMSLOW, - ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - - b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ - //TODO read core1/2 clip1 thres regs - - if (1 /* FIXME Band is 2.4GHz */) - b43_nphy_bphy_init(dev); - //TODO disable TX power control - //TODO Fix the TX power settings - //TODO Init periodic calibration with reason 3 - b43_nphy_rssi_cal(dev, 2); - b43_nphy_rssi_cal(dev, 0); - b43_nphy_rssi_cal(dev, 1); - //TODO get TX gain - //TODO init superswitch - //TODO calibrate LO - //TODO idle TSSI TX pctl - //TODO TX power control power setup - //TODO table writes - //TODO TX power control coefficients - //TODO enable TX power control - //TODO control antenna selection - //TODO init radar detection - //TODO reset channel if changed - - b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); - return 0; -} - -static int b43_nphy_op_allocate(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy; - - nphy = kzalloc(sizeof(*nphy), GFP_KERNEL); - if (!nphy) - return -ENOMEM; - dev->phy.n = nphy; - - //TODO init struct b43_phy_n - - return 0; -} - -static int b43_nphy_op_init(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - int err; - - err = b43_phy_initn(dev); - if (err) - return err; - nphy->initialised = 1; - - return 0; -} - -static void b43_nphy_op_exit(struct b43_wldev *dev) -{ - struct b43_phy_n *nphy = dev->phy.n; - - if (nphy->initialised) { - //TODO - nphy->initialised = 0; - } - //TODO - kfree(nphy); - dev->phy.n = NULL; -} - -static inline void check_phyreg(struct b43_wldev *dev, u16 offset) -{ -#if B43_DEBUG - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { - /* OFDM registers are onnly available on A/G-PHYs */ - b43err(dev->wl, "Invalid OFDM PHY access at " - "0x%04X on N-PHY\n", offset); - dump_stack(); - } - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { - /* Ext-G registers are only available on G-PHYs */ - b43err(dev->wl, "Invalid EXT-G PHY access at " - "0x%04X on N-PHY\n", offset); - dump_stack(); - } -#endif /* B43_DEBUG */ -} - -static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) -{ - check_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - check_phyreg(dev, reg); - b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); -} - -static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) -{ - /* Register 1 is a 32-bit register. */ - B43_WARN_ON(reg == 1); - /* N-PHY needs 0x100 for read access */ - reg |= 0x100; - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); - return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); -} - -static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) -{ - /* Register 1 is a 32-bit register. */ - B43_WARN_ON(reg == 1); - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); - b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); -} - -static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) -{//TODO -} - -static int b43_nphy_op_switch_channel(struct b43_wldev *dev, - unsigned int new_channel) -{ - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if ((new_channel < 1) || (new_channel > 14)) - return -EINVAL; - } else { - if (new_channel > 200) - return -EINVAL; - } - - return nphy_channel_switch(dev, new_channel); -} - -static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) -{ - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 1; - return 36; -} - -const struct b43_phy_operations b43_phyops_n = { - .allocate = b43_nphy_op_allocate, - .init = b43_nphy_op_init, - .exit = b43_nphy_op_exit, - .phy_read = b43_nphy_op_read, - .phy_write = b43_nphy_op_write, - .radio_read = b43_nphy_op_radio_read, - .radio_write = b43_nphy_op_radio_write, - .software_rfkill = b43_nphy_op_software_rfkill, - .switch_channel = b43_nphy_op_switch_channel, - .get_default_chan = b43_nphy_op_get_default_chan, - .recalc_txpower = b43_nphy_op_recalc_txpower, - .adjust_txpower = b43_nphy_op_adjust_txpower, -}; diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h deleted file mode 100644 index 3d1f65ed201..00000000000 --- a/drivers/net/wireless/b43/nphy.h +++ /dev/null @@ -1,932 +0,0 @@ -#ifndef B43_NPHY_H_ -#define B43_NPHY_H_ - -#include "phy_common.h" - - -/* N-PHY registers. */ - -#define B43_NPHY_BBCFG B43_PHY_N(0x001) /* BB config */ -#define B43_NPHY_BBCFG_RSTCCA 0x4000 /* Reset CCA */ -#define B43_NPHY_BBCFG_RSTRX 0x8000 /* Reset RX */ -#define B43_NPHY_CHANNEL B43_PHY_N(0x005) /* Channel */ -#define B43_NPHY_TXERR B43_PHY_N(0x007) /* TX error */ -#define B43_NPHY_BANDCTL B43_PHY_N(0x009) /* Band control */ -#define B43_NPHY_BANDCTL_5GHZ 0x0001 /* Use the 5GHz band */ -#define B43_NPHY_4WI_ADDR B43_PHY_N(0x00B) /* Four-wire bus address */ -#define B43_NPHY_4WI_DATAHI B43_PHY_N(0x00C) /* Four-wire bus data high */ -#define B43_NPHY_4WI_DATALO B43_PHY_N(0x00D) /* Four-wire bus data low */ -#define B43_NPHY_BIST_STAT0 B43_PHY_N(0x00E) /* Built-in self test status 0 */ -#define B43_NPHY_BIST_STAT1 B43_PHY_N(0x00F) /* Built-in self test status 1 */ - -#define B43_NPHY_C1_DESPWR B43_PHY_N(0x018) /* Core 1 desired power */ -#define B43_NPHY_C1_CCK_DESPWR B43_PHY_N(0x019) /* Core 1 CCK desired power */ -#define B43_NPHY_C1_BCLIPBKOFF B43_PHY_N(0x01A) /* Core 1 barely clip backoff */ -#define B43_NPHY_C1_CCK_BCLIPBKOFF B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */ -#define B43_NPHY_C1_CGAINI B43_PHY_N(0x01C) /* Core 1 compute gain info */ -#define B43_NPHY_C1_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ -#define B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT 0 -#define B43_NPHY_C1_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ -#define B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT 5 -#define B43_NPHY_C1_CGAINI_GAINSTEP 0x1C00 /* Gain step */ -#define B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT 10 -#define B43_NPHY_C1_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ -#define B43_NPHY_C1_CCK_CGAINI B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */ -#define B43_NPHY_C1_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ -#define B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ -#define B43_NPHY_C1_MINMAX_GAIN B43_PHY_N(0x01E) /* Core 1 min/max gain */ -#define B43_NPHY_C1_MINGAIN 0x00FF /* Minimum gain */ -#define B43_NPHY_C1_MINGAIN_SHIFT 0 -#define B43_NPHY_C1_MAXGAIN 0xFF00 /* Maximum gain */ -#define B43_NPHY_C1_MAXGAIN_SHIFT 8 -#define B43_NPHY_C1_CCK_MINMAX_GAIN B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */ -#define B43_NPHY_C1_CCK_MINGAIN 0x00FF /* Minimum gain */ -#define B43_NPHY_C1_CCK_MINGAIN_SHIFT 0 -#define B43_NPHY_C1_CCK_MAXGAIN 0xFF00 /* Maximum gain */ -#define B43_NPHY_C1_CCK_MAXGAIN_SHIFT 8 -#define B43_NPHY_C1_INITGAIN B43_PHY_N(0x020) /* Core 1 initial gain code */ -#define B43_NPHY_C1_INITGAIN_EXTLNA 0x0001 /* External LNA index */ -#define B43_NPHY_C1_INITGAIN_LNA 0x0006 /* LNA index */ -#define B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT 1 -#define B43_NPHY_C1_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ -#define B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT 3 -#define B43_NPHY_C1_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ -#define B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT 7 -#define B43_NPHY_C1_INITGAIN_TRRX 0x1000 /* TR RX index */ -#define B43_NPHY_C1_INITGAIN_TRTX 0x2000 /* TR TX index */ -#define B43_NPHY_C1_CLIP1_HIGAIN B43_PHY_N(0x021) /* Core 1 clip1 high gain code */ -#define B43_NPHY_C1_CLIP1_MEDGAIN B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */ -#define B43_NPHY_C1_CLIP1_LOGAIN B43_PHY_N(0x023) /* Core 1 clip1 low gain code */ -#define B43_NPHY_C1_CLIP2_GAIN B43_PHY_N(0x024) /* Core 1 clip2 gain code */ -#define B43_NPHY_C1_FILTERGAIN B43_PHY_N(0x025) /* Core 1 filter gain */ -#define B43_NPHY_C1_LPF_QHPF_BW B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */ -#define B43_NPHY_C1_CLIPWBTHRES B43_PHY_N(0x027) /* Core 1 clip wideband threshold */ -#define B43_NPHY_C1_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ -#define B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT 0 -#define B43_NPHY_C1_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ -#define B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT 6 -#define B43_NPHY_C1_W1THRES B43_PHY_N(0x028) /* Core 1 W1 threshold */ -#define B43_NPHY_C1_EDTHRES B43_PHY_N(0x029) /* Core 1 ED threshold */ -#define B43_NPHY_C1_SMSIGTHRES B43_PHY_N(0x02A) /* Core 1 small sig threshold */ -#define B43_NPHY_C1_NBCLIPTHRES B43_PHY_N(0x02B) /* Core 1 NB clip threshold */ -#define B43_NPHY_C1_CLIP1THRES B43_PHY_N(0x02C) /* Core 1 clip1 threshold */ -#define B43_NPHY_C1_CLIP2THRES B43_PHY_N(0x02D) /* Core 1 clip2 threshold */ - -#define B43_NPHY_C2_DESPWR B43_PHY_N(0x02E) /* Core 2 desired power */ -#define B43_NPHY_C2_CCK_DESPWR B43_PHY_N(0x02F) /* Core 2 CCK desired power */ -#define B43_NPHY_C2_BCLIPBKOFF B43_PHY_N(0x030) /* Core 2 barely clip backoff */ -#define B43_NPHY_C2_CCK_BCLIPBKOFF B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */ -#define B43_NPHY_C2_CGAINI B43_PHY_N(0x032) /* Core 2 compute gain info */ -#define B43_NPHY_C2_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ -#define B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT 0 -#define B43_NPHY_C2_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ -#define B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT 5 -#define B43_NPHY_C2_CGAINI_GAINSTEP 0x1C00 /* Gain step */ -#define B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT 10 -#define B43_NPHY_C2_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ -#define B43_NPHY_C2_CCK_CGAINI B43_PHY_N(0x033) /* Core 2 CCK compute gain info */ -#define B43_NPHY_C2_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ -#define B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ -#define B43_NPHY_C2_MINMAX_GAIN B43_PHY_N(0x034) /* Core 2 min/max gain */ -#define B43_NPHY_C2_MINGAIN 0x00FF /* Minimum gain */ -#define B43_NPHY_C2_MINGAIN_SHIFT 0 -#define B43_NPHY_C2_MAXGAIN 0xFF00 /* Maximum gain */ -#define B43_NPHY_C2_MAXGAIN_SHIFT 8 -#define B43_NPHY_C2_CCK_MINMAX_GAIN B43_PHY_N(0x035) /* Core 2 CCK min/max gain */ -#define B43_NPHY_C2_CCK_MINGAIN 0x00FF /* Minimum gain */ -#define B43_NPHY_C2_CCK_MINGAIN_SHIFT 0 -#define B43_NPHY_C2_CCK_MAXGAIN 0xFF00 /* Maximum gain */ -#define B43_NPHY_C2_CCK_MAXGAIN_SHIFT 8 -#define B43_NPHY_C2_INITGAIN B43_PHY_N(0x036) /* Core 2 initial gain code */ -#define B43_NPHY_C2_INITGAIN_EXTLNA 0x0001 /* External LNA index */ -#define B43_NPHY_C2_INITGAIN_LNA 0x0006 /* LNA index */ -#define B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT 1 -#define B43_NPHY_C2_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ -#define B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT 3 -#define B43_NPHY_C2_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ -#define B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT 7 -#define B43_NPHY_C2_INITGAIN_TRRX 0x1000 /* TR RX index */ -#define B43_NPHY_C2_INITGAIN_TRTX 0x2000 /* TR TX index */ -#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x037) /* Core 2 clip1 high gain code */ -#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */ -#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x039) /* Core 2 clip1 low gain code */ -#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x03A) /* Core 2 clip2 gain code */ -#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x03B) /* Core 2 filter gain */ -#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */ -#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */ -#define B43_NPHY_C2_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ -#define B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT 0 -#define B43_NPHY_C2_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ -#define B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT 6 -#define B43_NPHY_C2_W1THRES B43_PHY_N(0x03E) /* Core 2 W1 threshold */ -#define B43_NPHY_C2_EDTHRES B43_PHY_N(0x03F) /* Core 2 ED threshold */ -#define B43_NPHY_C2_SMSIGTHRES B43_PHY_N(0x040) /* Core 2 small sig threshold */ -#define B43_NPHY_C2_NBCLIPTHRES B43_PHY_N(0x041) /* Core 2 NB clip threshold */ -#define B43_NPHY_C2_CLIP1THRES B43_PHY_N(0x042) /* Core 2 clip1 threshold */ -#define B43_NPHY_C2_CLIP2THRES B43_PHY_N(0x043) /* Core 2 clip2 threshold */ - -#define B43_NPHY_CRS_THRES1 B43_PHY_N(0x044) /* CRS threshold 1 */ -#define B43_NPHY_CRS_THRES2 B43_PHY_N(0x045) /* CRS threshold 2 */ -#define B43_NPHY_CRS_THRES3 B43_PHY_N(0x046) /* CRS threshold 3 */ -#define B43_NPHY_CRSCTL B43_PHY_N(0x047) /* CRS control */ -#define B43_NPHY_DCFADDR B43_PHY_N(0x048) /* DC filter address */ -#define B43_NPHY_RXF20_NUM0 B43_PHY_N(0x049) /* RX filter 20 numerator 0 */ -#define B43_NPHY_RXF20_NUM1 B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */ -#define B43_NPHY_RXF20_NUM2 B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */ -#define B43_NPHY_RXF20_DENOM0 B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */ -#define B43_NPHY_RXF20_DENOM1 B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */ -#define B43_NPHY_RXF20_NUM10 B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */ -#define B43_NPHY_RXF20_NUM11 B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */ -#define B43_NPHY_RXF20_NUM12 B43_PHY_N(0x050) /* RX filter 20 numerator 12 */ -#define B43_NPHY_RXF20_DENOM10 B43_PHY_N(0x051) /* RX filter 20 denominator 10 */ -#define B43_NPHY_RXF20_DENOM11 B43_PHY_N(0x052) /* RX filter 20 denominator 11 */ -#define B43_NPHY_RXF40_NUM0 B43_PHY_N(0x053) /* RX filter 40 numerator 0 */ -#define B43_NPHY_RXF40_NUM1 B43_PHY_N(0x054) /* RX filter 40 numerator 1 */ -#define B43_NPHY_RXF40_NUM2 B43_PHY_N(0x055) /* RX filter 40 numerator 2 */ -#define B43_NPHY_RXF40_DENOM0 B43_PHY_N(0x056) /* RX filter 40 denominator 0 */ -#define B43_NPHY_RXF40_DENOM1 B43_PHY_N(0x057) /* RX filter 40 denominator 1 */ -#define B43_NPHY_RXF40_NUM10 B43_PHY_N(0x058) /* RX filter 40 numerator 10 */ -#define B43_NPHY_RXF40_NUM11 B43_PHY_N(0x059) /* RX filter 40 numerator 11 */ -#define B43_NPHY_RXF40_NUM12 B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */ -#define B43_NPHY_RXF40_DENOM10 B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */ -#define B43_NPHY_RXF40_DENOM11 B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */ -#define B43_NPHY_PPROC_RSTLEN B43_PHY_N(0x060) /* Packet processing reset length */ -#define B43_NPHY_INITCARR_DLEN B43_PHY_N(0x061) /* Initial carrier detection length */ -#define B43_NPHY_CLIP1CARR_DLEN B43_PHY_N(0x062) /* Clip1 carrier detection length */ -#define B43_NPHY_CLIP2CARR_DLEN B43_PHY_N(0x063) /* Clip2 carrier detection length */ -#define B43_NPHY_INITGAIN_SLEN B43_PHY_N(0x064) /* Initial gain settle length */ -#define B43_NPHY_CLIP1GAIN_SLEN B43_PHY_N(0x065) /* Clip1 gain settle length */ -#define B43_NPHY_CLIP2GAIN_SLEN B43_PHY_N(0x066) /* Clip2 gain settle length */ -#define B43_NPHY_PACKGAIN_SLEN B43_PHY_N(0x067) /* Packet gain settle length */ -#define B43_NPHY_CARRSRC_TLEN B43_PHY_N(0x068) /* Carrier search timeout length */ -#define B43_NPHY_TISRC_TLEN B43_PHY_N(0x069) /* Timing search timeout length */ -#define B43_NPHY_ENDROP_TLEN B43_PHY_N(0x06A) /* Energy drop timeout length */ -#define B43_NPHY_CLIP1_NBDWELL_LEN B43_PHY_N(0x06B) /* Clip1 NB dwell length */ -#define B43_NPHY_CLIP2_NBDWELL_LEN B43_PHY_N(0x06C) /* Clip2 NB dwell length */ -#define B43_NPHY_W1CLIP1_DWELL_LEN B43_PHY_N(0x06D) /* W1 clip1 dwell length */ -#define B43_NPHY_W1CLIP2_DWELL_LEN B43_PHY_N(0x06E) /* W1 clip2 dwell length */ -#define B43_NPHY_W2CLIP1_DWELL_LEN B43_PHY_N(0x06F) /* W2 clip1 dwell length */ -#define B43_NPHY_PLOAD_CSENSE_EXTLEN B43_PHY_N(0x070) /* Payload carrier sense extension length */ -#define B43_NPHY_EDROP_CSENSE_EXTLEN B43_PHY_N(0x071) /* Energy drop carrier sense extension length */ -#define B43_NPHY_TABLE_ADDR B43_PHY_N(0x072) /* Table address */ -#define B43_NPHY_TABLE_DATALO B43_PHY_N(0x073) /* Table data low */ -#define B43_NPHY_TABLE_DATAHI B43_PHY_N(0x074) /* Table data high */ -#define B43_NPHY_WWISE_LENIDX B43_PHY_N(0x075) /* WWiSE length index */ -#define B43_NPHY_TGNSYNC_LENIDX B43_PHY_N(0x076) /* TGNsync length index */ -#define B43_NPHY_TXMACIF_HOLDOFF B43_PHY_N(0x077) /* TX MAC IF Hold off */ -#define B43_NPHY_RFCTL_CMD B43_PHY_N(0x078) /* RF control (command) */ -#define B43_NPHY_RFCTL_CMD_START 0x0001 /* Start sequence */ -#define B43_NPHY_RFCTL_CMD_RXTX 0x0002 /* RX/TX */ -#define B43_NPHY_RFCTL_CMD_CORESEL 0x0038 /* Core select */ -#define B43_NPHY_RFCTL_CMD_CORESEL_SHIFT 3 -#define B43_NPHY_RFCTL_CMD_PORFORCE 0x0040 /* POR force */ -#define B43_NPHY_RFCTL_CMD_OEPORFORCE 0x0080 /* OE POR force */ -#define B43_NPHY_RFCTL_CMD_RXEN 0x0100 /* RX enable */ -#define B43_NPHY_RFCTL_CMD_TXEN 0x0200 /* TX enable */ -#define B43_NPHY_RFCTL_CMD_CHIP0PU 0x0400 /* Chip0 PU */ -#define B43_NPHY_RFCTL_CMD_EN 0x0800 /* Radio enabled */ -#define B43_NPHY_RFCTL_CMD_SEQENCORE 0xF000 /* Seq en core */ -#define B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT 12 -#define B43_NPHY_RFCTL_RSSIO1 B43_PHY_N(0x07A) /* RF control (RSSI others 1) */ -#define B43_NPHY_RFCTL_RSSIO1_RXPD 0x0001 /* RX PD */ -#define B43_NPHY_RFCTL_RSSIO1_TXPD 0x0002 /* TX PD */ -#define B43_NPHY_RFCTL_RSSIO1_PAPD 0x0004 /* PA PD */ -#define B43_NPHY_RFCTL_RSSIO1_RSSICTL 0x0030 /* RSSI control */ -#define B43_NPHY_RFCTL_RSSIO1_LPFBW 0x00C0 /* LPF bandwidth */ -#define B43_NPHY_RFCTL_RSSIO1_HPFBWHI 0x0100 /* HPF bandwidth high */ -#define B43_NPHY_RFCTL_RSSIO1_HIQDISCO 0x0200 /* HIQ dis core */ -#define B43_NPHY_RFCTL_RXG1 B43_PHY_N(0x07B) /* RF control (RX gain 1) */ -#define B43_NPHY_RFCTL_TXG1 B43_PHY_N(0x07C) /* RF control (TX gain 1) */ -#define B43_NPHY_RFCTL_RSSIO2 B43_PHY_N(0x07D) /* RF control (RSSI others 2) */ -#define B43_NPHY_RFCTL_RSSIO2_RXPD 0x0001 /* RX PD */ -#define B43_NPHY_RFCTL_RSSIO2_TXPD 0x0002 /* TX PD */ -#define B43_NPHY_RFCTL_RSSIO2_PAPD 0x0004 /* PA PD */ -#define B43_NPHY_RFCTL_RSSIO2_RSSICTL 0x0030 /* RSSI control */ -#define B43_NPHY_RFCTL_RSSIO2_LPFBW 0x00C0 /* LPF bandwidth */ -#define B43_NPHY_RFCTL_RSSIO2_HPFBWHI 0x0100 /* HPF bandwidth high */ -#define B43_NPHY_RFCTL_RSSIO2_HIQDISCO 0x0200 /* HIQ dis core */ -#define B43_NPHY_RFCTL_RXG2 B43_PHY_N(0x07E) /* RF control (RX gain 2) */ -#define B43_NPHY_RFCTL_TXG2 B43_PHY_N(0x07F) /* RF control (TX gain 2) */ -#define B43_NPHY_RFCTL_RSSIO3 B43_PHY_N(0x080) /* RF control (RSSI others 3) */ -#define B43_NPHY_RFCTL_RSSIO3_RXPD 0x0001 /* RX PD */ -#define B43_NPHY_RFCTL_RSSIO3_TXPD 0x0002 /* TX PD */ -#define B43_NPHY_RFCTL_RSSIO3_PAPD 0x0004 /* PA PD */ -#define B43_NPHY_RFCTL_RSSIO3_RSSICTL 0x0030 /* RSSI control */ -#define B43_NPHY_RFCTL_RSSIO3_LPFBW 0x00C0 /* LPF bandwidth */ -#define B43_NPHY_RFCTL_RSSIO3_HPFBWHI 0x0100 /* HPF bandwidth high */ -#define B43_NPHY_RFCTL_RSSIO3_HIQDISCO 0x0200 /* HIQ dis core */ -#define B43_NPHY_RFCTL_RXG3 B43_PHY_N(0x081) /* RF control (RX gain 3) */ -#define B43_NPHY_RFCTL_TXG3 B43_PHY_N(0x082) /* RF control (TX gain 3) */ -#define B43_NPHY_RFCTL_RSSIO4 B43_PHY_N(0x083) /* RF control (RSSI others 4) */ -#define B43_NPHY_RFCTL_RSSIO4_RXPD 0x0001 /* RX PD */ -#define B43_NPHY_RFCTL_RSSIO4_TXPD 0x0002 /* TX PD */ -#define B43_NPHY_RFCTL_RSSIO4_PAPD 0x0004 /* PA PD */ -#define B43_NPHY_RFCTL_RSSIO4_RSSICTL 0x0030 /* RSSI control */ -#define B43_NPHY_RFCTL_RSSIO4_LPFBW 0x00C0 /* LPF bandwidth */ -#define B43_NPHY_RFCTL_RSSIO4_HPFBWHI 0x0100 /* HPF bandwidth high */ -#define B43_NPHY_RFCTL_RSSIO4_HIQDISCO 0x0200 /* HIQ dis core */ -#define B43_NPHY_RFCTL_RXG4 B43_PHY_N(0x084) /* RF control (RX gain 4) */ -#define B43_NPHY_RFCTL_TXG4 B43_PHY_N(0x085) /* RF control (TX gain 4) */ -#define B43_NPHY_C1_TXIQ_COMP_OFF B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */ -#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ -#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ -#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ -#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ -#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ -#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 -#define B43_NPHY_SCRAM_SIGCTL_SCM 0x0080 /* Scram control mode */ -#define B43_NPHY_SCRAM_SIGCTL_SICE 0x0100 /* Scram index control enable */ -#define B43_NPHY_SCRAM_SIGCTL_START 0xFE00 /* Scram start bit */ -#define B43_NPHY_SCRAM_SIGCTL_START_SHIFT 9 -#define B43_NPHY_RFCTL_INTC1 B43_PHY_N(0x091) /* RF control (intc 1) */ -#define B43_NPHY_RFCTL_INTC2 B43_PHY_N(0x092) /* RF control (intc 2) */ -#define B43_NPHY_RFCTL_INTC3 B43_PHY_N(0x093) /* RF control (intc 3) */ -#define B43_NPHY_RFCTL_INTC4 B43_PHY_N(0x094) /* RF control (intc 4) */ -#define B43_NPHY_NRDTO_WWISE B43_PHY_N(0x095) /* # datatones WWiSE */ -#define B43_NPHY_NRDTO_TGNSYNC B43_PHY_N(0x096) /* # datatones TGNsync */ -#define B43_NPHY_SIGFMOD_WWISE B43_PHY_N(0x097) /* Signal field mod WWiSE */ -#define B43_NPHY_LEG_SIGFMOD_11N B43_PHY_N(0x098) /* Legacy signal field mod 11n */ -#define B43_NPHY_HT_SIGFMOD_11N B43_PHY_N(0x099) /* HT signal field mod 11n */ -#define B43_NPHY_C1_RXIQ_COMPA0 B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */ -#define B43_NPHY_C1_RXIQ_COMPB0 B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */ -#define B43_NPHY_C2_RXIQ_COMPA1 B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */ -#define B43_NPHY_C2_RXIQ_COMPB1 B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */ -#define B43_NPHY_RXCTL B43_PHY_N(0x0A0) /* RX control */ -#define B43_NPHY_RXCTL_BSELU20 0x0010 /* Band select upper 20 */ -#define B43_NPHY_RXCTL_RIFSEN 0x0080 /* RIFS enable */ -#define B43_NPHY_RFSEQMODE B43_PHY_N(0x0A1) /* RF seq mode */ -#define B43_NPHY_RFSEQMODE_CAOVER 0x0001 /* Core active override */ -#define B43_NPHY_RFSEQMODE_TROVER 0x0002 /* Trigger override */ -#define B43_NPHY_RFSEQCA B43_PHY_N(0x0A2) /* RF seq core active */ -#define B43_NPHY_RFSEQCA_TXEN 0x000F /* TX enable */ -#define B43_NPHY_RFSEQCA_TXEN_SHIFT 0 -#define B43_NPHY_RFSEQCA_RXEN 0x00F0 /* RX enable */ -#define B43_NPHY_RFSEQCA_RXEN_SHIFT 4 -#define B43_NPHY_RFSEQCA_TXDIS 0x0F00 /* TX disable */ -#define B43_NPHY_RFSEQCA_TXDIS_SHIFT 8 -#define B43_NPHY_RFSEQCA_RXDIS 0xF000 /* RX disable */ -#define B43_NPHY_RFSEQCA_RXDIS_SHIFT 12 -#define B43_NPHY_RFSEQTR B43_PHY_N(0x0A3) /* RF seq trigger */ -#define B43_NPHY_RFSEQTR_RX2TX 0x0001 /* RX2TX */ -#define B43_NPHY_RFSEQTR_TX2RX 0x0002 /* TX2RX */ -#define B43_NPHY_RFSEQTR_UPGH 0x0004 /* Update gain H */ -#define B43_NPHY_RFSEQTR_UPGL 0x0008 /* Update gain L */ -#define B43_NPHY_RFSEQTR_UPGU 0x0010 /* Update gain U */ -#define B43_NPHY_RFSEQTR_RST2RX 0x0020 /* Reset to RX */ -#define B43_NPHY_RFSEQST B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */ -#define B43_NPHY_AFECTL_OVER B43_PHY_N(0x0A5) /* AFE control override */ -#define B43_NPHY_AFECTL_C1 B43_PHY_N(0x0A6) /* AFE control core 1 */ -#define B43_NPHY_AFECTL_C2 B43_PHY_N(0x0A7) /* AFE control core 2 */ -#define B43_NPHY_AFECTL_C3 B43_PHY_N(0x0A8) /* AFE control core 3 */ -#define B43_NPHY_AFECTL_C4 B43_PHY_N(0x0A9) /* AFE control core 4 */ -#define B43_NPHY_AFECTL_DACGAIN1 B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */ -#define B43_NPHY_AFECTL_DACGAIN2 B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */ -#define B43_NPHY_AFECTL_DACGAIN3 B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */ -#define B43_NPHY_AFECTL_DACGAIN4 B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */ -#define B43_NPHY_STR_ADDR1 B43_PHY_N(0x0AE) /* STR address 1 */ -#define B43_NPHY_STR_ADDR2 B43_PHY_N(0x0AF) /* STR address 2 */ -#define B43_NPHY_CLASSCTL B43_PHY_N(0x0B0) /* Classifier control */ -#define B43_NPHY_CLASSCTL_CCKEN 0x0001 /* CCK enable */ -#define B43_NPHY_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ -#define B43_NPHY_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */ -#define B43_NPHY_IQFLIP B43_PHY_N(0x0B1) /* I/Q flip */ -#define B43_NPHY_IQFLIP_ADC1 0x0001 /* ADC1 */ -#define B43_NPHY_IQFLIP_ADC2 0x0010 /* ADC2 */ -#define B43_NPHY_SISO_SNR_THRES B43_PHY_N(0x0B2) /* SISO SNR threshold */ -#define B43_NPHY_SIGMA_N_MULT B43_PHY_N(0x0B3) /* Sigma N multiplier */ -#define B43_NPHY_TXMACDELAY B43_PHY_N(0x0B4) /* TX MAC delay */ -#define B43_NPHY_TXFRAMEDELAY B43_PHY_N(0x0B5) /* TX frame delay */ -#define B43_NPHY_MLPARM B43_PHY_N(0x0B6) /* ML parameters */ -#define B43_NPHY_MLCTL B43_PHY_N(0x0B7) /* ML control */ -#define B43_NPHY_WWISE_20NCYCDAT B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */ -#define B43_NPHY_WWISE_40NCYCDAT B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */ -#define B43_NPHY_TGNSYNC_20NCYCDAT B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */ -#define B43_NPHY_TGNSYNC_40NCYCDAT B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */ -#define B43_NPHY_INITSWIZP B43_PHY_N(0x0BC) /* Initial swizzle pattern */ -#define B43_NPHY_TXTAILCNT B43_PHY_N(0x0BD) /* TX tail count value */ -#define B43_NPHY_BPHY_CTL1 B43_PHY_N(0x0BE) /* B PHY control 1 */ -#define B43_NPHY_BPHY_CTL2 B43_PHY_N(0x0BF) /* B PHY control 2 */ -#define B43_NPHY_BPHY_CTL2_LUT 0x001F /* LUT index */ -#define B43_NPHY_BPHY_CTL2_LUT_SHIFT 0 -#define B43_NPHY_BPHY_CTL2_MACDEL 0x7FE0 /* MAC delay */ -#define B43_NPHY_BPHY_CTL2_MACDEL_SHIFT 5 -#define B43_NPHY_IQLOCAL_CMD B43_PHY_N(0x0C0) /* I/Q LO cal command */ -#define B43_NPHY_IQLOCAL_CMD_EN 0x8000 -#define B43_NPHY_IQLOCAL_CMDNNUM B43_PHY_N(0x0C1) /* I/Q LO cal command N num */ -#define B43_NPHY_IQLOCAL_CMDGCTL B43_PHY_N(0x0C2) /* I/Q LO cal command G control */ -#define B43_NPHY_SAMP_CMD B43_PHY_N(0x0C3) /* Sample command */ -#define B43_NPHY_SAMP_CMD_STOP 0x0002 /* Stop */ -#define B43_NPHY_SAMP_LOOPCNT B43_PHY_N(0x0C4) /* Sample loop count */ -#define B43_NPHY_SAMP_WAITCNT B43_PHY_N(0x0C5) /* Sample wait count */ -#define B43_NPHY_SAMP_DEPCNT B43_PHY_N(0x0C6) /* Sample depth count */ -#define B43_NPHY_SAMP_STAT B43_PHY_N(0x0C7) /* Sample status */ -#define B43_NPHY_GPIO_LOOEN B43_PHY_N(0x0C8) /* GPIO low out enable */ -#define B43_NPHY_GPIO_HIOEN B43_PHY_N(0x0C9) /* GPIO high out enable */ -#define B43_NPHY_GPIO_SEL B43_PHY_N(0x0CA) /* GPIO select */ -#define B43_NPHY_GPIO_CLKCTL B43_PHY_N(0x0CB) /* GPIO clock control */ -#define B43_NPHY_TXF_20CO_AS0 B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */ -#define B43_NPHY_TXF_20CO_AS1 B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */ -#define B43_NPHY_TXF_20CO_AS2 B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */ -#define B43_NPHY_TXF_20CO_B32S0 B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */ -#define B43_NPHY_TXF_20CO_B1S0 B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */ -#define B43_NPHY_TXF_20CO_B32S1 B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */ -#define B43_NPHY_TXF_20CO_B1S1 B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */ -#define B43_NPHY_TXF_20CO_B32S2 B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */ -#define B43_NPHY_TXF_20CO_B1S2 B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */ -#define B43_NPHY_SIGFLDTOL B43_PHY_N(0x0D5) /* Signal fld tolerance */ -#define B43_NPHY_TXSERFLD B43_PHY_N(0x0D6) /* TX service field */ -#define B43_NPHY_AFESEQ_RX2TX_PUD B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */ -#define B43_NPHY_AFESEQ_TX2RX_PUD B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */ -#define B43_NPHY_TGNSYNC_SCRAMI0 B43_PHY_N(0x0D9) /* TGNsync scram init 0 */ -#define B43_NPHY_TGNSYNC_SCRAMI1 B43_PHY_N(0x0DA) /* TGNsync scram init 1 */ -#define B43_NPHY_INITSWIZPATTLEG B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */ -#define B43_NPHY_BPHY_CTL3 B43_PHY_N(0x0DC) /* B PHY control 3 */ -#define B43_NPHY_BPHY_CTL3_SCALE 0x00FF /* Scale */ -#define B43_NPHY_BPHY_CTL3_SCALE_SHIFT 0 -#define B43_NPHY_BPHY_CTL3_FSC 0xFF00 /* Frame start count value */ -#define B43_NPHY_BPHY_CTL3_FSC_SHIFT 8 -#define B43_NPHY_BPHY_CTL4 B43_PHY_N(0x0DD) /* B PHY control 4 */ -#define B43_NPHY_C1_TXBBMULT B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */ -#define B43_NPHY_C2_TXBBMULT B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */ -#define B43_NPHY_TXF_40CO_AS0 B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */ -#define B43_NPHY_TXF_40CO_AS1 B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */ -#define B43_NPHY_TXF_40CO_AS2 B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */ -#define B43_NPHY_TXF_40CO_B32S0 B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */ -#define B43_NPHY_TXF_40CO_B1S0 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */ -#define B43_NPHY_TXF_40CO_B32S1 B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */ -#define B43_NPHY_TXF_40CO_B1S1 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */ -#define B43_NPHY_TXF_40CO_B32S2 B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */ -#define B43_NPHY_TXF_40CO_B1S2 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */ -#define B43_NPHY_BIST_STAT2 B43_PHY_N(0x0EA) /* BIST status 2 */ -#define B43_NPHY_BIST_STAT3 B43_PHY_N(0x0EB) /* BIST status 3 */ -#define B43_NPHY_RFCTL_OVER B43_PHY_N(0x0EC) /* RF control override */ -#define B43_NPHY_MIMOCFG B43_PHY_N(0x0ED) /* MIMO config */ -#define B43_NPHY_MIMOCFG_GFMIX 0x0004 /* Greenfield or mixed mode */ -#define B43_NPHY_MIMOCFG_AUTO 0x0100 /* Greenfield/mixed mode auto */ -#define B43_NPHY_RADAR_BLNKCTL B43_PHY_N(0x0EE) /* Radar blank control */ -#define B43_NPHY_A0RADAR_FIFOCTL B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */ -#define B43_NPHY_A1RADAR_FIFOCTL B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */ -#define B43_NPHY_A0RADAR_FIFODAT B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */ -#define B43_NPHY_A1RADAR_FIFODAT B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */ -#define B43_NPHY_RADAR_THRES0 B43_PHY_N(0x0F3) /* Radar threshold 0 */ -#define B43_NPHY_RADAR_THRES1 B43_PHY_N(0x0F4) /* Radar threshold 1 */ -#define B43_NPHY_RADAR_THRES0R B43_PHY_N(0x0F5) /* Radar threshold 0R */ -#define B43_NPHY_RADAR_THRES1R B43_PHY_N(0x0F6) /* Radar threshold 1R */ -#define B43_NPHY_CSEN_20IN40_DLEN B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */ -#define B43_NPHY_RFCTL_LUT_TRSW_LO1 B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */ -#define B43_NPHY_RFCTL_LUT_TRSW_UP1 B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */ -#define B43_NPHY_RFCTL_LUT_TRSW_LO2 B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */ -#define B43_NPHY_RFCTL_LUT_TRSW_UP2 B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */ -#define B43_NPHY_RFCTL_LUT_TRSW_LO3 B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */ -#define B43_NPHY_RFCTL_LUT_TRSW_UP3 B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */ -#define B43_NPHY_RFCTL_LUT_TRSW_LO4 B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */ -#define B43_NPHY_RFCTL_LUT_TRSW_UP4 B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */ -#define B43_NPHY_RFCTL_LUT_LNAPA1 B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */ -#define B43_NPHY_RFCTL_LUT_LNAPA2 B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */ -#define B43_NPHY_RFCTL_LUT_LNAPA3 B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */ -#define B43_NPHY_RFCTL_LUT_LNAPA4 B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */ -#define B43_NPHY_TGNSYNC_CRCM0 B43_PHY_N(0x104) /* TGNsync CRC mask 0 */ -#define B43_NPHY_TGNSYNC_CRCM1 B43_PHY_N(0x105) /* TGNsync CRC mask 1 */ -#define B43_NPHY_TGNSYNC_CRCM2 B43_PHY_N(0x106) /* TGNsync CRC mask 2 */ -#define B43_NPHY_TGNSYNC_CRCM3 B43_PHY_N(0x107) /* TGNsync CRC mask 3 */ -#define B43_NPHY_TGNSYNC_CRCM4 B43_PHY_N(0x108) /* TGNsync CRC mask 4 */ -#define B43_NPHY_CRCPOLY B43_PHY_N(0x109) /* CRC polynomial */ -#define B43_NPHY_SIGCNT B43_PHY_N(0x10A) /* # sig count */ -#define B43_NPHY_SIGSTARTBIT_CTL B43_PHY_N(0x10B) /* Sig start bit control */ -#define B43_NPHY_CRCPOLY_ORDER B43_PHY_N(0x10C) /* CRC polynomial order */ -#define B43_NPHY_RFCTL_CST0 B43_PHY_N(0x10D) /* RF control core swap table 0 */ -#define B43_NPHY_RFCTL_CST1 B43_PHY_N(0x10E) /* RF control core swap table 1 */ -#define B43_NPHY_RFCTL_CST2O B43_PHY_N(0x10F) /* RF control core swap table 2 + others */ -#define B43_NPHY_BPHY_CTL5 B43_PHY_N(0x111) /* B PHY control 5 */ -#define B43_NPHY_RFSEQ_LPFBW B43_PHY_N(0x112) /* RF seq LPF bandwidth */ -#define B43_NPHY_TSSIBIAS1 B43_PHY_N(0x114) /* TSSI bias val 1 */ -#define B43_NPHY_TSSIBIAS2 B43_PHY_N(0x115) /* TSSI bias val 2 */ -#define B43_NPHY_TSSIBIAS_BIAS 0x00FF /* Bias */ -#define B43_NPHY_TSSIBIAS_BIAS_SHIFT 0 -#define B43_NPHY_TSSIBIAS_VAL 0xFF00 /* Value */ -#define B43_NPHY_TSSIBIAS_VAL_SHIFT 8 -#define B43_NPHY_ESTPWR1 B43_PHY_N(0x118) /* Estimated power 1 */ -#define B43_NPHY_ESTPWR2 B43_PHY_N(0x119) /* Estimated power 2 */ -#define B43_NPHY_ESTPWR_PWR 0x00FF /* Estimated power */ -#define B43_NPHY_ESTPWR_PWR_SHIFT 0 -#define B43_NPHY_ESTPWR_VALID 0x0100 /* Estimated power valid */ -#define B43_NPHY_TSSI_MAXTXFDT B43_PHY_N(0x11C) /* TSSI max TX frame delay time */ -#define B43_NPHY_TSSI_MAXTXFDT_VAL 0x00FF /* max TX frame delay time */ -#define B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT 0 -#define B43_NPHY_TSSI_MAXTDT B43_PHY_N(0x11D) /* TSSI max TSSI delay time */ -#define B43_NPHY_TSSI_MAXTDT_VAL 0x00FF /* max TSSI delay time */ -#define B43_NPHY_TSSI_MAXTDT_VAL_SHIFT 0 -#define B43_NPHY_ITSSI1 B43_PHY_N(0x11E) /* TSSI idle 1 */ -#define B43_NPHY_ITSSI2 B43_PHY_N(0x11F) /* TSSI idle 2 */ -#define B43_NPHY_ITSSI_VAL 0x00FF /* Idle TSSI */ -#define B43_NPHY_ITSSI_VAL_SHIFT 0 -#define B43_NPHY_TSSIMODE B43_PHY_N(0x122) /* TSSI mode */ -#define B43_NPHY_TSSIMODE_EN 0x0001 /* TSSI enable */ -#define B43_NPHY_TSSIMODE_PDEN 0x0002 /* Power det enable */ -#define B43_NPHY_RXMACIFM B43_PHY_N(0x123) /* RX Macif mode */ -#define B43_NPHY_CRSIT_COCNT_LO B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */ -#define B43_NPHY_CRSIT_COCNT_HI B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */ -#define B43_NPHY_CRSIT_MTCNT_LO B43_PHY_N(0x126) /* CRS idle time measure time count (low) */ -#define B43_NPHY_CRSIT_MTCNT_HI B43_PHY_N(0x127) /* CRS idle time measure time count (high) */ -#define B43_NPHY_SAMTWC B43_PHY_N(0x128) /* Sample tail wait count */ -#define B43_NPHY_IQEST_CMD B43_PHY_N(0x129) /* I/Q estimate command */ -#define B43_NPHY_IQEST_CMD_START 0x0001 /* Start */ -#define B43_NPHY_IQEST_CMD_MODE 0x0002 /* Mode */ -#define B43_NPHY_IQEST_WT B43_PHY_N(0x12A) /* I/Q estimate wait time */ -#define B43_NPHY_IQEST_WT_VAL 0x00FF /* Wait time */ -#define B43_NPHY_IQEST_WT_VAL_SHIFT 0 -#define B43_NPHY_IQEST_SAMCNT B43_PHY_N(0x12B) /* I/Q estimate sample count */ -#define B43_NPHY_IQEST_IQACC_LO0 B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */ -#define B43_NPHY_IQEST_IQACC_HI0 B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */ -#define B43_NPHY_IQEST_IPACC_LO0 B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */ -#define B43_NPHY_IQEST_IPACC_HI0 B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */ -#define B43_NPHY_IQEST_QPACC_LO0 B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */ -#define B43_NPHY_IQEST_QPACC_HI0 B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */ -#define B43_NPHY_IQEST_IQACC_LO1 B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */ -#define B43_NPHY_IQEST_IQACC_HI1 B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */ -#define B43_NPHY_IQEST_IPACC_LO1 B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */ -#define B43_NPHY_IQEST_IPACC_HI1 B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */ -#define B43_NPHY_IQEST_QPACC_LO1 B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */ -#define B43_NPHY_IQEST_QPACC_HI1 B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */ -#define B43_NPHY_MIMO_CRSTXEXT B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */ -#define B43_NPHY_PWRDET1 B43_PHY_N(0x13B) /* Power det 1 */ -#define B43_NPHY_PWRDET2 B43_PHY_N(0x13C) /* Power det 2 */ -#define B43_NPHY_MAXRSSI_DTIME B43_PHY_N(0x13F) /* RSSI max RSSI delay time */ -#define B43_NPHY_PIL_DW0 B43_PHY_N(0x141) /* Pilot data weight 0 */ -#define B43_NPHY_PIL_DW1 B43_PHY_N(0x142) /* Pilot data weight 1 */ -#define B43_NPHY_PIL_DW2 B43_PHY_N(0x143) /* Pilot data weight 2 */ -#define B43_NPHY_PIL_DW_BPSK 0x000F /* BPSK */ -#define B43_NPHY_PIL_DW_BPSK_SHIFT 0 -#define B43_NPHY_PIL_DW_QPSK 0x00F0 /* QPSK */ -#define B43_NPHY_PIL_DW_QPSK_SHIFT 4 -#define B43_NPHY_PIL_DW_16QAM 0x0F00 /* 16-QAM */ -#define B43_NPHY_PIL_DW_16QAM_SHIFT 8 -#define B43_NPHY_PIL_DW_64QAM 0xF000 /* 64-QAM */ -#define B43_NPHY_PIL_DW_64QAM_SHIFT 12 -#define B43_NPHY_FMDEM_CFG B43_PHY_N(0x144) /* FM demodulation config */ -#define B43_NPHY_PHASETR_A0 B43_PHY_N(0x145) /* Phase track alpha 0 */ -#define B43_NPHY_PHASETR_A1 B43_PHY_N(0x146) /* Phase track alpha 1 */ -#define B43_NPHY_PHASETR_A2 B43_PHY_N(0x147) /* Phase track alpha 2 */ -#define B43_NPHY_PHASETR_B0 B43_PHY_N(0x148) /* Phase track beta 0 */ -#define B43_NPHY_PHASETR_B1 B43_PHY_N(0x149) /* Phase track beta 1 */ -#define B43_NPHY_PHASETR_B2 B43_PHY_N(0x14A) /* Phase track beta 2 */ -#define B43_NPHY_PHASETR_CHG0 B43_PHY_N(0x14B) /* Phase track change 0 */ -#define B43_NPHY_PHASETR_CHG1 B43_PHY_N(0x14C) /* Phase track change 1 */ -#define B43_NPHY_PHASETW_OFF B43_PHY_N(0x14D) /* Phase track offset */ -#define B43_NPHY_RFCTL_DBG B43_PHY_N(0x14E) /* RF control debug */ -#define B43_NPHY_CCK_SHIFTB_REF B43_PHY_N(0x150) /* CCK shiftbits reference var */ -#define B43_NPHY_OVER_DGAIN0 B43_PHY_N(0x152) /* Override digital gain 0 */ -#define B43_NPHY_OVER_DGAIN1 B43_PHY_N(0x153) /* Override digital gain 1 */ -#define B43_NPHY_OVER_DGAIN_FDGV 0x0007 /* Force digital gain value */ -#define B43_NPHY_OVER_DGAIN_FDGV_SHIFT 0 -#define B43_NPHY_OVER_DGAIN_FDGEN 0x0008 /* Force digital gain enable */ -#define B43_NPHY_OVER_DGAIN_CCKDGECV 0xFF00 /* CCK digital gain enable count value */ -#define B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT 8 -#define B43_NPHY_BIST_STAT4 B43_PHY_N(0x156) /* BIST status 4 */ -#define B43_NPHY_RADAR_MAL B43_PHY_N(0x157) /* Radar MA length */ -#define B43_NPHY_RADAR_SRCCTL B43_PHY_N(0x158) /* Radar search control */ -#define B43_NPHY_VLD_DTSIG B43_PHY_N(0x159) /* VLD data tones sig */ -#define B43_NPHY_VLD_DTDAT B43_PHY_N(0x15A) /* VLD data tones data */ -#define B43_NPHY_C1_BPHY_RXIQCA0 B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */ -#define B43_NPHY_C1_BPHY_RXIQCB0 B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */ -#define B43_NPHY_C2_BPHY_RXIQCA1 B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */ -#define B43_NPHY_C2_BPHY_RXIQCB1 B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */ -#define B43_NPHY_FREQGAIN0 B43_PHY_N(0x160) /* Frequency gain 0 */ -#define B43_NPHY_FREQGAIN1 B43_PHY_N(0x161) /* Frequency gain 1 */ -#define B43_NPHY_FREQGAIN2 B43_PHY_N(0x162) /* Frequency gain 2 */ -#define B43_NPHY_FREQGAIN3 B43_PHY_N(0x163) /* Frequency gain 3 */ -#define B43_NPHY_FREQGAIN4 B43_PHY_N(0x164) /* Frequency gain 4 */ -#define B43_NPHY_FREQGAIN5 B43_PHY_N(0x165) /* Frequency gain 5 */ -#define B43_NPHY_FREQGAIN6 B43_PHY_N(0x166) /* Frequency gain 6 */ -#define B43_NPHY_FREQGAIN7 B43_PHY_N(0x167) /* Frequency gain 7 */ -#define B43_NPHY_FREQGAIN_BYPASS B43_PHY_N(0x168) /* Frequency gain bypass */ -#define B43_NPHY_TRLOSS B43_PHY_N(0x169) /* TR loss value */ -#define B43_NPHY_C1_ADCCLIP B43_PHY_N(0x16A) /* Core 1 ADC clip */ -#define B43_NPHY_C2_ADCCLIP B43_PHY_N(0x16B) /* Core 2 ADC clip */ -#define B43_NPHY_LTRN_OFFGAIN B43_PHY_N(0x16F) /* LTRN offset gain */ -#define B43_NPHY_LTRN_OFF B43_PHY_N(0x170) /* LTRN offset */ -#define B43_NPHY_NRDATAT_WWISE20SIG B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */ -#define B43_NPHY_NRDATAT_WWISE40SIG B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */ -#define B43_NPHY_NRDATAT_TGNSYNC20SIG B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */ -#define B43_NPHY_NRDATAT_TGNSYNC40SIG B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */ -#define B43_NPHY_WWISE_CRCM0 B43_PHY_N(0x175) /* WWiSE CRC mask 0 */ -#define B43_NPHY_WWISE_CRCM1 B43_PHY_N(0x176) /* WWiSE CRC mask 1 */ -#define B43_NPHY_WWISE_CRCM2 B43_PHY_N(0x177) /* WWiSE CRC mask 2 */ -#define B43_NPHY_WWISE_CRCM3 B43_PHY_N(0x178) /* WWiSE CRC mask 3 */ -#define B43_NPHY_WWISE_CRCM4 B43_PHY_N(0x179) /* WWiSE CRC mask 4 */ -#define B43_NPHY_CHANEST_CDDSH B43_PHY_N(0x17A) /* Channel estimate CDD shift */ -#define B43_NPHY_HTAGC_WCNT B43_PHY_N(0x17B) /* HT ADC wait counters */ -#define B43_NPHY_SQPARM B43_PHY_N(0x17C) /* SQ params */ -#define B43_NPHY_MCSDUP6M B43_PHY_N(0x17D) /* MCS dup 6M */ -#define B43_NPHY_NDATAT_DUP40 B43_PHY_N(0x17E) /* # data tones dup 40 */ -#define B43_NPHY_DUP40_TGNSYNC_CYCD B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */ -#define B43_NPHY_DUP40_GFBL B43_PHY_N(0x180) /* Dup40 GF format BL address */ -#define B43_NPHY_DUP40_BL B43_PHY_N(0x181) /* Dup40 format BL address */ -#define B43_NPHY_LEGDUP_FTA B43_PHY_N(0x182) /* Legacy dup frm table address */ -#define B43_NPHY_PACPROC_DBG B43_PHY_N(0x183) /* Packet processing debug */ -#define B43_NPHY_PIL_CYC1 B43_PHY_N(0x184) /* Pilot cycle counter 1 */ -#define B43_NPHY_PIL_CYC2 B43_PHY_N(0x185) /* Pilot cycle counter 2 */ -#define B43_NPHY_TXF_20CO_S0A1 B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */ -#define B43_NPHY_TXF_20CO_S0A2 B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */ -#define B43_NPHY_TXF_20CO_S1A1 B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */ -#define B43_NPHY_TXF_20CO_S1A2 B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */ -#define B43_NPHY_TXF_20CO_S2A1 B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */ -#define B43_NPHY_TXF_20CO_S2A2 B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */ -#define B43_NPHY_TXF_20CO_S0B1 B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */ -#define B43_NPHY_TXF_20CO_S0B2 B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */ -#define B43_NPHY_TXF_20CO_S0B3 B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */ -#define B43_NPHY_TXF_20CO_S1B1 B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */ -#define B43_NPHY_TXF_20CO_S1B2 B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */ -#define B43_NPHY_TXF_20CO_S1B3 B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */ -#define B43_NPHY_TXF_20CO_S2B1 B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */ -#define B43_NPHY_TXF_20CO_S2B2 B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */ -#define B43_NPHY_TXF_20CO_S2B3 B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */ -#define B43_NPHY_TXF_40CO_S0A1 B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */ -#define B43_NPHY_TXF_40CO_S0A2 B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */ -#define B43_NPHY_TXF_40CO_S1A1 B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */ -#define B43_NPHY_TXF_40CO_S1A2 B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */ -#define B43_NPHY_TXF_40CO_S2A1 B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */ -#define B43_NPHY_TXF_40CO_S2A2 B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */ -#define B43_NPHY_TXF_40CO_S0B1 B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */ -#define B43_NPHY_TXF_40CO_S0B2 B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */ -#define B43_NPHY_TXF_40CO_S0B3 B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */ -#define B43_NPHY_TXF_40CO_S1B1 B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */ -#define B43_NPHY_TXF_40CO_S1B2 B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */ -#define B43_NPHY_TXF_40CO_S1B3 B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */ -#define B43_NPHY_TXF_40CO_S2B1 B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */ -#define B43_NPHY_TXF_40CO_S2B2 B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */ -#define B43_NPHY_TXF_40CO_S2B3 B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */ -#define B43_NPHY_RSSIMC_0I_RSSI_X B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */ -#define B43_NPHY_RSSIMC_0I_RSSI_Y B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */ -#define B43_NPHY_RSSIMC_0I_RSSI_Z B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */ -#define B43_NPHY_RSSIMC_0I_TBD B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */ -#define B43_NPHY_RSSIMC_0I_PWRDET B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */ -#define B43_NPHY_RSSIMC_0I_TSSI B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */ -#define B43_NPHY_RSSIMC_0Q_RSSI_X B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */ -#define B43_NPHY_RSSIMC_0Q_RSSI_Y B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */ -#define B43_NPHY_RSSIMC_0Q_RSSI_Z B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */ -#define B43_NPHY_RSSIMC_0Q_TBD B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */ -#define B43_NPHY_RSSIMC_0Q_PWRDET B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */ -#define B43_NPHY_RSSIMC_0Q_TSSI B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */ -#define B43_NPHY_RSSIMC_1I_RSSI_X B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */ -#define B43_NPHY_RSSIMC_1I_RSSI_Y B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */ -#define B43_NPHY_RSSIMC_1I_RSSI_Z B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */ -#define B43_NPHY_RSSIMC_1I_TBD B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */ -#define B43_NPHY_RSSIMC_1I_PWRDET B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */ -#define B43_NPHY_RSSIMC_1I_TSSI B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */ -#define B43_NPHY_RSSIMC_1Q_RSSI_X B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */ -#define B43_NPHY_RSSIMC_1Q_RSSI_Y B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */ -#define B43_NPHY_RSSIMC_1Q_RSSI_Z B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */ -#define B43_NPHY_RSSIMC_1Q_TBD B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */ -#define B43_NPHY_RSSIMC_1Q_PWRDET B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */ -#define B43_NPHY_RSSIMC_1Q_TSSI B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */ -#define B43_NPHY_SAMC_WCNT B43_PHY_N(0x1BC) /* Sample collect wait counter */ -#define B43_NPHY_PTHROUGH_CNT B43_PHY_N(0x1BD) /* Pass-through counter */ -#define B43_NPHY_LTRN_OFF_G20L B43_PHY_N(0x1C4) /* LTRN offset gain 20L */ -#define B43_NPHY_LTRN_OFF_20L B43_PHY_N(0x1C5) /* LTRN offset 20L */ -#define B43_NPHY_LTRN_OFF_G20U B43_PHY_N(0x1C6) /* LTRN offset gain 20U */ -#define B43_NPHY_LTRN_OFF_20U B43_PHY_N(0x1C7) /* LTRN offset 20U */ -#define B43_NPHY_DSSSCCK_GAINSL B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */ -#define B43_NPHY_GPIO_LOOUT B43_PHY_N(0x1C9) /* GPIO low out */ -#define B43_NPHY_GPIO_HIOUT B43_PHY_N(0x1CA) /* GPIO high out */ -#define B43_NPHY_CRS_CHECK B43_PHY_N(0x1CB) /* CRS check */ -#define B43_NPHY_ML_LOGSS_RAT B43_PHY_N(0x1CC) /* ML/logss ratio */ -#define B43_NPHY_DUPSCALE B43_PHY_N(0x1CD) /* Dup scale */ -#define B43_NPHY_BW1A B43_PHY_N(0x1CE) /* BW 1A */ -#define B43_NPHY_BW2 B43_PHY_N(0x1CF) /* BW 2 */ -#define B43_NPHY_BW3 B43_PHY_N(0x1D0) /* BW 3 */ -#define B43_NPHY_BW4 B43_PHY_N(0x1D1) /* BW 4 */ -#define B43_NPHY_BW5 B43_PHY_N(0x1D2) /* BW 5 */ -#define B43_NPHY_BW6 B43_PHY_N(0x1D3) /* BW 6 */ -#define B43_NPHY_COALEN0 B43_PHY_N(0x1D4) /* Coarse length 0 */ -#define B43_NPHY_COALEN1 B43_PHY_N(0x1D5) /* Coarse length 1 */ -#define B43_NPHY_CRSTHRES_1U B43_PHY_N(0x1D6) /* CRS threshold 1 U */ -#define B43_NPHY_CRSTHRES_2U B43_PHY_N(0x1D7) /* CRS threshold 2 U */ -#define B43_NPHY_CRSTHRES_3U B43_PHY_N(0x1D8) /* CRS threshold 3 U */ -#define B43_NPHY_CRSCTL_U B43_PHY_N(0x1D9) /* CRS control U */ -#define B43_NPHY_CRSTHRES_1L B43_PHY_N(0x1DA) /* CRS threshold 1 L */ -#define B43_NPHY_CRSTHRES_2L B43_PHY_N(0x1DB) /* CRS threshold 2 L */ -#define B43_NPHY_CRSTHRES_3L B43_PHY_N(0x1DC) /* CRS threshold 3 L */ -#define B43_NPHY_CRSCTL_L B43_PHY_N(0x1DD) /* CRS control L */ -#define B43_NPHY_STRA_1U B43_PHY_N(0x1DE) /* STR address 1 U */ -#define B43_NPHY_STRA_2U B43_PHY_N(0x1DF) /* STR address 2 U */ -#define B43_NPHY_STRA_1L B43_PHY_N(0x1E0) /* STR address 1 L */ -#define B43_NPHY_STRA_2L B43_PHY_N(0x1E1) /* STR address 2 L */ -#define B43_NPHY_CRSCHECK1 B43_PHY_N(0x1E2) /* CRS check 1 */ -#define B43_NPHY_CRSCHECK2 B43_PHY_N(0x1E3) /* CRS check 2 */ -#define B43_NPHY_CRSCHECK3 B43_PHY_N(0x1E4) /* CRS check 3 */ -#define B43_NPHY_JMPSTP0 B43_PHY_N(0x1E5) /* Jump step 0 */ -#define B43_NPHY_JMPSTP1 B43_PHY_N(0x1E6) /* Jump step 1 */ -#define B43_NPHY_TXPCTL_CMD B43_PHY_N(0x1E7) /* TX power control command */ -#define B43_NPHY_TXPCTL_CMD_INIT 0x007F /* Init */ -#define B43_NPHY_TXPCTL_CMD_INIT_SHIFT 0 -#define B43_NPHY_TXPCTL_CMD_COEFF 0x2000 /* Power control coefficients */ -#define B43_NPHY_TXPCTL_CMD_HWPCTLEN 0x4000 /* Hardware TX power control enable */ -#define B43_NPHY_TXPCTL_CMD_PCTLEN 0x8000 /* TX power control enable */ -#define B43_NPHY_TXPCTL_N B43_PHY_N(0x1E8) /* TX power control N num */ -#define B43_NPHY_TXPCTL_N_TSSID 0x00FF /* N TSSI delay */ -#define B43_NPHY_TXPCTL_N_TSSID_SHIFT 0 -#define B43_NPHY_TXPCTL_N_NPTIL2 0x0700 /* N PT integer log2 */ -#define B43_NPHY_TXPCTL_N_NPTIL2_SHIFT 8 -#define B43_NPHY_TXPCTL_ITSSI B43_PHY_N(0x1E9) /* TX power control idle TSSI */ -#define B43_NPHY_TXPCTL_ITSSI_0 0x003F /* Idle TSSI 0 */ -#define B43_NPHY_TXPCTL_ITSSI_0_SHIFT 0 -#define B43_NPHY_TXPCTL_ITSSI_1 0x3F00 /* Idle TSSI 1 */ -#define B43_NPHY_TXPCTL_ITSSI_1_SHIFT 8 -#define B43_NPHY_TXPCTL_ITSSI_BINF 0x8000 /* Raw TSSI offset bin format */ -#define B43_NPHY_TXPCTL_TPWR B43_PHY_N(0x1EA) /* TX power control target power */ -#define B43_NPHY_TXPCTL_TPWR_0 0x00FF /* Power 0 */ -#define B43_NPHY_TXPCTL_TPWR_0_SHIFT 0 -#define B43_NPHY_TXPCTL_TPWR_1 0xFF00 /* Power 1 */ -#define B43_NPHY_TXPCTL_TPWR_1_SHIFT 8 -#define B43_NPHY_TXPCTL_BIDX B43_PHY_N(0x1EB) /* TX power control base index */ -#define B43_NPHY_TXPCTL_BIDX_0 0x007F /* uC base index 0 */ -#define B43_NPHY_TXPCTL_BIDX_0_SHIFT 0 -#define B43_NPHY_TXPCTL_BIDX_1 0x7F00 /* uC base index 1 */ -#define B43_NPHY_TXPCTL_BIDX_1_SHIFT 8 -#define B43_NPHY_TXPCTL_BIDX_LOAD 0x8000 /* Load base index */ -#define B43_NPHY_TXPCTL_PIDX B43_PHY_N(0x1EC) /* TX power control power index */ -#define B43_NPHY_TXPCTL_PIDX_0 0x007F /* uC power index 0 */ -#define B43_NPHY_TXPCTL_PIDX_0_SHIFT 0 -#define B43_NPHY_TXPCTL_PIDX_1 0x7F00 /* uC power index 1 */ -#define B43_NPHY_TXPCTL_PIDX_1_SHIFT 8 -#define B43_NPHY_C1_TXPCTL_STAT B43_PHY_N(0x1ED) /* Core 1 TX power control status */ -#define B43_NPHY_C2_TXPCTL_STAT B43_PHY_N(0x1EE) /* Core 2 TX power control status */ -#define B43_NPHY_TXPCTL_STAT_EST 0x00FF /* Estimated power */ -#define B43_NPHY_TXPCTL_STAT_EST_SHIFT 0 -#define B43_NPHY_TXPCTL_STAT_BIDX 0x7F00 /* Base index */ -#define B43_NPHY_TXPCTL_STAT_BIDX_SHIFT 8 -#define B43_NPHY_TXPCTL_STAT_ESTVALID 0x8000 /* Estimated power valid */ -#define B43_NPHY_SMALLSGS_LEN B43_PHY_N(0x1EF) /* Small sig gain settle length */ -#define B43_NPHY_PHYSTAT_GAIN0 B43_PHY_N(0x1F0) /* PHY stats gain info 0 */ -#define B43_NPHY_PHYSTAT_GAIN1 B43_PHY_N(0x1F1) /* PHY stats gain info 1 */ -#define B43_NPHY_PHYSTAT_FREQEST B43_PHY_N(0x1F2) /* PHY stats frequency estimate */ -#define B43_NPHY_PHYSTAT_ADVRET B43_PHY_N(0x1F3) /* PHY stats ADV retard */ -#define B43_NPHY_PHYLB_MODE B43_PHY_N(0x1F4) /* PHY loopback mode */ -#define B43_NPHY_TONE_MIDX20_1 B43_PHY_N(0x1F5) /* Tone map index 20/1 */ -#define B43_NPHY_TONE_MIDX20_2 B43_PHY_N(0x1F6) /* Tone map index 20/2 */ -#define B43_NPHY_TONE_MIDX20_3 B43_PHY_N(0x1F7) /* Tone map index 20/3 */ -#define B43_NPHY_TONE_MIDX40_1 B43_PHY_N(0x1F8) /* Tone map index 40/1 */ -#define B43_NPHY_TONE_MIDX40_2 B43_PHY_N(0x1F9) /* Tone map index 40/2 */ -#define B43_NPHY_TONE_MIDX40_3 B43_PHY_N(0x1FA) /* Tone map index 40/3 */ -#define B43_NPHY_TONE_MIDX40_4 B43_PHY_N(0x1FB) /* Tone map index 40/4 */ -#define B43_NPHY_PILTONE_MIDX1 B43_PHY_N(0x1FC) /* Pilot tone map index 1 */ -#define B43_NPHY_PILTONE_MIDX2 B43_PHY_N(0x1FD) /* Pilot tone map index 2 */ -#define B43_NPHY_PILTONE_MIDX3 B43_PHY_N(0x1FE) /* Pilot tone map index 3 */ -#define B43_NPHY_TXRIFS_FRDEL B43_PHY_N(0x1FF) /* TX RIFS frame delay */ -#define B43_NPHY_AFESEQ_RX2TX_PUD_40M B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */ -#define B43_NPHY_AFESEQ_TX2RX_PUD_40M B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */ -#define B43_NPHY_AFESEQ_RX2TX_PUD_20M B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */ -#define B43_NPHY_AFESEQ_TX2RX_PUD_20M B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */ -#define B43_NPHY_RX_SIGCTL B43_PHY_N(0x204) /* RX signal control */ -#define B43_NPHY_RXPIL_CYCNT0 B43_PHY_N(0x205) /* RX pilot cycle counter 0 */ -#define B43_NPHY_RXPIL_CYCNT1 B43_PHY_N(0x206) /* RX pilot cycle counter 1 */ -#define B43_NPHY_RXPIL_CYCNT2 B43_PHY_N(0x207) /* RX pilot cycle counter 2 */ -#define B43_NPHY_AFESEQ_RX2TX_PUD_10M B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */ -#define B43_NPHY_AFESEQ_TX2RX_PUD_10M B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */ -#define B43_NPHY_DSSSCCK_CRSEXTL B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */ -#define B43_NPHY_ML_LOGSS_RATSLOPE B43_PHY_N(0x20B) /* ML/logss ratio slope */ -#define B43_NPHY_RIFS_SRCTL B43_PHY_N(0x20C) /* RIFS search timeout length */ -#define B43_NPHY_TXREALFD B43_PHY_N(0x20D) /* TX real frame delay */ -#define B43_NPHY_HPANT_SWTHRES B43_PHY_N(0x20E) /* High power antenna switch threshold */ -#define B43_NPHY_EDCRS_ASSTHRES0 B43_PHY_N(0x210) /* ED CRS assert threshold 0 */ -#define B43_NPHY_EDCRS_ASSTHRES1 B43_PHY_N(0x211) /* ED CRS assert threshold 1 */ -#define B43_NPHY_EDCRS_DEASSTHRES0 B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */ -#define B43_NPHY_EDCRS_DEASSTHRES1 B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */ -#define B43_NPHY_STR_WTIME20U B43_PHY_N(0x214) /* STR wait time 20U */ -#define B43_NPHY_STR_WTIME20L B43_PHY_N(0x215) /* STR wait time 20L */ -#define B43_NPHY_TONE_MIDX657M B43_PHY_N(0x216) /* Tone map index 657M */ -#define B43_NPHY_HTSIGTONES B43_PHY_N(0x217) /* HT signal tones */ -#define B43_NPHY_RSSI1 B43_PHY_N(0x219) /* RSSI value 1 */ -#define B43_NPHY_RSSI2 B43_PHY_N(0x21A) /* RSSI value 2 */ -#define B43_NPHY_CHAN_ESTHANG B43_PHY_N(0x21D) /* Channel estimate hang */ -#define B43_NPHY_FINERX2_CGC B43_PHY_N(0x221) /* Fine RX 2 clock gate control */ -#define B43_NPHY_FINERX2_CGC_DECGC 0x0008 /* Decode gated clocks */ -#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ -#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ -#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 - - - -/* Broadcom 2055 radio registers */ - -#define B2055_GEN_SPARE 0x00 /* GEN spare */ -#define B2055_SP_PINPD 0x02 /* SP PIN PD */ -#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */ -#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */ -#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */ -#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */ -#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */ -#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */ -#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */ -#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */ -#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */ -#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */ -#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */ -#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */ -#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */ -#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */ -#define B2055_MASTER1 0x11 /* Master control 1 */ -#define B2055_MASTER2 0x12 /* Master control 2 */ -#define B2055_PD_LGEN 0x13 /* PD LGEN */ -#define B2055_PD_PLLTS 0x14 /* PD PLL TS */ -#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */ -#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */ -#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */ -#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */ -#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */ -#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */ -#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */ -#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */ -#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */ -#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */ -#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */ -#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */ -#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */ -#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */ -#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */ -#define B2055_CAL_MISC 0x24 /* CAL MISC */ -#define B2055_CAL_COUT 0x25 /* CAL Counter out */ -#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */ -#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */ -#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */ -#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */ -#define B2055_CAL_TS 0x2A /* CAL TS */ -#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */ -#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */ -#define B2055_PADDRV 0x2D /* PAD driver */ -#define B2055_XOCTL1 0x2E /* XO Control 1 */ -#define B2055_XOCTL2 0x2F /* XO Control 2 */ -#define B2055_XOREGUL 0x30 /* XO Regulator */ -#define B2055_XOMISC 0x31 /* XO misc */ -#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */ -#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */ -#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */ -#define B2055_PLL_REF 0x35 /* PLL reference */ -#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */ -#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */ -#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */ -#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */ -#define B2055_PLL_RCAL 0x3A /* PLL RCAL */ -#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */ -#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */ -#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */ -#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */ -#define B2055_RF_MMDSP 0x3F /* RF MMD spare */ -#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */ -#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */ -#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */ -#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */ -#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */ -#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */ -#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */ -#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */ -#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */ -#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */ -#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */ -#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */ -#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */ -#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */ -#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */ -#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */ -#define B2055_VCO_KVCO 0x50 /* VCO KVCO */ -#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */ -#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */ -#define B2055_VCO_REG 0x53 /* VCO Regulator */ -#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */ -#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */ -#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */ -#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */ -#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */ -#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */ -#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */ -#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */ -#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */ -#define B2055_LGEN_DIV 0x5D /* LGEN div */ -#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */ -#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */ -#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */ -#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */ -#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */ -#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */ -#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */ -#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */ -#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */ -#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */ -#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */ -#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */ -#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */ -#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */ -#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */ -#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */ -#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */ -#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */ -#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */ -#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */ -#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */ -#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */ -#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */ -#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */ -#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */ -#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */ -#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */ -#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */ -#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */ -#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */ -#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */ -#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */ -#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */ -#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */ -#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */ -#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */ -#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */ -#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */ -#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */ -#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */ -#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */ -#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */ -#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */ -#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */ -#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */ -#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */ -#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */ -#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */ -#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */ -#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */ -#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */ -#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */ -#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */ -#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */ -#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */ -#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */ -#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */ -#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */ -#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */ -#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */ -#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */ -#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */ -#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */ -#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */ -#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */ -#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */ -#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */ -#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */ -#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */ -#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */ -#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */ -#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */ -#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */ -#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */ -#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */ -#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */ -#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */ -#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */ -#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */ -#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */ -#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */ -#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */ -#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */ -#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */ -#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */ -#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */ -#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */ -#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */ -#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */ -#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */ -#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */ -#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */ -#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */ -#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */ -#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */ -#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */ -#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */ -#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */ -#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */ -#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */ -#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */ -#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */ -#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */ -#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */ -#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */ -#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */ -#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */ -#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */ -#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */ -#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */ -#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */ - - - -struct b43_wldev; - -struct b43_phy_n { - bool initialised; - - //TODO lots of missing stuff -}; - - -struct b43_phy_operations; -extern const struct b43_phy_operations b43_phyops_n; - -#endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 5a550a7af2e..4b6c944be04 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -29,7 +29,7 @@ #include "phy_common.h" #include "phy_g.h" #include "phy_a.h" -#include "nphy.h" +#include "phy_n.h" #include "b43.h" #include "main.h" diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c new file mode 100644 index 00000000000..8162fd7792f --- /dev/null +++ b/drivers/net/wireless/b43/phy_n.c @@ -0,0 +1,624 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n PHY support + + Copyright (c) 2008 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include + +#include "b43.h" +#include "phy_n.h" +#include "tables_nphy.h" + + +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) +{//TODO +} + +static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) +{//TODO +} + +static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + +static void b43_chantab_radio_upload(struct b43_wldev *dev, + const struct b43_nphy_channeltab_entry *e) +{ + b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref); + b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0); + b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1); + b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail); + b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1); + b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2); + b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1); + b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1); + b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2); + b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf); + b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1); + b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2); + b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune); + b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune); + b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1); + b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn); + b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim); + b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune); + b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune); + b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1); + b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn); + b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim); +} + +static void b43_chantab_phy_upload(struct b43_wldev *dev, + const struct b43_nphy_channeltab_entry *e) +{ + b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a); + b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2); + b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3); + b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4); + b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5); + b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6); +} + +static void b43_nphy_tx_power_fix(struct b43_wldev *dev) +{ + //TODO +} + +/* Tune the hardware to a new channel. */ +static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel) +{ + const struct b43_nphy_channeltab_entry *tabent; + + tabent = b43_nphy_get_chantabent(dev, channel); + if (!tabent) + return -ESRCH; + + //FIXME enable/disable band select upper20 in RXCTL + if (0 /*FIXME 5Ghz*/) + b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20); + else + b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50); + b43_chantab_radio_upload(dev, tabent); + udelay(50); + b43_radio_write16(dev, B2055_VCO_CAL10, 5); + b43_radio_write16(dev, B2055_VCO_CAL10, 45); + b43_radio_write16(dev, B2055_VCO_CAL10, 65); + udelay(300); + if (0 /*FIXME 5Ghz*/) + b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); + else + b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); + b43_chantab_phy_upload(dev, tabent); + b43_nphy_tx_power_fix(dev); + + return 0; +} + +static void b43_radio_init2055_pre(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_PORFORCE); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_CHIP0PU | + B43_NPHY_RFCTL_CMD_OEPORFORCE); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_PORFORCE); +} + +static void b43_radio_init2055_post(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo); + int i; + u16 val; + + b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); + msleep(1); + if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) { + if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) || + (binfo->type != 0x46D) || + (binfo->rev < 0x41)) { + b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); + b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); + msleep(1); + } + } + b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C); + msleep(1); + b43_radio_write16(dev, B2055_CAL_MISC, 0x3C); + msleep(1); + b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE); + msleep(1); + b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80); + msleep(1); + b43_radio_set(dev, B2055_CAL_MISC, 0x1); + msleep(1); + b43_radio_set(dev, B2055_CAL_MISC, 0x40); + msleep(1); + for (i = 0; i < 100; i++) { + val = b43_radio_read16(dev, B2055_CAL_COUT2); + if (val & 0x80) + break; + udelay(10); + } + msleep(1); + b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); + msleep(1); + nphy_channel_switch(dev, dev->phy.channel); + b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); + b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); + b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); + b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83); +} + +/* Initialize a Broadcom 2055 N-radio */ +static void b43_radio_init2055(struct b43_wldev *dev) +{ + b43_radio_init2055_pre(dev); + if (b43_status(dev) < B43_STAT_INITIALIZED) + b2055_upload_inittab(dev, 0, 1); + else + b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0); + b43_radio_init2055_post(dev); +} + +void b43_nphy_radio_turn_on(struct b43_wldev *dev) +{ + b43_radio_init2055(dev); +} + +void b43_nphy_radio_turn_off(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_EN); +} + +#define ntab_upload(dev, offset, data) do { \ + unsigned int i; \ + for (i = 0; i < (offset##_SIZE); i++) \ + b43_ntab_write(dev, (offset) + i, (data)[i]); \ + } while (0) + +/* Upload the N-PHY tables. */ +static void b43_nphy_tables_init(struct b43_wldev *dev) +{ + /* Static tables */ + ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); + ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); + ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); + ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); + ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); + ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); + ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); + ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); + ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); + ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); + ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); + ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); + ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); + ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); + + /* Volatile tables */ + ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); + ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); + ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); + ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); + ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); + ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); + ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); + ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); + ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); + ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); + ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); + ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); +} + +static void b43_nphy_workarounds(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + unsigned int i; + + b43_phy_set(dev, B43_NPHY_IQFLIP, + B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + if (1 /* FIXME band is 2.4GHz */) { + b43_phy_set(dev, B43_NPHY_CLASSCTL, + B43_NPHY_CLASSCTL_CCKEN); + } else { + b43_phy_mask(dev, B43_NPHY_CLASSCTL, + ~B43_NPHY_CLASSCTL_CCKEN); + } + b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); + b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8); + + /* Fixup some tables */ + b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800); + b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800); + + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); + + //TODO set RF sequence + + /* Set narrowband clip threshold */ + b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66); + b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66); + + /* Set wideband clip 2 threshold */ + b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, + ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, + ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT); + + /* Set Clip 2 detect */ + b43_phy_set(dev, B43_NPHY_C1_CGAINI, + B43_NPHY_C1_CGAINI_CL2DETECT); + b43_phy_set(dev, B43_NPHY_C2_CGAINI, + B43_NPHY_C2_CGAINI_CL2DETECT); + + if (0 /*FIXME*/) { + /* Set dwell lengths */ + b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9); + b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9); + + /* Set gain backoff */ + b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, + ~B43_NPHY_C1_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, + ~B43_NPHY_C2_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT); + + /* Set HPVGA2 index */ + b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, + ~B43_NPHY_C1_INITGAIN_HPVGA2, + 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, + ~B43_NPHY_C2_INITGAIN_HPVGA2, + 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); + + //FIXME verify that the specs really mean to use autoinc here. + for (i = 0; i < 3; i++) + b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673); + } + + /* Set minimum gain value */ + b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, + ~B43_NPHY_C1_MINGAIN, + 23 << B43_NPHY_C1_MINGAIN_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, + ~B43_NPHY_C2_MINGAIN, + 23 << B43_NPHY_C2_MINGAIN_SHIFT); + + if (phy->rev < 2) { + b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, + ~B43_NPHY_SCRAM_SIGCTL_SCM); + } + + /* Set phase track alpha and beta */ + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); +} + +static void b43_nphy_reset_cca(struct b43_wldev *dev) +{ + u16 bbcfg; + + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); + bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); + b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); + b43_phy_write(dev, B43_NPHY_BBCFG, + bbcfg & ~B43_NPHY_BBCFG_RSTCCA); + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); +} + +enum b43_nphy_rf_sequence { + B43_RFSEQ_RX2TX, + B43_RFSEQ_TX2RX, + B43_RFSEQ_RESET2RX, + B43_RFSEQ_UPDATE_GAINH, + B43_RFSEQ_UPDATE_GAINL, + B43_RFSEQ_UPDATE_GAINU, +}; + +static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, + enum b43_nphy_rf_sequence seq) +{ + static const u16 trigger[] = { + [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX, + [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX, + [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX, + [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH, + [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL, + [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, + }; + int i; + + B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); + + b43_phy_set(dev, B43_NPHY_RFSEQMODE, + B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER); + b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]); + for (i = 0; i < 200; i++) { + if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq])) + goto ok; + msleep(1); + } + b43err(dev->wl, "RF sequence status timeout\n"); +ok: + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); +} + +static void b43_nphy_bphy_init(struct b43_wldev *dev) +{ + unsigned int i; + u16 val; + + val = 0x1E1F; + for (i = 0; i < 14; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); + val -= 0x202; + } + val = 0x3E3F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); + val -= 0x202; + } + b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); +} + +/* RSSI Calibration */ +static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) +{ + //TODO +} + +int b43_phy_initn(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + //TODO: Spectral management + b43_nphy_tables_init(dev); + + /* Clear all overrides */ + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | + B43_NPHY_RFSEQMODE_TROVER)); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); + + tmp = (phy->rev < 2) ? 64 : 59; + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, + ~B43_NPHY_BPHY_CTL3_SCALE, + tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); + + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); + + b43_phy_write(dev, B43_NPHY_TXREALFD, 184); + b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); + b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); + + //TODO MIMO-Config + //TODO Update TX/RX chain + + if (phy->rev < 2) { + b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); + b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); + } + b43_nphy_workarounds(dev); + b43_nphy_reset_cca(dev); + + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); + + b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ + //TODO read core1/2 clip1 thres regs + + if (1 /* FIXME Band is 2.4GHz */) + b43_nphy_bphy_init(dev); + //TODO disable TX power control + //TODO Fix the TX power settings + //TODO Init periodic calibration with reason 3 + b43_nphy_rssi_cal(dev, 2); + b43_nphy_rssi_cal(dev, 0); + b43_nphy_rssi_cal(dev, 1); + //TODO get TX gain + //TODO init superswitch + //TODO calibrate LO + //TODO idle TSSI TX pctl + //TODO TX power control power setup + //TODO table writes + //TODO TX power control coefficients + //TODO enable TX power control + //TODO control antenna selection + //TODO init radar detection + //TODO reset channel if changed + + b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); + return 0; +} + +static int b43_nphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy; + + nphy = kzalloc(sizeof(*nphy), GFP_KERNEL); + if (!nphy) + return -ENOMEM; + dev->phy.n = nphy; + + //TODO init struct b43_phy_n + + return 0; +} + +static int b43_nphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + int err; + + err = b43_phy_initn(dev); + if (err) + return err; + nphy->initialised = 1; + + return 0; +} + +static void b43_nphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + if (nphy->initialised) { + //TODO + nphy->initialised = 0; + } + //TODO + kfree(nphy); + dev->phy.n = NULL; +} + +static inline void check_phyreg(struct b43_wldev *dev, u16 offset) +{ +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + /* OFDM registers are onnly available on A/G-PHYs */ + b43err(dev->wl, "Invalid OFDM PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ +} + +static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* N-PHY needs 0x100 for read access */ + reg |= 0x100; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{//TODO +} + +static int b43_nphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + } else { + if (new_channel > 200) + return -EINVAL; + } + + return nphy_channel_switch(dev, new_channel); +} + +static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + +const struct b43_phy_operations b43_phyops_n = { + .allocate = b43_nphy_op_allocate, + .init = b43_nphy_op_init, + .exit = b43_nphy_op_exit, + .phy_read = b43_nphy_op_read, + .phy_write = b43_nphy_op_write, + .radio_read = b43_nphy_op_radio_read, + .radio_write = b43_nphy_op_radio_write, + .software_rfkill = b43_nphy_op_software_rfkill, + .switch_channel = b43_nphy_op_switch_channel, + .get_default_chan = b43_nphy_op_get_default_chan, + .recalc_txpower = b43_nphy_op_recalc_txpower, + .adjust_txpower = b43_nphy_op_adjust_txpower, +}; diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h new file mode 100644 index 00000000000..3d1f65ed201 --- /dev/null +++ b/drivers/net/wireless/b43/phy_n.h @@ -0,0 +1,932 @@ +#ifndef B43_NPHY_H_ +#define B43_NPHY_H_ + +#include "phy_common.h" + + +/* N-PHY registers. */ + +#define B43_NPHY_BBCFG B43_PHY_N(0x001) /* BB config */ +#define B43_NPHY_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_NPHY_BBCFG_RSTRX 0x8000 /* Reset RX */ +#define B43_NPHY_CHANNEL B43_PHY_N(0x005) /* Channel */ +#define B43_NPHY_TXERR B43_PHY_N(0x007) /* TX error */ +#define B43_NPHY_BANDCTL B43_PHY_N(0x009) /* Band control */ +#define B43_NPHY_BANDCTL_5GHZ 0x0001 /* Use the 5GHz band */ +#define B43_NPHY_4WI_ADDR B43_PHY_N(0x00B) /* Four-wire bus address */ +#define B43_NPHY_4WI_DATAHI B43_PHY_N(0x00C) /* Four-wire bus data high */ +#define B43_NPHY_4WI_DATALO B43_PHY_N(0x00D) /* Four-wire bus data low */ +#define B43_NPHY_BIST_STAT0 B43_PHY_N(0x00E) /* Built-in self test status 0 */ +#define B43_NPHY_BIST_STAT1 B43_PHY_N(0x00F) /* Built-in self test status 1 */ + +#define B43_NPHY_C1_DESPWR B43_PHY_N(0x018) /* Core 1 desired power */ +#define B43_NPHY_C1_CCK_DESPWR B43_PHY_N(0x019) /* Core 1 CCK desired power */ +#define B43_NPHY_C1_BCLIPBKOFF B43_PHY_N(0x01A) /* Core 1 barely clip backoff */ +#define B43_NPHY_C1_CCK_BCLIPBKOFF B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */ +#define B43_NPHY_C1_CGAINI B43_PHY_N(0x01C) /* Core 1 compute gain info */ +#define B43_NPHY_C1_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT 0 +#define B43_NPHY_C1_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ +#define B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT 5 +#define B43_NPHY_C1_CGAINI_GAINSTEP 0x1C00 /* Gain step */ +#define B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT 10 +#define B43_NPHY_C1_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ +#define B43_NPHY_C1_CCK_CGAINI B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */ +#define B43_NPHY_C1_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ +#define B43_NPHY_C1_MINMAX_GAIN B43_PHY_N(0x01E) /* Core 1 min/max gain */ +#define B43_NPHY_C1_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C1_MINGAIN_SHIFT 0 +#define B43_NPHY_C1_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C1_MAXGAIN_SHIFT 8 +#define B43_NPHY_C1_CCK_MINMAX_GAIN B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */ +#define B43_NPHY_C1_CCK_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C1_CCK_MINGAIN_SHIFT 0 +#define B43_NPHY_C1_CCK_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C1_CCK_MAXGAIN_SHIFT 8 +#define B43_NPHY_C1_INITGAIN B43_PHY_N(0x020) /* Core 1 initial gain code */ +#define B43_NPHY_C1_INITGAIN_EXTLNA 0x0001 /* External LNA index */ +#define B43_NPHY_C1_INITGAIN_LNA 0x0006 /* LNA index */ +#define B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT 1 +#define B43_NPHY_C1_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ +#define B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT 3 +#define B43_NPHY_C1_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ +#define B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT 7 +#define B43_NPHY_C1_INITGAIN_TRRX 0x1000 /* TR RX index */ +#define B43_NPHY_C1_INITGAIN_TRTX 0x2000 /* TR TX index */ +#define B43_NPHY_C1_CLIP1_HIGAIN B43_PHY_N(0x021) /* Core 1 clip1 high gain code */ +#define B43_NPHY_C1_CLIP1_MEDGAIN B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */ +#define B43_NPHY_C1_CLIP1_LOGAIN B43_PHY_N(0x023) /* Core 1 clip1 low gain code */ +#define B43_NPHY_C1_CLIP2_GAIN B43_PHY_N(0x024) /* Core 1 clip2 gain code */ +#define B43_NPHY_C1_FILTERGAIN B43_PHY_N(0x025) /* Core 1 filter gain */ +#define B43_NPHY_C1_LPF_QHPF_BW B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */ +#define B43_NPHY_C1_CLIPWBTHRES B43_PHY_N(0x027) /* Core 1 clip wideband threshold */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT 0 +#define B43_NPHY_C1_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT 6 +#define B43_NPHY_C1_W1THRES B43_PHY_N(0x028) /* Core 1 W1 threshold */ +#define B43_NPHY_C1_EDTHRES B43_PHY_N(0x029) /* Core 1 ED threshold */ +#define B43_NPHY_C1_SMSIGTHRES B43_PHY_N(0x02A) /* Core 1 small sig threshold */ +#define B43_NPHY_C1_NBCLIPTHRES B43_PHY_N(0x02B) /* Core 1 NB clip threshold */ +#define B43_NPHY_C1_CLIP1THRES B43_PHY_N(0x02C) /* Core 1 clip1 threshold */ +#define B43_NPHY_C1_CLIP2THRES B43_PHY_N(0x02D) /* Core 1 clip2 threshold */ + +#define B43_NPHY_C2_DESPWR B43_PHY_N(0x02E) /* Core 2 desired power */ +#define B43_NPHY_C2_CCK_DESPWR B43_PHY_N(0x02F) /* Core 2 CCK desired power */ +#define B43_NPHY_C2_BCLIPBKOFF B43_PHY_N(0x030) /* Core 2 barely clip backoff */ +#define B43_NPHY_C2_CCK_BCLIPBKOFF B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */ +#define B43_NPHY_C2_CGAINI B43_PHY_N(0x032) /* Core 2 compute gain info */ +#define B43_NPHY_C2_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT 0 +#define B43_NPHY_C2_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ +#define B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT 5 +#define B43_NPHY_C2_CGAINI_GAINSTEP 0x1C00 /* Gain step */ +#define B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT 10 +#define B43_NPHY_C2_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ +#define B43_NPHY_C2_CCK_CGAINI B43_PHY_N(0x033) /* Core 2 CCK compute gain info */ +#define B43_NPHY_C2_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ +#define B43_NPHY_C2_MINMAX_GAIN B43_PHY_N(0x034) /* Core 2 min/max gain */ +#define B43_NPHY_C2_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C2_MINGAIN_SHIFT 0 +#define B43_NPHY_C2_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C2_MAXGAIN_SHIFT 8 +#define B43_NPHY_C2_CCK_MINMAX_GAIN B43_PHY_N(0x035) /* Core 2 CCK min/max gain */ +#define B43_NPHY_C2_CCK_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C2_CCK_MINGAIN_SHIFT 0 +#define B43_NPHY_C2_CCK_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C2_CCK_MAXGAIN_SHIFT 8 +#define B43_NPHY_C2_INITGAIN B43_PHY_N(0x036) /* Core 2 initial gain code */ +#define B43_NPHY_C2_INITGAIN_EXTLNA 0x0001 /* External LNA index */ +#define B43_NPHY_C2_INITGAIN_LNA 0x0006 /* LNA index */ +#define B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT 1 +#define B43_NPHY_C2_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ +#define B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT 3 +#define B43_NPHY_C2_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ +#define B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT 7 +#define B43_NPHY_C2_INITGAIN_TRRX 0x1000 /* TR RX index */ +#define B43_NPHY_C2_INITGAIN_TRTX 0x2000 /* TR TX index */ +#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x037) /* Core 2 clip1 high gain code */ +#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */ +#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x039) /* Core 2 clip1 low gain code */ +#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x03A) /* Core 2 clip2 gain code */ +#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x03B) /* Core 2 filter gain */ +#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */ +#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT 0 +#define B43_NPHY_C2_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT 6 +#define B43_NPHY_C2_W1THRES B43_PHY_N(0x03E) /* Core 2 W1 threshold */ +#define B43_NPHY_C2_EDTHRES B43_PHY_N(0x03F) /* Core 2 ED threshold */ +#define B43_NPHY_C2_SMSIGTHRES B43_PHY_N(0x040) /* Core 2 small sig threshold */ +#define B43_NPHY_C2_NBCLIPTHRES B43_PHY_N(0x041) /* Core 2 NB clip threshold */ +#define B43_NPHY_C2_CLIP1THRES B43_PHY_N(0x042) /* Core 2 clip1 threshold */ +#define B43_NPHY_C2_CLIP2THRES B43_PHY_N(0x043) /* Core 2 clip2 threshold */ + +#define B43_NPHY_CRS_THRES1 B43_PHY_N(0x044) /* CRS threshold 1 */ +#define B43_NPHY_CRS_THRES2 B43_PHY_N(0x045) /* CRS threshold 2 */ +#define B43_NPHY_CRS_THRES3 B43_PHY_N(0x046) /* CRS threshold 3 */ +#define B43_NPHY_CRSCTL B43_PHY_N(0x047) /* CRS control */ +#define B43_NPHY_DCFADDR B43_PHY_N(0x048) /* DC filter address */ +#define B43_NPHY_RXF20_NUM0 B43_PHY_N(0x049) /* RX filter 20 numerator 0 */ +#define B43_NPHY_RXF20_NUM1 B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */ +#define B43_NPHY_RXF20_NUM2 B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */ +#define B43_NPHY_RXF20_DENOM0 B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */ +#define B43_NPHY_RXF20_DENOM1 B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */ +#define B43_NPHY_RXF20_NUM10 B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */ +#define B43_NPHY_RXF20_NUM11 B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */ +#define B43_NPHY_RXF20_NUM12 B43_PHY_N(0x050) /* RX filter 20 numerator 12 */ +#define B43_NPHY_RXF20_DENOM10 B43_PHY_N(0x051) /* RX filter 20 denominator 10 */ +#define B43_NPHY_RXF20_DENOM11 B43_PHY_N(0x052) /* RX filter 20 denominator 11 */ +#define B43_NPHY_RXF40_NUM0 B43_PHY_N(0x053) /* RX filter 40 numerator 0 */ +#define B43_NPHY_RXF40_NUM1 B43_PHY_N(0x054) /* RX filter 40 numerator 1 */ +#define B43_NPHY_RXF40_NUM2 B43_PHY_N(0x055) /* RX filter 40 numerator 2 */ +#define B43_NPHY_RXF40_DENOM0 B43_PHY_N(0x056) /* RX filter 40 denominator 0 */ +#define B43_NPHY_RXF40_DENOM1 B43_PHY_N(0x057) /* RX filter 40 denominator 1 */ +#define B43_NPHY_RXF40_NUM10 B43_PHY_N(0x058) /* RX filter 40 numerator 10 */ +#define B43_NPHY_RXF40_NUM11 B43_PHY_N(0x059) /* RX filter 40 numerator 11 */ +#define B43_NPHY_RXF40_NUM12 B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */ +#define B43_NPHY_RXF40_DENOM10 B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */ +#define B43_NPHY_RXF40_DENOM11 B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */ +#define B43_NPHY_PPROC_RSTLEN B43_PHY_N(0x060) /* Packet processing reset length */ +#define B43_NPHY_INITCARR_DLEN B43_PHY_N(0x061) /* Initial carrier detection length */ +#define B43_NPHY_CLIP1CARR_DLEN B43_PHY_N(0x062) /* Clip1 carrier detection length */ +#define B43_NPHY_CLIP2CARR_DLEN B43_PHY_N(0x063) /* Clip2 carrier detection length */ +#define B43_NPHY_INITGAIN_SLEN B43_PHY_N(0x064) /* Initial gain settle length */ +#define B43_NPHY_CLIP1GAIN_SLEN B43_PHY_N(0x065) /* Clip1 gain settle length */ +#define B43_NPHY_CLIP2GAIN_SLEN B43_PHY_N(0x066) /* Clip2 gain settle length */ +#define B43_NPHY_PACKGAIN_SLEN B43_PHY_N(0x067) /* Packet gain settle length */ +#define B43_NPHY_CARRSRC_TLEN B43_PHY_N(0x068) /* Carrier search timeout length */ +#define B43_NPHY_TISRC_TLEN B43_PHY_N(0x069) /* Timing search timeout length */ +#define B43_NPHY_ENDROP_TLEN B43_PHY_N(0x06A) /* Energy drop timeout length */ +#define B43_NPHY_CLIP1_NBDWELL_LEN B43_PHY_N(0x06B) /* Clip1 NB dwell length */ +#define B43_NPHY_CLIP2_NBDWELL_LEN B43_PHY_N(0x06C) /* Clip2 NB dwell length */ +#define B43_NPHY_W1CLIP1_DWELL_LEN B43_PHY_N(0x06D) /* W1 clip1 dwell length */ +#define B43_NPHY_W1CLIP2_DWELL_LEN B43_PHY_N(0x06E) /* W1 clip2 dwell length */ +#define B43_NPHY_W2CLIP1_DWELL_LEN B43_PHY_N(0x06F) /* W2 clip1 dwell length */ +#define B43_NPHY_PLOAD_CSENSE_EXTLEN B43_PHY_N(0x070) /* Payload carrier sense extension length */ +#define B43_NPHY_EDROP_CSENSE_EXTLEN B43_PHY_N(0x071) /* Energy drop carrier sense extension length */ +#define B43_NPHY_TABLE_ADDR B43_PHY_N(0x072) /* Table address */ +#define B43_NPHY_TABLE_DATALO B43_PHY_N(0x073) /* Table data low */ +#define B43_NPHY_TABLE_DATAHI B43_PHY_N(0x074) /* Table data high */ +#define B43_NPHY_WWISE_LENIDX B43_PHY_N(0x075) /* WWiSE length index */ +#define B43_NPHY_TGNSYNC_LENIDX B43_PHY_N(0x076) /* TGNsync length index */ +#define B43_NPHY_TXMACIF_HOLDOFF B43_PHY_N(0x077) /* TX MAC IF Hold off */ +#define B43_NPHY_RFCTL_CMD B43_PHY_N(0x078) /* RF control (command) */ +#define B43_NPHY_RFCTL_CMD_START 0x0001 /* Start sequence */ +#define B43_NPHY_RFCTL_CMD_RXTX 0x0002 /* RX/TX */ +#define B43_NPHY_RFCTL_CMD_CORESEL 0x0038 /* Core select */ +#define B43_NPHY_RFCTL_CMD_CORESEL_SHIFT 3 +#define B43_NPHY_RFCTL_CMD_PORFORCE 0x0040 /* POR force */ +#define B43_NPHY_RFCTL_CMD_OEPORFORCE 0x0080 /* OE POR force */ +#define B43_NPHY_RFCTL_CMD_RXEN 0x0100 /* RX enable */ +#define B43_NPHY_RFCTL_CMD_TXEN 0x0200 /* TX enable */ +#define B43_NPHY_RFCTL_CMD_CHIP0PU 0x0400 /* Chip0 PU */ +#define B43_NPHY_RFCTL_CMD_EN 0x0800 /* Radio enabled */ +#define B43_NPHY_RFCTL_CMD_SEQENCORE 0xF000 /* Seq en core */ +#define B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT 12 +#define B43_NPHY_RFCTL_RSSIO1 B43_PHY_N(0x07A) /* RF control (RSSI others 1) */ +#define B43_NPHY_RFCTL_RSSIO1_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO1_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO1_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO1_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO1_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO1_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO1_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG1 B43_PHY_N(0x07B) /* RF control (RX gain 1) */ +#define B43_NPHY_RFCTL_TXG1 B43_PHY_N(0x07C) /* RF control (TX gain 1) */ +#define B43_NPHY_RFCTL_RSSIO2 B43_PHY_N(0x07D) /* RF control (RSSI others 2) */ +#define B43_NPHY_RFCTL_RSSIO2_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO2_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO2_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO2_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO2_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO2_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO2_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG2 B43_PHY_N(0x07E) /* RF control (RX gain 2) */ +#define B43_NPHY_RFCTL_TXG2 B43_PHY_N(0x07F) /* RF control (TX gain 2) */ +#define B43_NPHY_RFCTL_RSSIO3 B43_PHY_N(0x080) /* RF control (RSSI others 3) */ +#define B43_NPHY_RFCTL_RSSIO3_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO3_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO3_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO3_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO3_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO3_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO3_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG3 B43_PHY_N(0x081) /* RF control (RX gain 3) */ +#define B43_NPHY_RFCTL_TXG3 B43_PHY_N(0x082) /* RF control (TX gain 3) */ +#define B43_NPHY_RFCTL_RSSIO4 B43_PHY_N(0x083) /* RF control (RSSI others 4) */ +#define B43_NPHY_RFCTL_RSSIO4_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO4_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO4_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO4_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO4_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO4_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO4_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG4 B43_PHY_N(0x084) /* RF control (RX gain 4) */ +#define B43_NPHY_RFCTL_TXG4 B43_PHY_N(0x085) /* RF control (TX gain 4) */ +#define B43_NPHY_C1_TXIQ_COMP_OFF B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */ +#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ +#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ +#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ +#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ +#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ +#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 +#define B43_NPHY_SCRAM_SIGCTL_SCM 0x0080 /* Scram control mode */ +#define B43_NPHY_SCRAM_SIGCTL_SICE 0x0100 /* Scram index control enable */ +#define B43_NPHY_SCRAM_SIGCTL_START 0xFE00 /* Scram start bit */ +#define B43_NPHY_SCRAM_SIGCTL_START_SHIFT 9 +#define B43_NPHY_RFCTL_INTC1 B43_PHY_N(0x091) /* RF control (intc 1) */ +#define B43_NPHY_RFCTL_INTC2 B43_PHY_N(0x092) /* RF control (intc 2) */ +#define B43_NPHY_RFCTL_INTC3 B43_PHY_N(0x093) /* RF control (intc 3) */ +#define B43_NPHY_RFCTL_INTC4 B43_PHY_N(0x094) /* RF control (intc 4) */ +#define B43_NPHY_NRDTO_WWISE B43_PHY_N(0x095) /* # datatones WWiSE */ +#define B43_NPHY_NRDTO_TGNSYNC B43_PHY_N(0x096) /* # datatones TGNsync */ +#define B43_NPHY_SIGFMOD_WWISE B43_PHY_N(0x097) /* Signal field mod WWiSE */ +#define B43_NPHY_LEG_SIGFMOD_11N B43_PHY_N(0x098) /* Legacy signal field mod 11n */ +#define B43_NPHY_HT_SIGFMOD_11N B43_PHY_N(0x099) /* HT signal field mod 11n */ +#define B43_NPHY_C1_RXIQ_COMPA0 B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */ +#define B43_NPHY_C1_RXIQ_COMPB0 B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */ +#define B43_NPHY_C2_RXIQ_COMPA1 B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */ +#define B43_NPHY_C2_RXIQ_COMPB1 B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */ +#define B43_NPHY_RXCTL B43_PHY_N(0x0A0) /* RX control */ +#define B43_NPHY_RXCTL_BSELU20 0x0010 /* Band select upper 20 */ +#define B43_NPHY_RXCTL_RIFSEN 0x0080 /* RIFS enable */ +#define B43_NPHY_RFSEQMODE B43_PHY_N(0x0A1) /* RF seq mode */ +#define B43_NPHY_RFSEQMODE_CAOVER 0x0001 /* Core active override */ +#define B43_NPHY_RFSEQMODE_TROVER 0x0002 /* Trigger override */ +#define B43_NPHY_RFSEQCA B43_PHY_N(0x0A2) /* RF seq core active */ +#define B43_NPHY_RFSEQCA_TXEN 0x000F /* TX enable */ +#define B43_NPHY_RFSEQCA_TXEN_SHIFT 0 +#define B43_NPHY_RFSEQCA_RXEN 0x00F0 /* RX enable */ +#define B43_NPHY_RFSEQCA_RXEN_SHIFT 4 +#define B43_NPHY_RFSEQCA_TXDIS 0x0F00 /* TX disable */ +#define B43_NPHY_RFSEQCA_TXDIS_SHIFT 8 +#define B43_NPHY_RFSEQCA_RXDIS 0xF000 /* RX disable */ +#define B43_NPHY_RFSEQCA_RXDIS_SHIFT 12 +#define B43_NPHY_RFSEQTR B43_PHY_N(0x0A3) /* RF seq trigger */ +#define B43_NPHY_RFSEQTR_RX2TX 0x0001 /* RX2TX */ +#define B43_NPHY_RFSEQTR_TX2RX 0x0002 /* TX2RX */ +#define B43_NPHY_RFSEQTR_UPGH 0x0004 /* Update gain H */ +#define B43_NPHY_RFSEQTR_UPGL 0x0008 /* Update gain L */ +#define B43_NPHY_RFSEQTR_UPGU 0x0010 /* Update gain U */ +#define B43_NPHY_RFSEQTR_RST2RX 0x0020 /* Reset to RX */ +#define B43_NPHY_RFSEQST B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */ +#define B43_NPHY_AFECTL_OVER B43_PHY_N(0x0A5) /* AFE control override */ +#define B43_NPHY_AFECTL_C1 B43_PHY_N(0x0A6) /* AFE control core 1 */ +#define B43_NPHY_AFECTL_C2 B43_PHY_N(0x0A7) /* AFE control core 2 */ +#define B43_NPHY_AFECTL_C3 B43_PHY_N(0x0A8) /* AFE control core 3 */ +#define B43_NPHY_AFECTL_C4 B43_PHY_N(0x0A9) /* AFE control core 4 */ +#define B43_NPHY_AFECTL_DACGAIN1 B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */ +#define B43_NPHY_AFECTL_DACGAIN2 B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */ +#define B43_NPHY_AFECTL_DACGAIN3 B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */ +#define B43_NPHY_AFECTL_DACGAIN4 B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */ +#define B43_NPHY_STR_ADDR1 B43_PHY_N(0x0AE) /* STR address 1 */ +#define B43_NPHY_STR_ADDR2 B43_PHY_N(0x0AF) /* STR address 2 */ +#define B43_NPHY_CLASSCTL B43_PHY_N(0x0B0) /* Classifier control */ +#define B43_NPHY_CLASSCTL_CCKEN 0x0001 /* CCK enable */ +#define B43_NPHY_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ +#define B43_NPHY_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */ +#define B43_NPHY_IQFLIP B43_PHY_N(0x0B1) /* I/Q flip */ +#define B43_NPHY_IQFLIP_ADC1 0x0001 /* ADC1 */ +#define B43_NPHY_IQFLIP_ADC2 0x0010 /* ADC2 */ +#define B43_NPHY_SISO_SNR_THRES B43_PHY_N(0x0B2) /* SISO SNR threshold */ +#define B43_NPHY_SIGMA_N_MULT B43_PHY_N(0x0B3) /* Sigma N multiplier */ +#define B43_NPHY_TXMACDELAY B43_PHY_N(0x0B4) /* TX MAC delay */ +#define B43_NPHY_TXFRAMEDELAY B43_PHY_N(0x0B5) /* TX frame delay */ +#define B43_NPHY_MLPARM B43_PHY_N(0x0B6) /* ML parameters */ +#define B43_NPHY_MLCTL B43_PHY_N(0x0B7) /* ML control */ +#define B43_NPHY_WWISE_20NCYCDAT B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */ +#define B43_NPHY_WWISE_40NCYCDAT B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */ +#define B43_NPHY_TGNSYNC_20NCYCDAT B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */ +#define B43_NPHY_TGNSYNC_40NCYCDAT B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */ +#define B43_NPHY_INITSWIZP B43_PHY_N(0x0BC) /* Initial swizzle pattern */ +#define B43_NPHY_TXTAILCNT B43_PHY_N(0x0BD) /* TX tail count value */ +#define B43_NPHY_BPHY_CTL1 B43_PHY_N(0x0BE) /* B PHY control 1 */ +#define B43_NPHY_BPHY_CTL2 B43_PHY_N(0x0BF) /* B PHY control 2 */ +#define B43_NPHY_BPHY_CTL2_LUT 0x001F /* LUT index */ +#define B43_NPHY_BPHY_CTL2_LUT_SHIFT 0 +#define B43_NPHY_BPHY_CTL2_MACDEL 0x7FE0 /* MAC delay */ +#define B43_NPHY_BPHY_CTL2_MACDEL_SHIFT 5 +#define B43_NPHY_IQLOCAL_CMD B43_PHY_N(0x0C0) /* I/Q LO cal command */ +#define B43_NPHY_IQLOCAL_CMD_EN 0x8000 +#define B43_NPHY_IQLOCAL_CMDNNUM B43_PHY_N(0x0C1) /* I/Q LO cal command N num */ +#define B43_NPHY_IQLOCAL_CMDGCTL B43_PHY_N(0x0C2) /* I/Q LO cal command G control */ +#define B43_NPHY_SAMP_CMD B43_PHY_N(0x0C3) /* Sample command */ +#define B43_NPHY_SAMP_CMD_STOP 0x0002 /* Stop */ +#define B43_NPHY_SAMP_LOOPCNT B43_PHY_N(0x0C4) /* Sample loop count */ +#define B43_NPHY_SAMP_WAITCNT B43_PHY_N(0x0C5) /* Sample wait count */ +#define B43_NPHY_SAMP_DEPCNT B43_PHY_N(0x0C6) /* Sample depth count */ +#define B43_NPHY_SAMP_STAT B43_PHY_N(0x0C7) /* Sample status */ +#define B43_NPHY_GPIO_LOOEN B43_PHY_N(0x0C8) /* GPIO low out enable */ +#define B43_NPHY_GPIO_HIOEN B43_PHY_N(0x0C9) /* GPIO high out enable */ +#define B43_NPHY_GPIO_SEL B43_PHY_N(0x0CA) /* GPIO select */ +#define B43_NPHY_GPIO_CLKCTL B43_PHY_N(0x0CB) /* GPIO clock control */ +#define B43_NPHY_TXF_20CO_AS0 B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */ +#define B43_NPHY_TXF_20CO_AS1 B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */ +#define B43_NPHY_TXF_20CO_AS2 B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */ +#define B43_NPHY_TXF_20CO_B32S0 B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */ +#define B43_NPHY_TXF_20CO_B1S0 B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */ +#define B43_NPHY_TXF_20CO_B32S1 B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */ +#define B43_NPHY_TXF_20CO_B1S1 B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */ +#define B43_NPHY_TXF_20CO_B32S2 B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */ +#define B43_NPHY_TXF_20CO_B1S2 B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */ +#define B43_NPHY_SIGFLDTOL B43_PHY_N(0x0D5) /* Signal fld tolerance */ +#define B43_NPHY_TXSERFLD B43_PHY_N(0x0D6) /* TX service field */ +#define B43_NPHY_AFESEQ_RX2TX_PUD B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */ +#define B43_NPHY_AFESEQ_TX2RX_PUD B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */ +#define B43_NPHY_TGNSYNC_SCRAMI0 B43_PHY_N(0x0D9) /* TGNsync scram init 0 */ +#define B43_NPHY_TGNSYNC_SCRAMI1 B43_PHY_N(0x0DA) /* TGNsync scram init 1 */ +#define B43_NPHY_INITSWIZPATTLEG B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */ +#define B43_NPHY_BPHY_CTL3 B43_PHY_N(0x0DC) /* B PHY control 3 */ +#define B43_NPHY_BPHY_CTL3_SCALE 0x00FF /* Scale */ +#define B43_NPHY_BPHY_CTL3_SCALE_SHIFT 0 +#define B43_NPHY_BPHY_CTL3_FSC 0xFF00 /* Frame start count value */ +#define B43_NPHY_BPHY_CTL3_FSC_SHIFT 8 +#define B43_NPHY_BPHY_CTL4 B43_PHY_N(0x0DD) /* B PHY control 4 */ +#define B43_NPHY_C1_TXBBMULT B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */ +#define B43_NPHY_C2_TXBBMULT B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */ +#define B43_NPHY_TXF_40CO_AS0 B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */ +#define B43_NPHY_TXF_40CO_AS1 B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */ +#define B43_NPHY_TXF_40CO_AS2 B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */ +#define B43_NPHY_TXF_40CO_B32S0 B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */ +#define B43_NPHY_TXF_40CO_B1S0 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */ +#define B43_NPHY_TXF_40CO_B32S1 B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */ +#define B43_NPHY_TXF_40CO_B1S1 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */ +#define B43_NPHY_TXF_40CO_B32S2 B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */ +#define B43_NPHY_TXF_40CO_B1S2 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */ +#define B43_NPHY_BIST_STAT2 B43_PHY_N(0x0EA) /* BIST status 2 */ +#define B43_NPHY_BIST_STAT3 B43_PHY_N(0x0EB) /* BIST status 3 */ +#define B43_NPHY_RFCTL_OVER B43_PHY_N(0x0EC) /* RF control override */ +#define B43_NPHY_MIMOCFG B43_PHY_N(0x0ED) /* MIMO config */ +#define B43_NPHY_MIMOCFG_GFMIX 0x0004 /* Greenfield or mixed mode */ +#define B43_NPHY_MIMOCFG_AUTO 0x0100 /* Greenfield/mixed mode auto */ +#define B43_NPHY_RADAR_BLNKCTL B43_PHY_N(0x0EE) /* Radar blank control */ +#define B43_NPHY_A0RADAR_FIFOCTL B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */ +#define B43_NPHY_A1RADAR_FIFOCTL B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */ +#define B43_NPHY_A0RADAR_FIFODAT B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */ +#define B43_NPHY_A1RADAR_FIFODAT B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */ +#define B43_NPHY_RADAR_THRES0 B43_PHY_N(0x0F3) /* Radar threshold 0 */ +#define B43_NPHY_RADAR_THRES1 B43_PHY_N(0x0F4) /* Radar threshold 1 */ +#define B43_NPHY_RADAR_THRES0R B43_PHY_N(0x0F5) /* Radar threshold 0R */ +#define B43_NPHY_RADAR_THRES1R B43_PHY_N(0x0F6) /* Radar threshold 1R */ +#define B43_NPHY_CSEN_20IN40_DLEN B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO1 B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP1 B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO2 B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP2 B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO3 B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP3 B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO4 B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP4 B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */ +#define B43_NPHY_RFCTL_LUT_LNAPA1 B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */ +#define B43_NPHY_RFCTL_LUT_LNAPA2 B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */ +#define B43_NPHY_RFCTL_LUT_LNAPA3 B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */ +#define B43_NPHY_RFCTL_LUT_LNAPA4 B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */ +#define B43_NPHY_TGNSYNC_CRCM0 B43_PHY_N(0x104) /* TGNsync CRC mask 0 */ +#define B43_NPHY_TGNSYNC_CRCM1 B43_PHY_N(0x105) /* TGNsync CRC mask 1 */ +#define B43_NPHY_TGNSYNC_CRCM2 B43_PHY_N(0x106) /* TGNsync CRC mask 2 */ +#define B43_NPHY_TGNSYNC_CRCM3 B43_PHY_N(0x107) /* TGNsync CRC mask 3 */ +#define B43_NPHY_TGNSYNC_CRCM4 B43_PHY_N(0x108) /* TGNsync CRC mask 4 */ +#define B43_NPHY_CRCPOLY B43_PHY_N(0x109) /* CRC polynomial */ +#define B43_NPHY_SIGCNT B43_PHY_N(0x10A) /* # sig count */ +#define B43_NPHY_SIGSTARTBIT_CTL B43_PHY_N(0x10B) /* Sig start bit control */ +#define B43_NPHY_CRCPOLY_ORDER B43_PHY_N(0x10C) /* CRC polynomial order */ +#define B43_NPHY_RFCTL_CST0 B43_PHY_N(0x10D) /* RF control core swap table 0 */ +#define B43_NPHY_RFCTL_CST1 B43_PHY_N(0x10E) /* RF control core swap table 1 */ +#define B43_NPHY_RFCTL_CST2O B43_PHY_N(0x10F) /* RF control core swap table 2 + others */ +#define B43_NPHY_BPHY_CTL5 B43_PHY_N(0x111) /* B PHY control 5 */ +#define B43_NPHY_RFSEQ_LPFBW B43_PHY_N(0x112) /* RF seq LPF bandwidth */ +#define B43_NPHY_TSSIBIAS1 B43_PHY_N(0x114) /* TSSI bias val 1 */ +#define B43_NPHY_TSSIBIAS2 B43_PHY_N(0x115) /* TSSI bias val 2 */ +#define B43_NPHY_TSSIBIAS_BIAS 0x00FF /* Bias */ +#define B43_NPHY_TSSIBIAS_BIAS_SHIFT 0 +#define B43_NPHY_TSSIBIAS_VAL 0xFF00 /* Value */ +#define B43_NPHY_TSSIBIAS_VAL_SHIFT 8 +#define B43_NPHY_ESTPWR1 B43_PHY_N(0x118) /* Estimated power 1 */ +#define B43_NPHY_ESTPWR2 B43_PHY_N(0x119) /* Estimated power 2 */ +#define B43_NPHY_ESTPWR_PWR 0x00FF /* Estimated power */ +#define B43_NPHY_ESTPWR_PWR_SHIFT 0 +#define B43_NPHY_ESTPWR_VALID 0x0100 /* Estimated power valid */ +#define B43_NPHY_TSSI_MAXTXFDT B43_PHY_N(0x11C) /* TSSI max TX frame delay time */ +#define B43_NPHY_TSSI_MAXTXFDT_VAL 0x00FF /* max TX frame delay time */ +#define B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT 0 +#define B43_NPHY_TSSI_MAXTDT B43_PHY_N(0x11D) /* TSSI max TSSI delay time */ +#define B43_NPHY_TSSI_MAXTDT_VAL 0x00FF /* max TSSI delay time */ +#define B43_NPHY_TSSI_MAXTDT_VAL_SHIFT 0 +#define B43_NPHY_ITSSI1 B43_PHY_N(0x11E) /* TSSI idle 1 */ +#define B43_NPHY_ITSSI2 B43_PHY_N(0x11F) /* TSSI idle 2 */ +#define B43_NPHY_ITSSI_VAL 0x00FF /* Idle TSSI */ +#define B43_NPHY_ITSSI_VAL_SHIFT 0 +#define B43_NPHY_TSSIMODE B43_PHY_N(0x122) /* TSSI mode */ +#define B43_NPHY_TSSIMODE_EN 0x0001 /* TSSI enable */ +#define B43_NPHY_TSSIMODE_PDEN 0x0002 /* Power det enable */ +#define B43_NPHY_RXMACIFM B43_PHY_N(0x123) /* RX Macif mode */ +#define B43_NPHY_CRSIT_COCNT_LO B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */ +#define B43_NPHY_CRSIT_COCNT_HI B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */ +#define B43_NPHY_CRSIT_MTCNT_LO B43_PHY_N(0x126) /* CRS idle time measure time count (low) */ +#define B43_NPHY_CRSIT_MTCNT_HI B43_PHY_N(0x127) /* CRS idle time measure time count (high) */ +#define B43_NPHY_SAMTWC B43_PHY_N(0x128) /* Sample tail wait count */ +#define B43_NPHY_IQEST_CMD B43_PHY_N(0x129) /* I/Q estimate command */ +#define B43_NPHY_IQEST_CMD_START 0x0001 /* Start */ +#define B43_NPHY_IQEST_CMD_MODE 0x0002 /* Mode */ +#define B43_NPHY_IQEST_WT B43_PHY_N(0x12A) /* I/Q estimate wait time */ +#define B43_NPHY_IQEST_WT_VAL 0x00FF /* Wait time */ +#define B43_NPHY_IQEST_WT_VAL_SHIFT 0 +#define B43_NPHY_IQEST_SAMCNT B43_PHY_N(0x12B) /* I/Q estimate sample count */ +#define B43_NPHY_IQEST_IQACC_LO0 B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */ +#define B43_NPHY_IQEST_IQACC_HI0 B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */ +#define B43_NPHY_IQEST_IPACC_LO0 B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */ +#define B43_NPHY_IQEST_IPACC_HI0 B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */ +#define B43_NPHY_IQEST_QPACC_LO0 B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */ +#define B43_NPHY_IQEST_QPACC_HI0 B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */ +#define B43_NPHY_IQEST_IQACC_LO1 B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */ +#define B43_NPHY_IQEST_IQACC_HI1 B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */ +#define B43_NPHY_IQEST_IPACC_LO1 B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */ +#define B43_NPHY_IQEST_IPACC_HI1 B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */ +#define B43_NPHY_IQEST_QPACC_LO1 B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */ +#define B43_NPHY_IQEST_QPACC_HI1 B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */ +#define B43_NPHY_MIMO_CRSTXEXT B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */ +#define B43_NPHY_PWRDET1 B43_PHY_N(0x13B) /* Power det 1 */ +#define B43_NPHY_PWRDET2 B43_PHY_N(0x13C) /* Power det 2 */ +#define B43_NPHY_MAXRSSI_DTIME B43_PHY_N(0x13F) /* RSSI max RSSI delay time */ +#define B43_NPHY_PIL_DW0 B43_PHY_N(0x141) /* Pilot data weight 0 */ +#define B43_NPHY_PIL_DW1 B43_PHY_N(0x142) /* Pilot data weight 1 */ +#define B43_NPHY_PIL_DW2 B43_PHY_N(0x143) /* Pilot data weight 2 */ +#define B43_NPHY_PIL_DW_BPSK 0x000F /* BPSK */ +#define B43_NPHY_PIL_DW_BPSK_SHIFT 0 +#define B43_NPHY_PIL_DW_QPSK 0x00F0 /* QPSK */ +#define B43_NPHY_PIL_DW_QPSK_SHIFT 4 +#define B43_NPHY_PIL_DW_16QAM 0x0F00 /* 16-QAM */ +#define B43_NPHY_PIL_DW_16QAM_SHIFT 8 +#define B43_NPHY_PIL_DW_64QAM 0xF000 /* 64-QAM */ +#define B43_NPHY_PIL_DW_64QAM_SHIFT 12 +#define B43_NPHY_FMDEM_CFG B43_PHY_N(0x144) /* FM demodulation config */ +#define B43_NPHY_PHASETR_A0 B43_PHY_N(0x145) /* Phase track alpha 0 */ +#define B43_NPHY_PHASETR_A1 B43_PHY_N(0x146) /* Phase track alpha 1 */ +#define B43_NPHY_PHASETR_A2 B43_PHY_N(0x147) /* Phase track alpha 2 */ +#define B43_NPHY_PHASETR_B0 B43_PHY_N(0x148) /* Phase track beta 0 */ +#define B43_NPHY_PHASETR_B1 B43_PHY_N(0x149) /* Phase track beta 1 */ +#define B43_NPHY_PHASETR_B2 B43_PHY_N(0x14A) /* Phase track beta 2 */ +#define B43_NPHY_PHASETR_CHG0 B43_PHY_N(0x14B) /* Phase track change 0 */ +#define B43_NPHY_PHASETR_CHG1 B43_PHY_N(0x14C) /* Phase track change 1 */ +#define B43_NPHY_PHASETW_OFF B43_PHY_N(0x14D) /* Phase track offset */ +#define B43_NPHY_RFCTL_DBG B43_PHY_N(0x14E) /* RF control debug */ +#define B43_NPHY_CCK_SHIFTB_REF B43_PHY_N(0x150) /* CCK shiftbits reference var */ +#define B43_NPHY_OVER_DGAIN0 B43_PHY_N(0x152) /* Override digital gain 0 */ +#define B43_NPHY_OVER_DGAIN1 B43_PHY_N(0x153) /* Override digital gain 1 */ +#define B43_NPHY_OVER_DGAIN_FDGV 0x0007 /* Force digital gain value */ +#define B43_NPHY_OVER_DGAIN_FDGV_SHIFT 0 +#define B43_NPHY_OVER_DGAIN_FDGEN 0x0008 /* Force digital gain enable */ +#define B43_NPHY_OVER_DGAIN_CCKDGECV 0xFF00 /* CCK digital gain enable count value */ +#define B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT 8 +#define B43_NPHY_BIST_STAT4 B43_PHY_N(0x156) /* BIST status 4 */ +#define B43_NPHY_RADAR_MAL B43_PHY_N(0x157) /* Radar MA length */ +#define B43_NPHY_RADAR_SRCCTL B43_PHY_N(0x158) /* Radar search control */ +#define B43_NPHY_VLD_DTSIG B43_PHY_N(0x159) /* VLD data tones sig */ +#define B43_NPHY_VLD_DTDAT B43_PHY_N(0x15A) /* VLD data tones data */ +#define B43_NPHY_C1_BPHY_RXIQCA0 B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */ +#define B43_NPHY_C1_BPHY_RXIQCB0 B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */ +#define B43_NPHY_C2_BPHY_RXIQCA1 B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */ +#define B43_NPHY_C2_BPHY_RXIQCB1 B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */ +#define B43_NPHY_FREQGAIN0 B43_PHY_N(0x160) /* Frequency gain 0 */ +#define B43_NPHY_FREQGAIN1 B43_PHY_N(0x161) /* Frequency gain 1 */ +#define B43_NPHY_FREQGAIN2 B43_PHY_N(0x162) /* Frequency gain 2 */ +#define B43_NPHY_FREQGAIN3 B43_PHY_N(0x163) /* Frequency gain 3 */ +#define B43_NPHY_FREQGAIN4 B43_PHY_N(0x164) /* Frequency gain 4 */ +#define B43_NPHY_FREQGAIN5 B43_PHY_N(0x165) /* Frequency gain 5 */ +#define B43_NPHY_FREQGAIN6 B43_PHY_N(0x166) /* Frequency gain 6 */ +#define B43_NPHY_FREQGAIN7 B43_PHY_N(0x167) /* Frequency gain 7 */ +#define B43_NPHY_FREQGAIN_BYPASS B43_PHY_N(0x168) /* Frequency gain bypass */ +#define B43_NPHY_TRLOSS B43_PHY_N(0x169) /* TR loss value */ +#define B43_NPHY_C1_ADCCLIP B43_PHY_N(0x16A) /* Core 1 ADC clip */ +#define B43_NPHY_C2_ADCCLIP B43_PHY_N(0x16B) /* Core 2 ADC clip */ +#define B43_NPHY_LTRN_OFFGAIN B43_PHY_N(0x16F) /* LTRN offset gain */ +#define B43_NPHY_LTRN_OFF B43_PHY_N(0x170) /* LTRN offset */ +#define B43_NPHY_NRDATAT_WWISE20SIG B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */ +#define B43_NPHY_NRDATAT_WWISE40SIG B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */ +#define B43_NPHY_NRDATAT_TGNSYNC20SIG B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */ +#define B43_NPHY_NRDATAT_TGNSYNC40SIG B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */ +#define B43_NPHY_WWISE_CRCM0 B43_PHY_N(0x175) /* WWiSE CRC mask 0 */ +#define B43_NPHY_WWISE_CRCM1 B43_PHY_N(0x176) /* WWiSE CRC mask 1 */ +#define B43_NPHY_WWISE_CRCM2 B43_PHY_N(0x177) /* WWiSE CRC mask 2 */ +#define B43_NPHY_WWISE_CRCM3 B43_PHY_N(0x178) /* WWiSE CRC mask 3 */ +#define B43_NPHY_WWISE_CRCM4 B43_PHY_N(0x179) /* WWiSE CRC mask 4 */ +#define B43_NPHY_CHANEST_CDDSH B43_PHY_N(0x17A) /* Channel estimate CDD shift */ +#define B43_NPHY_HTAGC_WCNT B43_PHY_N(0x17B) /* HT ADC wait counters */ +#define B43_NPHY_SQPARM B43_PHY_N(0x17C) /* SQ params */ +#define B43_NPHY_MCSDUP6M B43_PHY_N(0x17D) /* MCS dup 6M */ +#define B43_NPHY_NDATAT_DUP40 B43_PHY_N(0x17E) /* # data tones dup 40 */ +#define B43_NPHY_DUP40_TGNSYNC_CYCD B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */ +#define B43_NPHY_DUP40_GFBL B43_PHY_N(0x180) /* Dup40 GF format BL address */ +#define B43_NPHY_DUP40_BL B43_PHY_N(0x181) /* Dup40 format BL address */ +#define B43_NPHY_LEGDUP_FTA B43_PHY_N(0x182) /* Legacy dup frm table address */ +#define B43_NPHY_PACPROC_DBG B43_PHY_N(0x183) /* Packet processing debug */ +#define B43_NPHY_PIL_CYC1 B43_PHY_N(0x184) /* Pilot cycle counter 1 */ +#define B43_NPHY_PIL_CYC2 B43_PHY_N(0x185) /* Pilot cycle counter 2 */ +#define B43_NPHY_TXF_20CO_S0A1 B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */ +#define B43_NPHY_TXF_20CO_S0A2 B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */ +#define B43_NPHY_TXF_20CO_S1A1 B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */ +#define B43_NPHY_TXF_20CO_S1A2 B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */ +#define B43_NPHY_TXF_20CO_S2A1 B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */ +#define B43_NPHY_TXF_20CO_S2A2 B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */ +#define B43_NPHY_TXF_20CO_S0B1 B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */ +#define B43_NPHY_TXF_20CO_S0B2 B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */ +#define B43_NPHY_TXF_20CO_S0B3 B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */ +#define B43_NPHY_TXF_20CO_S1B1 B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */ +#define B43_NPHY_TXF_20CO_S1B2 B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */ +#define B43_NPHY_TXF_20CO_S1B3 B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */ +#define B43_NPHY_TXF_20CO_S2B1 B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */ +#define B43_NPHY_TXF_20CO_S2B2 B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */ +#define B43_NPHY_TXF_20CO_S2B3 B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */ +#define B43_NPHY_TXF_40CO_S0A1 B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */ +#define B43_NPHY_TXF_40CO_S0A2 B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */ +#define B43_NPHY_TXF_40CO_S1A1 B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */ +#define B43_NPHY_TXF_40CO_S1A2 B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */ +#define B43_NPHY_TXF_40CO_S2A1 B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */ +#define B43_NPHY_TXF_40CO_S2A2 B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */ +#define B43_NPHY_TXF_40CO_S0B1 B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */ +#define B43_NPHY_TXF_40CO_S0B2 B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */ +#define B43_NPHY_TXF_40CO_S0B3 B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */ +#define B43_NPHY_TXF_40CO_S1B1 B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */ +#define B43_NPHY_TXF_40CO_S1B2 B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */ +#define B43_NPHY_TXF_40CO_S1B3 B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */ +#define B43_NPHY_TXF_40CO_S2B1 B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */ +#define B43_NPHY_TXF_40CO_S2B2 B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */ +#define B43_NPHY_TXF_40CO_S2B3 B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */ +#define B43_NPHY_RSSIMC_0I_RSSI_X B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */ +#define B43_NPHY_RSSIMC_0I_RSSI_Y B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */ +#define B43_NPHY_RSSIMC_0I_RSSI_Z B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */ +#define B43_NPHY_RSSIMC_0I_TBD B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */ +#define B43_NPHY_RSSIMC_0I_PWRDET B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */ +#define B43_NPHY_RSSIMC_0I_TSSI B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */ +#define B43_NPHY_RSSIMC_0Q_RSSI_X B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */ +#define B43_NPHY_RSSIMC_0Q_RSSI_Y B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */ +#define B43_NPHY_RSSIMC_0Q_RSSI_Z B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */ +#define B43_NPHY_RSSIMC_0Q_TBD B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */ +#define B43_NPHY_RSSIMC_0Q_PWRDET B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */ +#define B43_NPHY_RSSIMC_0Q_TSSI B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */ +#define B43_NPHY_RSSIMC_1I_RSSI_X B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */ +#define B43_NPHY_RSSIMC_1I_RSSI_Y B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */ +#define B43_NPHY_RSSIMC_1I_RSSI_Z B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */ +#define B43_NPHY_RSSIMC_1I_TBD B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */ +#define B43_NPHY_RSSIMC_1I_PWRDET B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */ +#define B43_NPHY_RSSIMC_1I_TSSI B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */ +#define B43_NPHY_RSSIMC_1Q_RSSI_X B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */ +#define B43_NPHY_RSSIMC_1Q_RSSI_Y B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */ +#define B43_NPHY_RSSIMC_1Q_RSSI_Z B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */ +#define B43_NPHY_RSSIMC_1Q_TBD B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */ +#define B43_NPHY_RSSIMC_1Q_PWRDET B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */ +#define B43_NPHY_RSSIMC_1Q_TSSI B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */ +#define B43_NPHY_SAMC_WCNT B43_PHY_N(0x1BC) /* Sample collect wait counter */ +#define B43_NPHY_PTHROUGH_CNT B43_PHY_N(0x1BD) /* Pass-through counter */ +#define B43_NPHY_LTRN_OFF_G20L B43_PHY_N(0x1C4) /* LTRN offset gain 20L */ +#define B43_NPHY_LTRN_OFF_20L B43_PHY_N(0x1C5) /* LTRN offset 20L */ +#define B43_NPHY_LTRN_OFF_G20U B43_PHY_N(0x1C6) /* LTRN offset gain 20U */ +#define B43_NPHY_LTRN_OFF_20U B43_PHY_N(0x1C7) /* LTRN offset 20U */ +#define B43_NPHY_DSSSCCK_GAINSL B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */ +#define B43_NPHY_GPIO_LOOUT B43_PHY_N(0x1C9) /* GPIO low out */ +#define B43_NPHY_GPIO_HIOUT B43_PHY_N(0x1CA) /* GPIO high out */ +#define B43_NPHY_CRS_CHECK B43_PHY_N(0x1CB) /* CRS check */ +#define B43_NPHY_ML_LOGSS_RAT B43_PHY_N(0x1CC) /* ML/logss ratio */ +#define B43_NPHY_DUPSCALE B43_PHY_N(0x1CD) /* Dup scale */ +#define B43_NPHY_BW1A B43_PHY_N(0x1CE) /* BW 1A */ +#define B43_NPHY_BW2 B43_PHY_N(0x1CF) /* BW 2 */ +#define B43_NPHY_BW3 B43_PHY_N(0x1D0) /* BW 3 */ +#define B43_NPHY_BW4 B43_PHY_N(0x1D1) /* BW 4 */ +#define B43_NPHY_BW5 B43_PHY_N(0x1D2) /* BW 5 */ +#define B43_NPHY_BW6 B43_PHY_N(0x1D3) /* BW 6 */ +#define B43_NPHY_COALEN0 B43_PHY_N(0x1D4) /* Coarse length 0 */ +#define B43_NPHY_COALEN1 B43_PHY_N(0x1D5) /* Coarse length 1 */ +#define B43_NPHY_CRSTHRES_1U B43_PHY_N(0x1D6) /* CRS threshold 1 U */ +#define B43_NPHY_CRSTHRES_2U B43_PHY_N(0x1D7) /* CRS threshold 2 U */ +#define B43_NPHY_CRSTHRES_3U B43_PHY_N(0x1D8) /* CRS threshold 3 U */ +#define B43_NPHY_CRSCTL_U B43_PHY_N(0x1D9) /* CRS control U */ +#define B43_NPHY_CRSTHRES_1L B43_PHY_N(0x1DA) /* CRS threshold 1 L */ +#define B43_NPHY_CRSTHRES_2L B43_PHY_N(0x1DB) /* CRS threshold 2 L */ +#define B43_NPHY_CRSTHRES_3L B43_PHY_N(0x1DC) /* CRS threshold 3 L */ +#define B43_NPHY_CRSCTL_L B43_PHY_N(0x1DD) /* CRS control L */ +#define B43_NPHY_STRA_1U B43_PHY_N(0x1DE) /* STR address 1 U */ +#define B43_NPHY_STRA_2U B43_PHY_N(0x1DF) /* STR address 2 U */ +#define B43_NPHY_STRA_1L B43_PHY_N(0x1E0) /* STR address 1 L */ +#define B43_NPHY_STRA_2L B43_PHY_N(0x1E1) /* STR address 2 L */ +#define B43_NPHY_CRSCHECK1 B43_PHY_N(0x1E2) /* CRS check 1 */ +#define B43_NPHY_CRSCHECK2 B43_PHY_N(0x1E3) /* CRS check 2 */ +#define B43_NPHY_CRSCHECK3 B43_PHY_N(0x1E4) /* CRS check 3 */ +#define B43_NPHY_JMPSTP0 B43_PHY_N(0x1E5) /* Jump step 0 */ +#define B43_NPHY_JMPSTP1 B43_PHY_N(0x1E6) /* Jump step 1 */ +#define B43_NPHY_TXPCTL_CMD B43_PHY_N(0x1E7) /* TX power control command */ +#define B43_NPHY_TXPCTL_CMD_INIT 0x007F /* Init */ +#define B43_NPHY_TXPCTL_CMD_INIT_SHIFT 0 +#define B43_NPHY_TXPCTL_CMD_COEFF 0x2000 /* Power control coefficients */ +#define B43_NPHY_TXPCTL_CMD_HWPCTLEN 0x4000 /* Hardware TX power control enable */ +#define B43_NPHY_TXPCTL_CMD_PCTLEN 0x8000 /* TX power control enable */ +#define B43_NPHY_TXPCTL_N B43_PHY_N(0x1E8) /* TX power control N num */ +#define B43_NPHY_TXPCTL_N_TSSID 0x00FF /* N TSSI delay */ +#define B43_NPHY_TXPCTL_N_TSSID_SHIFT 0 +#define B43_NPHY_TXPCTL_N_NPTIL2 0x0700 /* N PT integer log2 */ +#define B43_NPHY_TXPCTL_N_NPTIL2_SHIFT 8 +#define B43_NPHY_TXPCTL_ITSSI B43_PHY_N(0x1E9) /* TX power control idle TSSI */ +#define B43_NPHY_TXPCTL_ITSSI_0 0x003F /* Idle TSSI 0 */ +#define B43_NPHY_TXPCTL_ITSSI_0_SHIFT 0 +#define B43_NPHY_TXPCTL_ITSSI_1 0x3F00 /* Idle TSSI 1 */ +#define B43_NPHY_TXPCTL_ITSSI_1_SHIFT 8 +#define B43_NPHY_TXPCTL_ITSSI_BINF 0x8000 /* Raw TSSI offset bin format */ +#define B43_NPHY_TXPCTL_TPWR B43_PHY_N(0x1EA) /* TX power control target power */ +#define B43_NPHY_TXPCTL_TPWR_0 0x00FF /* Power 0 */ +#define B43_NPHY_TXPCTL_TPWR_0_SHIFT 0 +#define B43_NPHY_TXPCTL_TPWR_1 0xFF00 /* Power 1 */ +#define B43_NPHY_TXPCTL_TPWR_1_SHIFT 8 +#define B43_NPHY_TXPCTL_BIDX B43_PHY_N(0x1EB) /* TX power control base index */ +#define B43_NPHY_TXPCTL_BIDX_0 0x007F /* uC base index 0 */ +#define B43_NPHY_TXPCTL_BIDX_0_SHIFT 0 +#define B43_NPHY_TXPCTL_BIDX_1 0x7F00 /* uC base index 1 */ +#define B43_NPHY_TXPCTL_BIDX_1_SHIFT 8 +#define B43_NPHY_TXPCTL_BIDX_LOAD 0x8000 /* Load base index */ +#define B43_NPHY_TXPCTL_PIDX B43_PHY_N(0x1EC) /* TX power control power index */ +#define B43_NPHY_TXPCTL_PIDX_0 0x007F /* uC power index 0 */ +#define B43_NPHY_TXPCTL_PIDX_0_SHIFT 0 +#define B43_NPHY_TXPCTL_PIDX_1 0x7F00 /* uC power index 1 */ +#define B43_NPHY_TXPCTL_PIDX_1_SHIFT 8 +#define B43_NPHY_C1_TXPCTL_STAT B43_PHY_N(0x1ED) /* Core 1 TX power control status */ +#define B43_NPHY_C2_TXPCTL_STAT B43_PHY_N(0x1EE) /* Core 2 TX power control status */ +#define B43_NPHY_TXPCTL_STAT_EST 0x00FF /* Estimated power */ +#define B43_NPHY_TXPCTL_STAT_EST_SHIFT 0 +#define B43_NPHY_TXPCTL_STAT_BIDX 0x7F00 /* Base index */ +#define B43_NPHY_TXPCTL_STAT_BIDX_SHIFT 8 +#define B43_NPHY_TXPCTL_STAT_ESTVALID 0x8000 /* Estimated power valid */ +#define B43_NPHY_SMALLSGS_LEN B43_PHY_N(0x1EF) /* Small sig gain settle length */ +#define B43_NPHY_PHYSTAT_GAIN0 B43_PHY_N(0x1F0) /* PHY stats gain info 0 */ +#define B43_NPHY_PHYSTAT_GAIN1 B43_PHY_N(0x1F1) /* PHY stats gain info 1 */ +#define B43_NPHY_PHYSTAT_FREQEST B43_PHY_N(0x1F2) /* PHY stats frequency estimate */ +#define B43_NPHY_PHYSTAT_ADVRET B43_PHY_N(0x1F3) /* PHY stats ADV retard */ +#define B43_NPHY_PHYLB_MODE B43_PHY_N(0x1F4) /* PHY loopback mode */ +#define B43_NPHY_TONE_MIDX20_1 B43_PHY_N(0x1F5) /* Tone map index 20/1 */ +#define B43_NPHY_TONE_MIDX20_2 B43_PHY_N(0x1F6) /* Tone map index 20/2 */ +#define B43_NPHY_TONE_MIDX20_3 B43_PHY_N(0x1F7) /* Tone map index 20/3 */ +#define B43_NPHY_TONE_MIDX40_1 B43_PHY_N(0x1F8) /* Tone map index 40/1 */ +#define B43_NPHY_TONE_MIDX40_2 B43_PHY_N(0x1F9) /* Tone map index 40/2 */ +#define B43_NPHY_TONE_MIDX40_3 B43_PHY_N(0x1FA) /* Tone map index 40/3 */ +#define B43_NPHY_TONE_MIDX40_4 B43_PHY_N(0x1FB) /* Tone map index 40/4 */ +#define B43_NPHY_PILTONE_MIDX1 B43_PHY_N(0x1FC) /* Pilot tone map index 1 */ +#define B43_NPHY_PILTONE_MIDX2 B43_PHY_N(0x1FD) /* Pilot tone map index 2 */ +#define B43_NPHY_PILTONE_MIDX3 B43_PHY_N(0x1FE) /* Pilot tone map index 3 */ +#define B43_NPHY_TXRIFS_FRDEL B43_PHY_N(0x1FF) /* TX RIFS frame delay */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_40M B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_40M B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_20M B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_20M B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */ +#define B43_NPHY_RX_SIGCTL B43_PHY_N(0x204) /* RX signal control */ +#define B43_NPHY_RXPIL_CYCNT0 B43_PHY_N(0x205) /* RX pilot cycle counter 0 */ +#define B43_NPHY_RXPIL_CYCNT1 B43_PHY_N(0x206) /* RX pilot cycle counter 1 */ +#define B43_NPHY_RXPIL_CYCNT2 B43_PHY_N(0x207) /* RX pilot cycle counter 2 */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_10M B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_10M B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */ +#define B43_NPHY_DSSSCCK_CRSEXTL B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */ +#define B43_NPHY_ML_LOGSS_RATSLOPE B43_PHY_N(0x20B) /* ML/logss ratio slope */ +#define B43_NPHY_RIFS_SRCTL B43_PHY_N(0x20C) /* RIFS search timeout length */ +#define B43_NPHY_TXREALFD B43_PHY_N(0x20D) /* TX real frame delay */ +#define B43_NPHY_HPANT_SWTHRES B43_PHY_N(0x20E) /* High power antenna switch threshold */ +#define B43_NPHY_EDCRS_ASSTHRES0 B43_PHY_N(0x210) /* ED CRS assert threshold 0 */ +#define B43_NPHY_EDCRS_ASSTHRES1 B43_PHY_N(0x211) /* ED CRS assert threshold 1 */ +#define B43_NPHY_EDCRS_DEASSTHRES0 B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */ +#define B43_NPHY_EDCRS_DEASSTHRES1 B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */ +#define B43_NPHY_STR_WTIME20U B43_PHY_N(0x214) /* STR wait time 20U */ +#define B43_NPHY_STR_WTIME20L B43_PHY_N(0x215) /* STR wait time 20L */ +#define B43_NPHY_TONE_MIDX657M B43_PHY_N(0x216) /* Tone map index 657M */ +#define B43_NPHY_HTSIGTONES B43_PHY_N(0x217) /* HT signal tones */ +#define B43_NPHY_RSSI1 B43_PHY_N(0x219) /* RSSI value 1 */ +#define B43_NPHY_RSSI2 B43_PHY_N(0x21A) /* RSSI value 2 */ +#define B43_NPHY_CHAN_ESTHANG B43_PHY_N(0x21D) /* Channel estimate hang */ +#define B43_NPHY_FINERX2_CGC B43_PHY_N(0x221) /* Fine RX 2 clock gate control */ +#define B43_NPHY_FINERX2_CGC_DECGC 0x0008 /* Decode gated clocks */ +#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ +#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ +#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 + + + +/* Broadcom 2055 radio registers */ + +#define B2055_GEN_SPARE 0x00 /* GEN spare */ +#define B2055_SP_PINPD 0x02 /* SP PIN PD */ +#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */ +#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */ +#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */ +#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */ +#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */ +#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */ +#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */ +#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */ +#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */ +#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */ +#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */ +#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */ +#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */ +#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */ +#define B2055_MASTER1 0x11 /* Master control 1 */ +#define B2055_MASTER2 0x12 /* Master control 2 */ +#define B2055_PD_LGEN 0x13 /* PD LGEN */ +#define B2055_PD_PLLTS 0x14 /* PD PLL TS */ +#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */ +#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */ +#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */ +#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */ +#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */ +#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */ +#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */ +#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */ +#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */ +#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */ +#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */ +#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */ +#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */ +#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */ +#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */ +#define B2055_CAL_MISC 0x24 /* CAL MISC */ +#define B2055_CAL_COUT 0x25 /* CAL Counter out */ +#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */ +#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */ +#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */ +#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */ +#define B2055_CAL_TS 0x2A /* CAL TS */ +#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */ +#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */ +#define B2055_PADDRV 0x2D /* PAD driver */ +#define B2055_XOCTL1 0x2E /* XO Control 1 */ +#define B2055_XOCTL2 0x2F /* XO Control 2 */ +#define B2055_XOREGUL 0x30 /* XO Regulator */ +#define B2055_XOMISC 0x31 /* XO misc */ +#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */ +#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */ +#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */ +#define B2055_PLL_REF 0x35 /* PLL reference */ +#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */ +#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */ +#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */ +#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */ +#define B2055_PLL_RCAL 0x3A /* PLL RCAL */ +#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */ +#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */ +#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */ +#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */ +#define B2055_RF_MMDSP 0x3F /* RF MMD spare */ +#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */ +#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */ +#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */ +#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */ +#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */ +#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */ +#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */ +#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */ +#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */ +#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */ +#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */ +#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */ +#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */ +#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */ +#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */ +#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */ +#define B2055_VCO_KVCO 0x50 /* VCO KVCO */ +#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */ +#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */ +#define B2055_VCO_REG 0x53 /* VCO Regulator */ +#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */ +#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */ +#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */ +#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */ +#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */ +#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */ +#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */ +#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */ +#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */ +#define B2055_LGEN_DIV 0x5D /* LGEN div */ +#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */ +#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */ +#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */ +#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */ +#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */ +#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */ +#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */ +#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */ +#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */ +#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */ +#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */ +#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */ +#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */ +#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */ +#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */ +#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */ +#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */ +#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */ +#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */ +#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */ +#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */ +#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */ +#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */ +#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */ +#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */ +#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */ +#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */ +#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */ +#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */ +#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */ +#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */ +#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */ +#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */ +#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */ +#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */ +#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */ +#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */ +#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */ +#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */ +#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */ +#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */ +#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */ +#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */ +#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */ +#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */ +#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */ +#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */ +#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */ +#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */ +#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */ +#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */ +#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */ +#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */ +#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */ +#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */ +#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */ +#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */ +#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */ +#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */ +#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */ +#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */ +#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */ +#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */ +#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */ +#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */ +#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */ +#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */ +#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */ +#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */ +#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */ +#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */ +#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */ +#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */ +#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */ +#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */ +#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */ +#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */ +#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */ +#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */ +#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */ +#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */ +#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */ +#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */ +#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */ +#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */ +#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */ +#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */ +#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */ +#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */ +#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */ +#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */ +#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */ +#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */ +#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */ +#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */ +#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */ +#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */ +#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */ +#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */ +#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */ +#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */ +#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */ +#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */ +#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */ +#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */ +#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */ +#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */ +#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */ +#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */ +#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */ +#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */ + + + +struct b43_wldev; + +struct b43_phy_n { + bool initialised; + + //TODO lots of missing stuff +}; + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_n; + +#endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 1de2c2e2e14..4e233631554 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -25,7 +25,7 @@ #include "b43.h" #include "tables_nphy.h" #include "phy_common.h" -#include "nphy.h" +#include "phy_n.h" struct b2055_inittab_entry { -- cgit v1.2.3 From e63e436326919dcc36e2bb242bc570257de70521 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 30 Aug 2008 10:55:48 +0200 Subject: b43: Add LP-PHY template This adds template code for the LP-PHY. No actual functionality is implemented. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 12 +++ drivers/net/wireless/b43/Makefile | 1 + drivers/net/wireless/b43/phy_common.c | 5 +- drivers/net/wireless/b43/phy_common.h | 3 + drivers/net/wireless/b43/phy_lp.c | 142 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/phy_lp.h | 14 ++++ 6 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/b43/phy_lp.c create mode 100644 drivers/net/wireless/b43/phy_lp.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 1fa043d1802..1f81d36f87c 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -80,6 +80,18 @@ config B43_NPHY SAY N. +config B43_PHY_LP + bool "IEEE 802.11g LP-PHY support (BROKEN)" + depends on B43 && EXPERIMENTAL && BROKEN + ---help--- + Support for the LP-PHY. + The LP-PHY is an IEEE 802.11g based PHY built into some notebooks + and embedded devices. + + THIS IS BROKEN AND DOES NOT WORK YET. + + SAY N. + # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 7fe49034ff2..14a02b3aea5 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -5,6 +5,7 @@ b43-y += phy_common.o b43-y += phy_g.o b43-y += phy_a.o b43-$(CONFIG_B43_NPHY) += phy_n.o +b43-$(CONFIG_B43_PHY_LP) += phy_lp.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 4b6c944be04..b3762d8163c 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -30,6 +30,7 @@ #include "phy_g.h" #include "phy_a.h" #include "phy_n.h" +#include "phy_lp.h" #include "b43.h" #include "main.h" @@ -54,7 +55,9 @@ int b43_phy_operations_setup(struct b43_wldev *dev) #endif break; case B43_PHYTYPE_LP: - /* FIXME: Not yet */ +#ifdef CONFIG_B43_PHY_LP + phy->ops = &b43_phyops_lp; +#endif break; } if (B43_WARN_ON(!phy->ops)) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index f8db9f40df5..a876e169cc8 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -165,6 +165,7 @@ struct b43_phy_operations { struct b43_phy_a; struct b43_phy_g; struct b43_phy_n; +struct b43_phy_lp; struct b43_phy { /* Hardware operation callbacks. */ @@ -185,6 +186,8 @@ struct b43_phy { struct b43_phy_g *g; /* N-PHY specific information */ struct b43_phy_n *n; + /* LP-PHY specific information */ + struct b43_phy_lp *lp; }; /* Band support flags. */ diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c new file mode 100644 index 00000000000..be2a5191f48 --- /dev/null +++ b/drivers/net/wireless/b43/phy_lp.c @@ -0,0 +1,142 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11g LP-PHY driver + + Copyright (c) 2008 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_lp.h" +#include "phy_common.h" + + +static int b43_lpphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy; + + lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL); + if (!lpphy) + return -ENOMEM; + dev->phy.lp = lpphy; + + //TODO + + return 0; +} + +static int b43_lpphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + //TODO + lpphy->initialised = 1; + + return 0; +} + +static void b43_lpphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (lpphy->initialised) { + //TODO + lpphy->initialised = 0; + } + + kfree(lpphy); + dev->phy.lp = NULL; +} + +static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) +{ + //TODO + return 0; +} + +static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + //TODO +} + +static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + //TODO + return 0; +} + +static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + //TODO +} + +static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{ + //TODO +} + +static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + //TODO + return 0; +} + +static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 1; /* Default to channel 1 */ +} + +static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{ + //TODO +} + +static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev) +{ + //TODO +} + +static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{ + //TODO + return B43_TXPWR_RES_DONE; +} + + +const struct b43_phy_operations b43_phyops_lp = { + .allocate = b43_lpphy_op_allocate, + .init = b43_lpphy_op_init, + .exit = b43_lpphy_op_exit, + .phy_read = b43_lpphy_op_read, + .phy_write = b43_lpphy_op_write, + .radio_read = b43_lpphy_op_radio_read, + .radio_write = b43_lpphy_op_radio_write, + .software_rfkill = b43_lpphy_op_software_rfkill, + .switch_channel = b43_lpphy_op_switch_channel, + .get_default_chan = b43_lpphy_op_get_default_chan, + .set_rx_antenna = b43_lpphy_op_set_rx_antenna, + .recalc_txpower = b43_lpphy_op_recalc_txpower, + .adjust_txpower = b43_lpphy_op_adjust_txpower, +}; diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h new file mode 100644 index 00000000000..e39a5436d8c --- /dev/null +++ b/drivers/net/wireless/b43/phy_lp.h @@ -0,0 +1,14 @@ +#ifndef LINUX_B43_PHY_LP_H_ +#define LINUX_B43_PHY_LP_H_ + +/* Definitions for the LP-PHY */ + +struct b43_phy_lp { + bool initialised; +}; + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_lp; + +#endif /* LINUX_B43_PHY_LP_H_ */ -- cgit v1.2.3 From 0888707f1aade9325f121a21314d57400fb779aa Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 30 Aug 2008 11:49:45 +0200 Subject: b43: Add LP-PHY read/write phyops This adds read/write phyops for the LP-PHY and LP-PHY radios. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index be2a5191f48..e769ca0b29a 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -66,19 +66,29 @@ static void b43_lpphy_op_exit(struct b43_wldev *dev) static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) { - //TODO - return 0; + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); } static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) { - //TODO + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); } static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg) { - //TODO - return 0; + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* LP-PHY needs a special bit set for read access */ + if (dev->phy.rev < 2) { + if (reg != 0x4001) + reg |= 0x100; + } else + reg |= 0x200; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); } static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) @@ -86,7 +96,8 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) /* Register 1 is a 32-bit register. */ B43_WARN_ON(reg == 1); - //TODO + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); } static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, -- cgit v1.2.3 From 400828c3da74a2e22b51bfc08d6db4697e3bce3e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 30 Aug 2008 13:07:31 +0200 Subject: b43: Add LP-PHY radio register definitions This adds definitions for the LP-PHY radios. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.h | 526 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index e39a5436d8c..9a0da355f28 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -3,6 +3,532 @@ /* Definitions for the LP-PHY */ + + + +#define B43_LP_RADIO(radio_reg) (radio_reg) +#define B43_LP_NORTH(radio_reg) B43_LP_RADIO(radio_reg) +#define B43_LP_SOUTH(radio_reg) B43_LP_RADIO((radio_reg) | 0x4000) + + +/*** Broadcom 2062 NORTH radio registers ***/ +#define B2062_N_COMM1 B43_LP_NORTH(0x000) /* Common 01 (north) */ +#define B2062_N_COMM2 B43_LP_NORTH(0x002) /* Common 02 (north) */ +#define B2062_N_COMM3 B43_LP_NORTH(0x003) /* Common 03 (north) */ +#define B2062_N_COMM4 B43_LP_NORTH(0x004) /* Common 04 (north) */ +#define B2062_N_COMM5 B43_LP_NORTH(0x005) /* Common 05 (north) */ +#define B2062_N_COMM6 B43_LP_NORTH(0x006) /* Common 06 (north) */ +#define B2062_N_COMM7 B43_LP_NORTH(0x007) /* Common 07 (north) */ +#define B2062_N_COMM8 B43_LP_NORTH(0x008) /* Common 08 (north) */ +#define B2062_N_COMM9 B43_LP_NORTH(0x009) /* Common 09 (north) */ +#define B2062_N_COMM10 B43_LP_NORTH(0x00A) /* Common 10 (north) */ +#define B2062_N_COMM11 B43_LP_NORTH(0x00B) /* Common 11 (north) */ +#define B2062_N_COMM12 B43_LP_NORTH(0x00C) /* Common 12 (north) */ +#define B2062_N_COMM13 B43_LP_NORTH(0x00D) /* Common 13 (north) */ +#define B2062_N_COMM14 B43_LP_NORTH(0x00E) /* Common 14 (north) */ +#define B2062_N_COMM15 B43_LP_NORTH(0x00F) /* Common 15 (north) */ +#define B2062_N_PDN_CTL0 B43_LP_NORTH(0x010) /* PDN Control 0 (north) */ +#define B2062_N_PDN_CTL1 B43_LP_NORTH(0x011) /* PDN Control 1 (north) */ +#define B2062_N_PDN_CTL2 B43_LP_NORTH(0x012) /* PDN Control 2 (north) */ +#define B2062_N_PDN_CTL3 B43_LP_NORTH(0x013) /* PDN Control 3 (north) */ +#define B2062_N_PDN_CTL4 B43_LP_NORTH(0x014) /* PDN Control 4 (north) */ +#define B2062_N_GEN_CTL0 B43_LP_NORTH(0x015) /* GEN Control 0 (north) */ +#define B2062_N_IQ_CALIB B43_LP_NORTH(0x016) /* IQ Calibration (north) */ +#define B2062_N_LGENC B43_LP_NORTH(0x017) /* LGENC (north) */ +#define B2062_N_LGENA_LPF B43_LP_NORTH(0x018) /* LGENA LPF (north) */ +#define B2062_N_LGENA_BIAS0 B43_LP_NORTH(0x019) /* LGENA Bias 0 (north) */ +#define B2062_N_LGNEA_BIAS1 B43_LP_NORTH(0x01A) /* LGNEA Bias 1 (north) */ +#define B2062_N_LGENA_CTL0 B43_LP_NORTH(0x01B) /* LGENA Control 0 (north) */ +#define B2062_N_LGENA_CTL1 B43_LP_NORTH(0x01C) /* LGENA Control 1 (north) */ +#define B2062_N_LGENA_CTL2 B43_LP_NORTH(0x01D) /* LGENA Control 2 (north) */ +#define B2062_N_LGENA_TUNE0 B43_LP_NORTH(0x01E) /* LGENA Tune 0 (north) */ +#define B2062_N_LGENA_TUNE1 B43_LP_NORTH(0x01F) /* LGENA Tune 1 (north) */ +#define B2062_N_LGENA_TUNE2 B43_LP_NORTH(0x020) /* LGENA Tune 2 (north) */ +#define B2062_N_LGENA_TUNE3 B43_LP_NORTH(0x021) /* LGENA Tune 3 (north) */ +#define B2062_N_LGENA_CTL3 B43_LP_NORTH(0x022) /* LGENA Control 3 (north) */ +#define B2062_N_LGENA_CTL4 B43_LP_NORTH(0x023) /* LGENA Control 4 (north) */ +#define B2062_N_LGENA_CTL5 B43_LP_NORTH(0x024) /* LGENA Control 5 (north) */ +#define B2062_N_LGENA_CTL6 B43_LP_NORTH(0x025) /* LGENA Control 6 (north) */ +#define B2062_N_LGENA_CTL7 B43_LP_NORTH(0x026) /* LGENA Control 7 (north) */ +#define B2062_N_RXA_CTL0 B43_LP_NORTH(0x027) /* RXA Control 0 (north) */ +#define B2062_N_RXA_CTL1 B43_LP_NORTH(0x028) /* RXA Control 1 (north) */ +#define B2062_N_RXA_CTL2 B43_LP_NORTH(0x029) /* RXA Control 2 (north) */ +#define B2062_N_RXA_CTL3 B43_LP_NORTH(0x02A) /* RXA Control 3 (north) */ +#define B2062_N_RXA_CTL4 B43_LP_NORTH(0x02B) /* RXA Control 4 (north) */ +#define B2062_N_RXA_CTL5 B43_LP_NORTH(0x02C) /* RXA Control 5 (north) */ +#define B2062_N_RXA_CTL6 B43_LP_NORTH(0x02D) /* RXA Control 6 (north) */ +#define B2062_N_RXA_CTL7 B43_LP_NORTH(0x02E) /* RXA Control 7 (north) */ +#define B2062_N_RXBB_CTL0 B43_LP_NORTH(0x02F) /* RXBB Control 0 (north) */ +#define B2062_N_RXBB_CTL1 B43_LP_NORTH(0x030) /* RXBB Control 1 (north) */ +#define B2062_N_RXBB_CTL2 B43_LP_NORTH(0x031) /* RXBB Control 2 (north) */ +#define B2062_N_RXBB_GAIN0 B43_LP_NORTH(0x032) /* RXBB Gain 0 (north) */ +#define B2062_N_RXBB_GAIN1 B43_LP_NORTH(0x033) /* RXBB Gain 1 (north) */ +#define B2062_N_RXBB_GAIN2 B43_LP_NORTH(0x034) /* RXBB Gain 2 (north) */ +#define B2062_N_RXBB_GAIN3 B43_LP_NORTH(0x035) /* RXBB Gain 3 (north) */ +#define B2062_N_RXBB_RSSI0 B43_LP_NORTH(0x036) /* RXBB RSSI 0 (north) */ +#define B2062_N_RXBB_RSSI1 B43_LP_NORTH(0x037) /* RXBB RSSI 1 (north) */ +#define B2062_N_RXBB_CALIB0 B43_LP_NORTH(0x038) /* RXBB Calibration0 (north) */ +#define B2062_N_RXBB_CALIB1 B43_LP_NORTH(0x039) /* RXBB Calibration1 (north) */ +#define B2062_N_RXBB_CALIB2 B43_LP_NORTH(0x03A) /* RXBB Calibration2 (north) */ +#define B2062_N_RXBB_BIAS0 B43_LP_NORTH(0x03B) /* RXBB Bias 0 (north) */ +#define B2062_N_RXBB_BIAS1 B43_LP_NORTH(0x03C) /* RXBB Bias 1 (north) */ +#define B2062_N_RXBB_BIAS2 B43_LP_NORTH(0x03D) /* RXBB Bias 2 (north) */ +#define B2062_N_RXBB_BIAS3 B43_LP_NORTH(0x03E) /* RXBB Bias 3 (north) */ +#define B2062_N_RXBB_BIAS4 B43_LP_NORTH(0x03F) /* RXBB Bias 4 (north) */ +#define B2062_N_RXBB_BIAS5 B43_LP_NORTH(0x040) /* RXBB Bias 5 (north) */ +#define B2062_N_RXBB_RSSI2 B43_LP_NORTH(0x041) /* RXBB RSSI 2 (north) */ +#define B2062_N_RXBB_RSSI3 B43_LP_NORTH(0x042) /* RXBB RSSI 3 (north) */ +#define B2062_N_RXBB_RSSI4 B43_LP_NORTH(0x043) /* RXBB RSSI 4 (north) */ +#define B2062_N_RXBB_RSSI5 B43_LP_NORTH(0x044) /* RXBB RSSI 5 (north) */ +#define B2062_N_TX_CTL0 B43_LP_NORTH(0x045) /* TX Control 0 (north) */ +#define B2062_N_TX_CTL1 B43_LP_NORTH(0x046) /* TX Control 1 (north) */ +#define B2062_N_TX_CTL2 B43_LP_NORTH(0x047) /* TX Control 2 (north) */ +#define B2062_N_TX_CTL3 B43_LP_NORTH(0x048) /* TX Control 3 (north) */ +#define B2062_N_TX_CTL4 B43_LP_NORTH(0x049) /* TX Control 4 (north) */ +#define B2062_N_TX_CTL5 B43_LP_NORTH(0x04A) /* TX Control 5 (north) */ +#define B2062_N_TX_CTL6 B43_LP_NORTH(0x04B) /* TX Control 6 (north) */ +#define B2062_N_TX_CTL7 B43_LP_NORTH(0x04C) /* TX Control 7 (north) */ +#define B2062_N_TX_CTL8 B43_LP_NORTH(0x04D) /* TX Control 8 (north) */ +#define B2062_N_TX_CTL9 B43_LP_NORTH(0x04E) /* TX Control 9 (north) */ +#define B2062_N_TX_CTL_A B43_LP_NORTH(0x04F) /* TX Control A (north) */ +#define B2062_N_TX_GC2G B43_LP_NORTH(0x050) /* TX GC2G (north) */ +#define B2062_N_TX_GC5G B43_LP_NORTH(0x051) /* TX GC5G (north) */ +#define B2062_N_TX_TUNE B43_LP_NORTH(0x052) /* TX Tune (north) */ +#define B2062_N_TX_PAD B43_LP_NORTH(0x053) /* TX PAD (north) */ +#define B2062_N_TX_PGA B43_LP_NORTH(0x054) /* TX PGA (north) */ +#define B2062_N_TX_PADAUX B43_LP_NORTH(0x055) /* TX PADAUX (north) */ +#define B2062_N_TX_PGAAUX B43_LP_NORTH(0x056) /* TX PGAAUX (north) */ +#define B2062_N_TSSI_CTL0 B43_LP_NORTH(0x057) /* TSSI Control 0 (north) */ +#define B2062_N_TSSI_CTL1 B43_LP_NORTH(0x058) /* TSSI Control 1 (north) */ +#define B2062_N_TSSI_CTL2 B43_LP_NORTH(0x059) /* TSSI Control 2 (north) */ +#define B2062_N_IQ_CALIB_CTL0 B43_LP_NORTH(0x05A) /* IQ Calibration Control 0 (north) */ +#define B2062_N_IQ_CALIB_CTL1 B43_LP_NORTH(0x05B) /* IQ Calibration Control 1 (north) */ +#define B2062_N_IQ_CALIB_CTL2 B43_LP_NORTH(0x05C) /* IQ Calibration Control 2 (north) */ +#define B2062_N_CALIB_TS B43_LP_NORTH(0x05D) /* Calibration TS (north) */ +#define B2062_N_CALIB_CTL0 B43_LP_NORTH(0x05E) /* Calibration Control 0 (north) */ +#define B2062_N_CALIB_CTL1 B43_LP_NORTH(0x05F) /* Calibration Control 1 (north) */ +#define B2062_N_CALIB_CTL2 B43_LP_NORTH(0x060) /* Calibration Control 2 (north) */ +#define B2062_N_CALIB_CTL3 B43_LP_NORTH(0x061) /* Calibration Control 3 (north) */ +#define B2062_N_CALIB_CTL4 B43_LP_NORTH(0x062) /* Calibration Control 4 (north) */ +#define B2062_N_CALIB_DBG0 B43_LP_NORTH(0x063) /* Calibration Debug 0 (north) */ +#define B2062_N_CALIB_DBG1 B43_LP_NORTH(0x064) /* Calibration Debug 1 (north) */ +#define B2062_N_CALIB_DBG2 B43_LP_NORTH(0x065) /* Calibration Debug 2 (north) */ +#define B2062_N_CALIB_DBG3 B43_LP_NORTH(0x066) /* Calibration Debug 3 (north) */ +#define B2062_N_PSENSE_CTL0 B43_LP_NORTH(0x069) /* PSENSE Control 0 (north) */ +#define B2062_N_PSENSE_CTL1 B43_LP_NORTH(0x06A) /* PSENSE Control 1 (north) */ +#define B2062_N_PSENSE_CTL2 B43_LP_NORTH(0x06B) /* PSENSE Control 2 (north) */ +#define B2062_N_TEST_BUF0 B43_LP_NORTH(0x06C) /* TEST BUF0 (north) */ + +/*** Broadcom 2062 SOUTH radio registers ***/ +#define B2062_S_COMM1 B43_LP_SOUTH(0x000) /* Common 01 (south) */ +#define B2062_S_RADIO_ID_CODE B43_LP_SOUTH(0x001) /* Radio ID code (south) */ +#define B2062_S_COMM2 B43_LP_SOUTH(0x002) /* Common 02 (south) */ +#define B2062_S_COMM3 B43_LP_SOUTH(0x003) /* Common 03 (south) */ +#define B2062_S_COMM4 B43_LP_SOUTH(0x004) /* Common 04 (south) */ +#define B2062_S_COMM5 B43_LP_SOUTH(0x005) /* Common 05 (south) */ +#define B2062_S_COMM6 B43_LP_SOUTH(0x006) /* Common 06 (south) */ +#define B2062_S_COMM7 B43_LP_SOUTH(0x007) /* Common 07 (south) */ +#define B2062_S_COMM8 B43_LP_SOUTH(0x008) /* Common 08 (south) */ +#define B2062_S_COMM9 B43_LP_SOUTH(0x009) /* Common 09 (south) */ +#define B2062_S_COMM10 B43_LP_SOUTH(0x00A) /* Common 10 (south) */ +#define B2062_S_COMM11 B43_LP_SOUTH(0x00B) /* Common 11 (south) */ +#define B2062_S_COMM12 B43_LP_SOUTH(0x00C) /* Common 12 (south) */ +#define B2062_S_COMM13 B43_LP_SOUTH(0x00D) /* Common 13 (south) */ +#define B2062_S_COMM14 B43_LP_SOUTH(0x00E) /* Common 14 (south) */ +#define B2062_S_COMM15 B43_LP_SOUTH(0x00F) /* Common 15 (south) */ +#define B2062_S_PDS_CTL0 B43_LP_SOUTH(0x010) /* PDS Control 0 (south) */ +#define B2062_S_PDS_CTL1 B43_LP_SOUTH(0x011) /* PDS Control 1 (south) */ +#define B2062_S_PDS_CTL2 B43_LP_SOUTH(0x012) /* PDS Control 2 (south) */ +#define B2062_S_PDS_CTL3 B43_LP_SOUTH(0x013) /* PDS Control 3 (south) */ +#define B2062_S_BG_CTL0 B43_LP_SOUTH(0x014) /* BG Control 0 (south) */ +#define B2062_S_BG_CTL1 B43_LP_SOUTH(0x015) /* BG Control 1 (south) */ +#define B2062_S_BG_CTL2 B43_LP_SOUTH(0x016) /* BG Control 2 (south) */ +#define B2062_S_LGENG_CTL0 B43_LP_SOUTH(0x017) /* LGENG Control 00 (south) */ +#define B2062_S_LGENG_CTL1 B43_LP_SOUTH(0x018) /* LGENG Control 01 (south) */ +#define B2062_S_LGENG_CTL2 B43_LP_SOUTH(0x019) /* LGENG Control 02 (south) */ +#define B2062_S_LGENG_CTL3 B43_LP_SOUTH(0x01A) /* LGENG Control 03 (south) */ +#define B2062_S_LGENG_CTL4 B43_LP_SOUTH(0x01B) /* LGENG Control 04 (south) */ +#define B2062_S_LGENG_CTL5 B43_LP_SOUTH(0x01C) /* LGENG Control 05 (south) */ +#define B2062_S_LGENG_CTL6 B43_LP_SOUTH(0x01D) /* LGENG Control 06 (south) */ +#define B2062_S_LGENG_CTL7 B43_LP_SOUTH(0x01E) /* LGENG Control 07 (south) */ +#define B2062_S_LGENG_CTL8 B43_LP_SOUTH(0x01F) /* LGENG Control 08 (south) */ +#define B2062_S_LGENG_CTL9 B43_LP_SOUTH(0x020) /* LGENG Control 09 (south) */ +#define B2062_S_LGENG_CTL10 B43_LP_SOUTH(0x021) /* LGENG Control 10 (south) */ +#define B2062_S_LGENG_CTL11 B43_LP_SOUTH(0x022) /* LGENG Control 11 (south) */ +#define B2062_S_REFPLL_CTL0 B43_LP_SOUTH(0x023) /* REFPLL Control 00 (south) */ +#define B2062_S_REFPLL_CTL1 B43_LP_SOUTH(0x024) /* REFPLL Control 01 (south) */ +#define B2062_S_REFPLL_CTL2 B43_LP_SOUTH(0x025) /* REFPLL Control 02 (south) */ +#define B2062_S_REFPLL_CTL3 B43_LP_SOUTH(0x026) /* REFPLL Control 03 (south) */ +#define B2062_S_REFPLL_CTL4 B43_LP_SOUTH(0x027) /* REFPLL Control 04 (south) */ +#define B2062_S_REFPLL_CTL5 B43_LP_SOUTH(0x028) /* REFPLL Control 05 (south) */ +#define B2062_S_REFPLL_CTL6 B43_LP_SOUTH(0x029) /* REFPLL Control 06 (south) */ +#define B2062_S_REFPLL_CTL7 B43_LP_SOUTH(0x02A) /* REFPLL Control 07 (south) */ +#define B2062_S_REFPLL_CTL8 B43_LP_SOUTH(0x02B) /* REFPLL Control 08 (south) */ +#define B2062_S_REFPLL_CTL9 B43_LP_SOUTH(0x02C) /* REFPLL Control 09 (south) */ +#define B2062_S_REFPLL_CTL10 B43_LP_SOUTH(0x02D) /* REFPLL Control 10 (south) */ +#define B2062_S_REFPLL_CTL11 B43_LP_SOUTH(0x02E) /* REFPLL Control 11 (south) */ +#define B2062_S_REFPLL_CTL12 B43_LP_SOUTH(0x02F) /* REFPLL Control 12 (south) */ +#define B2062_S_REFPLL_CTL13 B43_LP_SOUTH(0x030) /* REFPLL Control 13 (south) */ +#define B2062_S_REFPLL_CTL14 B43_LP_SOUTH(0x031) /* REFPLL Control 14 (south) */ +#define B2062_S_REFPLL_CTL15 B43_LP_SOUTH(0x032) /* REFPLL Control 15 (south) */ +#define B2062_S_REFPLL_CTL16 B43_LP_SOUTH(0x033) /* REFPLL Control 16 (south) */ +#define B2062_S_RFPLL_CTL0 B43_LP_SOUTH(0x034) /* RFPLL Control 00 (south) */ +#define B2062_S_RFPLL_CTL1 B43_LP_SOUTH(0x035) /* RFPLL Control 01 (south) */ +#define B2062_S_RFPLL_CTL2 B43_LP_SOUTH(0x036) /* RFPLL Control 02 (south) */ +#define B2062_S_RFPLL_CTL3 B43_LP_SOUTH(0x037) /* RFPLL Control 03 (south) */ +#define B2062_S_RFPLL_CTL4 B43_LP_SOUTH(0x038) /* RFPLL Control 04 (south) */ +#define B2062_S_RFPLL_CTL5 B43_LP_SOUTH(0x039) /* RFPLL Control 05 (south) */ +#define B2062_S_RFPLL_CTL6 B43_LP_SOUTH(0x03A) /* RFPLL Control 06 (south) */ +#define B2062_S_RFPLL_CTL7 B43_LP_SOUTH(0x03B) /* RFPLL Control 07 (south) */ +#define B2062_S_RFPLL_CTL8 B43_LP_SOUTH(0x03C) /* RFPLL Control 08 (south) */ +#define B2062_S_RFPLL_CTL9 B43_LP_SOUTH(0x03D) /* RFPLL Control 09 (south) */ +#define B2062_S_RFPLL_CTL10 B43_LP_SOUTH(0x03E) /* RFPLL Control 10 (south) */ +#define B2062_S_RFPLL_CTL11 B43_LP_SOUTH(0x03F) /* RFPLL Control 11 (south) */ +#define B2062_S_RFPLL_CTL12 B43_LP_SOUTH(0x040) /* RFPLL Control 12 (south) */ +#define B2062_S_RFPLL_CTL13 B43_LP_SOUTH(0x041) /* RFPLL Control 13 (south) */ +#define B2062_S_RFPLL_CTL14 B43_LP_SOUTH(0x042) /* RFPLL Control 14 (south) */ +#define B2062_S_RFPLL_CTL15 B43_LP_SOUTH(0x043) /* RFPLL Control 15 (south) */ +#define B2062_S_RFPLL_CTL16 B43_LP_SOUTH(0x044) /* RFPLL Control 16 (south) */ +#define B2062_S_RFPLL_CTL17 B43_LP_SOUTH(0x045) /* RFPLL Control 17 (south) */ +#define B2062_S_RFPLL_CTL18 B43_LP_SOUTH(0x046) /* RFPLL Control 18 (south) */ +#define B2062_S_RFPLL_CTL19 B43_LP_SOUTH(0x047) /* RFPLL Control 19 (south) */ +#define B2062_S_RFPLL_CTL20 B43_LP_SOUTH(0x048) /* RFPLL Control 20 (south) */ +#define B2062_S_RFPLL_CTL21 B43_LP_SOUTH(0x049) /* RFPLL Control 21 (south) */ +#define B2062_S_RFPLL_CTL22 B43_LP_SOUTH(0x04A) /* RFPLL Control 22 (south) */ +#define B2062_S_RFPLL_CTL23 B43_LP_SOUTH(0x04B) /* RFPLL Control 23 (south) */ +#define B2062_S_RFPLL_CTL24 B43_LP_SOUTH(0x04C) /* RFPLL Control 24 (south) */ +#define B2062_S_RFPLL_CTL25 B43_LP_SOUTH(0x04D) /* RFPLL Control 25 (south) */ +#define B2062_S_RFPLL_CTL26 B43_LP_SOUTH(0x04E) /* RFPLL Control 26 (south) */ +#define B2062_S_RFPLL_CTL27 B43_LP_SOUTH(0x04F) /* RFPLL Control 27 (south) */ +#define B2062_S_RFPLL_CTL28 B43_LP_SOUTH(0x050) /* RFPLL Control 28 (south) */ +#define B2062_S_RFPLL_CTL29 B43_LP_SOUTH(0x051) /* RFPLL Control 29 (south) */ +#define B2062_S_RFPLL_CTL30 B43_LP_SOUTH(0x052) /* RFPLL Control 30 (south) */ +#define B2062_S_RFPLL_CTL31 B43_LP_SOUTH(0x053) /* RFPLL Control 31 (south) */ +#define B2062_S_RFPLL_CTL32 B43_LP_SOUTH(0x054) /* RFPLL Control 32 (south) */ +#define B2062_S_RFPLL_CTL33 B43_LP_SOUTH(0x055) /* RFPLL Control 33 (south) */ +#define B2062_S_RFPLL_CTL34 B43_LP_SOUTH(0x056) /* RFPLL Control 34 (south) */ +#define B2062_S_RXG_CNT0 B43_LP_SOUTH(0x057) /* RXG Counter 00 (south) */ +#define B2062_S_RXG_CNT1 B43_LP_SOUTH(0x058) /* RXG Counter 01 (south) */ +#define B2062_S_RXG_CNT2 B43_LP_SOUTH(0x059) /* RXG Counter 02 (south) */ +#define B2062_S_RXG_CNT3 B43_LP_SOUTH(0x05A) /* RXG Counter 03 (south) */ +#define B2062_S_RXG_CNT4 B43_LP_SOUTH(0x05B) /* RXG Counter 04 (south) */ +#define B2062_S_RXG_CNT5 B43_LP_SOUTH(0x05C) /* RXG Counter 05 (south) */ +#define B2062_S_RXG_CNT6 B43_LP_SOUTH(0x05D) /* RXG Counter 06 (south) */ +#define B2062_S_RXG_CNT7 B43_LP_SOUTH(0x05E) /* RXG Counter 07 (south) */ +#define B2062_S_RXG_CNT8 B43_LP_SOUTH(0x05F) /* RXG Counter 08 (south) */ +#define B2062_S_RXG_CNT9 B43_LP_SOUTH(0x060) /* RXG Counter 09 (south) */ +#define B2062_S_RXG_CNT10 B43_LP_SOUTH(0x061) /* RXG Counter 10 (south) */ +#define B2062_S_RXG_CNT11 B43_LP_SOUTH(0x062) /* RXG Counter 11 (south) */ +#define B2062_S_RXG_CNT12 B43_LP_SOUTH(0x063) /* RXG Counter 12 (south) */ +#define B2062_S_RXG_CNT13 B43_LP_SOUTH(0x064) /* RXG Counter 13 (south) */ +#define B2062_S_RXG_CNT14 B43_LP_SOUTH(0x065) /* RXG Counter 14 (south) */ +#define B2062_S_RXG_CNT15 B43_LP_SOUTH(0x066) /* RXG Counter 15 (south) */ +#define B2062_S_RXG_CNT16 B43_LP_SOUTH(0x067) /* RXG Counter 16 (south) */ +#define B2062_S_RXG_CNT17 B43_LP_SOUTH(0x068) /* RXG Counter 17 (south) */ + + + +/*** Broadcom 2063 radio registers ***/ +#define B2063_RADIO_ID_CODE B43_LP_RADIO(0x001) /* Radio ID code */ +#define B2063_COMM1 B43_LP_RADIO(0x000) /* Common 01 */ +#define B2063_COMM2 B43_LP_RADIO(0x002) /* Common 02 */ +#define B2063_COMM3 B43_LP_RADIO(0x003) /* Common 03 */ +#define B2063_COMM4 B43_LP_RADIO(0x004) /* Common 04 */ +#define B2063_COMM5 B43_LP_RADIO(0x005) /* Common 05 */ +#define B2063_COMM6 B43_LP_RADIO(0x006) /* Common 06 */ +#define B2063_COMM7 B43_LP_RADIO(0x007) /* Common 07 */ +#define B2063_COMM8 B43_LP_RADIO(0x008) /* Common 08 */ +#define B2063_COMM9 B43_LP_RADIO(0x009) /* Common 09 */ +#define B2063_COMM10 B43_LP_RADIO(0x00A) /* Common 10 */ +#define B2063_COMM11 B43_LP_RADIO(0x00B) /* Common 11 */ +#define B2063_COMM12 B43_LP_RADIO(0x00C) /* Common 12 */ +#define B2063_COMM13 B43_LP_RADIO(0x00D) /* Common 13 */ +#define B2063_COMM14 B43_LP_RADIO(0x00E) /* Common 14 */ +#define B2063_COMM15 B43_LP_RADIO(0x00F) /* Common 15 */ +#define B2063_COMM16 B43_LP_RADIO(0x010) /* Common 16 */ +#define B2063_COMM17 B43_LP_RADIO(0x011) /* Common 17 */ +#define B2063_COMM18 B43_LP_RADIO(0x012) /* Common 18 */ +#define B2063_COMM19 B43_LP_RADIO(0x013) /* Common 19 */ +#define B2063_COMM20 B43_LP_RADIO(0x014) /* Common 20 */ +#define B2063_COMM21 B43_LP_RADIO(0x015) /* Common 21 */ +#define B2063_COMM22 B43_LP_RADIO(0x016) /* Common 22 */ +#define B2063_COMM23 B43_LP_RADIO(0x017) /* Common 23 */ +#define B2063_COMM24 B43_LP_RADIO(0x018) /* Common 24 */ +#define B2063_PWR_SWITCH_CTL B43_LP_RADIO(0x019) /* POWER SWITCH Control */ +#define B2063_PLL_SP1 B43_LP_RADIO(0x01A) /* PLL SP 1 */ +#define B2063_PLL_SP2 B43_LP_RADIO(0x01B) /* PLL SP 2 */ +#define B2063_LOGEN_SP1 B43_LP_RADIO(0x01C) /* LOGEN SP 1 */ +#define B2063_LOGEN_SP2 B43_LP_RADIO(0x01D) /* LOGEN SP 2 */ +#define B2063_LOGEN_SP3 B43_LP_RADIO(0x01E) /* LOGEN SP 3 */ +#define B2063_LOGEN_SP4 B43_LP_RADIO(0x01F) /* LOGEN SP 4 */ +#define B2063_LOGEN_SP5 B43_LP_RADIO(0x020) /* LOGEN SP 5 */ +#define B2063_G_RX_SP1 B43_LP_RADIO(0x021) /* G RX SP 1 */ +#define B2063_G_RX_SP2 B43_LP_RADIO(0x022) /* G RX SP 2 */ +#define B2063_G_RX_SP3 B43_LP_RADIO(0x023) /* G RX SP 3 */ +#define B2063_G_RX_SP4 B43_LP_RADIO(0x024) /* G RX SP 4 */ +#define B2063_G_RX_SP5 B43_LP_RADIO(0x025) /* G RX SP 5 */ +#define B2063_G_RX_SP6 B43_LP_RADIO(0x026) /* G RX SP 6 */ +#define B2063_G_RX_SP7 B43_LP_RADIO(0x027) /* G RX SP 7 */ +#define B2063_G_RX_SP8 B43_LP_RADIO(0x028) /* G RX SP 8 */ +#define B2063_G_RX_SP9 B43_LP_RADIO(0x029) /* G RX SP 9 */ +#define B2063_G_RX_SP10 B43_LP_RADIO(0x02A) /* G RX SP 10 */ +#define B2063_G_RX_SP11 B43_LP_RADIO(0x02B) /* G RX SP 11 */ +#define B2063_A_RX_SP1 B43_LP_RADIO(0x02C) /* A RX SP 1 */ +#define B2063_A_RX_SP2 B43_LP_RADIO(0x02D) /* A RX SP 2 */ +#define B2063_A_RX_SP3 B43_LP_RADIO(0x02E) /* A RX SP 3 */ +#define B2063_A_RX_SP4 B43_LP_RADIO(0x02F) /* A RX SP 4 */ +#define B2063_A_RX_SP5 B43_LP_RADIO(0x030) /* A RX SP 5 */ +#define B2063_A_RX_SP6 B43_LP_RADIO(0x031) /* A RX SP 6 */ +#define B2063_A_RX_SP7 B43_LP_RADIO(0x032) /* A RX SP 7 */ +#define B2063_RX_BB_SP1 B43_LP_RADIO(0x033) /* RX BB SP 1 */ +#define B2063_RX_BB_SP2 B43_LP_RADIO(0x034) /* RX BB SP 2 */ +#define B2063_RX_BB_SP3 B43_LP_RADIO(0x035) /* RX BB SP 3 */ +#define B2063_RX_BB_SP4 B43_LP_RADIO(0x036) /* RX BB SP 4 */ +#define B2063_RX_BB_SP5 B43_LP_RADIO(0x037) /* RX BB SP 5 */ +#define B2063_RX_BB_SP6 B43_LP_RADIO(0x038) /* RX BB SP 6 */ +#define B2063_RX_BB_SP7 B43_LP_RADIO(0x039) /* RX BB SP 7 */ +#define B2063_RX_BB_SP8 B43_LP_RADIO(0x03A) /* RX BB SP 8 */ +#define B2063_TX_RF_SP1 B43_LP_RADIO(0x03B) /* TX RF SP 1 */ +#define B2063_TX_RF_SP2 B43_LP_RADIO(0x03C) /* TX RF SP 2 */ +#define B2063_TX_RF_SP3 B43_LP_RADIO(0x03D) /* TX RF SP 3 */ +#define B2063_TX_RF_SP4 B43_LP_RADIO(0x03E) /* TX RF SP 4 */ +#define B2063_TX_RF_SP5 B43_LP_RADIO(0x03F) /* TX RF SP 5 */ +#define B2063_TX_RF_SP6 B43_LP_RADIO(0x040) /* TX RF SP 6 */ +#define B2063_TX_RF_SP7 B43_LP_RADIO(0x041) /* TX RF SP 7 */ +#define B2063_TX_RF_SP8 B43_LP_RADIO(0x042) /* TX RF SP 8 */ +#define B2063_TX_RF_SP9 B43_LP_RADIO(0x043) /* TX RF SP 9 */ +#define B2063_TX_RF_SP10 B43_LP_RADIO(0x044) /* TX RF SP 10 */ +#define B2063_TX_RF_SP11 B43_LP_RADIO(0x045) /* TX RF SP 11 */ +#define B2063_TX_RF_SP12 B43_LP_RADIO(0x046) /* TX RF SP 12 */ +#define B2063_TX_RF_SP13 B43_LP_RADIO(0x047) /* TX RF SP 13 */ +#define B2063_TX_RF_SP14 B43_LP_RADIO(0x048) /* TX RF SP 14 */ +#define B2063_TX_RF_SP15 B43_LP_RADIO(0x049) /* TX RF SP 15 */ +#define B2063_TX_RF_SP16 B43_LP_RADIO(0x04A) /* TX RF SP 16 */ +#define B2063_TX_RF_SP17 B43_LP_RADIO(0x04B) /* TX RF SP 17 */ +#define B2063_PA_SP1 B43_LP_RADIO(0x04C) /* PA SP 1 */ +#define B2063_PA_SP2 B43_LP_RADIO(0x04D) /* PA SP 2 */ +#define B2063_PA_SP3 B43_LP_RADIO(0x04E) /* PA SP 3 */ +#define B2063_PA_SP4 B43_LP_RADIO(0x04F) /* PA SP 4 */ +#define B2063_PA_SP5 B43_LP_RADIO(0x050) /* PA SP 5 */ +#define B2063_PA_SP6 B43_LP_RADIO(0x051) /* PA SP 6 */ +#define B2063_PA_SP7 B43_LP_RADIO(0x052) /* PA SP 7 */ +#define B2063_TX_BB_SP1 B43_LP_RADIO(0x053) /* TX BB SP 1 */ +#define B2063_TX_BB_SP2 B43_LP_RADIO(0x054) /* TX BB SP 2 */ +#define B2063_TX_BB_SP3 B43_LP_RADIO(0x055) /* TX BB SP 3 */ +#define B2063_REG_SP1 B43_LP_RADIO(0x056) /* REG SP 1 */ +#define B2063_BANDGAP_CTL1 B43_LP_RADIO(0x057) /* BANDGAP Control 1 */ +#define B2063_BANDGAP_CTL2 B43_LP_RADIO(0x058) /* BANDGAP Control 2 */ +#define B2063_LPO_CTL1 B43_LP_RADIO(0x059) /* LPO Control 1 */ +#define B2063_RC_CALIB_CTL1 B43_LP_RADIO(0x05A) /* RC Calibration Control 1 */ +#define B2063_RC_CALIB_CTL2 B43_LP_RADIO(0x05B) /* RC Calibration Control 2 */ +#define B2063_RC_CALIB_CTL3 B43_LP_RADIO(0x05C) /* RC Calibration Control 3 */ +#define B2063_RC_CALIB_CTL4 B43_LP_RADIO(0x05D) /* RC Calibration Control 4 */ +#define B2063_RC_CALIB_CTL5 B43_LP_RADIO(0x05E) /* RC Calibration Control 5 */ +#define B2063_RC_CALIB_CTL6 B43_LP_RADIO(0x05F) /* RC Calibration Control 6 */ +#define B2063_RC_CALIB_CTL7 B43_LP_RADIO(0x060) /* RC Calibration Control 7 */ +#define B2063_RC_CALIB_CTL8 B43_LP_RADIO(0x061) /* RC Calibration Control 8 */ +#define B2063_RC_CALIB_CTL9 B43_LP_RADIO(0x062) /* RC Calibration Control 9 */ +#define B2063_RC_CALIB_CTL10 B43_LP_RADIO(0x063) /* RC Calibration Control 10 */ +#define B2063_PLL_JTAG_CALNRST B43_LP_RADIO(0x064) /* PLL JTAG CALNRST */ +#define B2063_PLL_JTAG_IN_PLL1 B43_LP_RADIO(0x065) /* PLL JTAG IN PLL 1 */ +#define B2063_PLL_JTAG_IN_PLL2 B43_LP_RADIO(0x066) /* PLL JTAG IN PLL 2 */ +#define B2063_PLL_JTAG_PLL_CP1 B43_LP_RADIO(0x067) /* PLL JTAG PLL CP 1 */ +#define B2063_PLL_JTAG_PLL_CP2 B43_LP_RADIO(0x068) /* PLL JTAG PLL CP 2 */ +#define B2063_PLL_JTAG_PLL_CP3 B43_LP_RADIO(0x069) /* PLL JTAG PLL CP 3 */ +#define B2063_PLL_JTAG_PLL_CP4 B43_LP_RADIO(0x06A) /* PLL JTAG PLL CP 4 */ +#define B2063_PLL_JTAG_PLL_CTL1 B43_LP_RADIO(0x06B) /* PLL JTAG PLL Control 1 */ +#define B2063_PLL_JTAG_PLL_LF1 B43_LP_RADIO(0x06C) /* PLL JTAG PLL LF 1 */ +#define B2063_PLL_JTAG_PLL_LF2 B43_LP_RADIO(0x06D) /* PLL JTAG PLL LF 2 */ +#define B2063_PLL_JTAG_PLL_LF3 B43_LP_RADIO(0x06E) /* PLL JTAG PLL LF 3 */ +#define B2063_PLL_JTAG_PLL_LF4 B43_LP_RADIO(0x06F) /* PLL JTAG PLL LF 4 */ +#define B2063_PLL_JTAG_PLL_SG1 B43_LP_RADIO(0x070) /* PLL JTAG PLL SG 1 */ +#define B2063_PLL_JTAG_PLL_SG2 B43_LP_RADIO(0x071) /* PLL JTAG PLL SG 2 */ +#define B2063_PLL_JTAG_PLL_SG3 B43_LP_RADIO(0x072) /* PLL JTAG PLL SG 3 */ +#define B2063_PLL_JTAG_PLL_SG4 B43_LP_RADIO(0x073) /* PLL JTAG PLL SG 4 */ +#define B2063_PLL_JTAG_PLL_SG5 B43_LP_RADIO(0x074) /* PLL JTAG PLL SG 5 */ +#define B2063_PLL_JTAG_PLL_VCO1 B43_LP_RADIO(0x075) /* PLL JTAG PLL VCO 1 */ +#define B2063_PLL_JTAG_PLL_VCO2 B43_LP_RADIO(0x076) /* PLL JTAG PLL VCO 2 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB1 B43_LP_RADIO(0x077) /* PLL JTAG PLL VCO Calibration 1 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB2 B43_LP_RADIO(0x078) /* PLL JTAG PLL VCO Calibration 2 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB3 B43_LP_RADIO(0x079) /* PLL JTAG PLL VCO Calibration 3 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB4 B43_LP_RADIO(0x07A) /* PLL JTAG PLL VCO Calibration 4 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB5 B43_LP_RADIO(0x07B) /* PLL JTAG PLL VCO Calibration 5 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB6 B43_LP_RADIO(0x07C) /* PLL JTAG PLL VCO Calibration 6 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB7 B43_LP_RADIO(0x07D) /* PLL JTAG PLL VCO Calibration 7 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB8 B43_LP_RADIO(0x07E) /* PLL JTAG PLL VCO Calibration 8 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB9 B43_LP_RADIO(0x07F) /* PLL JTAG PLL VCO Calibration 9 */ +#define B2063_PLL_JTAG_PLL_VCO_CALIB10 B43_LP_RADIO(0x080) /* PLL JTAG PLL VCO Calibration 10 */ +#define B2063_PLL_JTAG_PLL_XTAL_12 B43_LP_RADIO(0x081) /* PLL JTAG PLL XTAL 1 2 */ +#define B2063_PLL_JTAG_PLL_XTAL3 B43_LP_RADIO(0x082) /* PLL JTAG PLL XTAL 3 */ +#define B2063_LOGEN_ACL1 B43_LP_RADIO(0x083) /* LOGEN ACL 1 */ +#define B2063_LOGEN_ACL2 B43_LP_RADIO(0x084) /* LOGEN ACL 2 */ +#define B2063_LOGEN_ACL3 B43_LP_RADIO(0x085) /* LOGEN ACL 3 */ +#define B2063_LOGEN_ACL4 B43_LP_RADIO(0x086) /* LOGEN ACL 4 */ +#define B2063_LOGEN_ACL5 B43_LP_RADIO(0x087) /* LOGEN ACL 5 */ +#define B2063_LO_CALIB_INPUTS B43_LP_RADIO(0x088) /* LO Calibration INPUTS */ +#define B2063_LO_CALIB_CTL1 B43_LP_RADIO(0x089) /* LO Calibration Control 1 */ +#define B2063_LO_CALIB_CTL2 B43_LP_RADIO(0x08A) /* LO Calibration Control 2 */ +#define B2063_LO_CALIB_CTL3 B43_LP_RADIO(0x08B) /* LO Calibration Control 3 */ +#define B2063_LO_CALIB_WAITCNT B43_LP_RADIO(0x08C) /* LO Calibration WAITCNT */ +#define B2063_LO_CALIB_OVR1 B43_LP_RADIO(0x08D) /* LO Calibration OVR 1 */ +#define B2063_LO_CALIB_OVR2 B43_LP_RADIO(0x08E) /* LO Calibration OVR 2 */ +#define B2063_LO_CALIB_OVAL1 B43_LP_RADIO(0x08F) /* LO Calibration OVAL 1 */ +#define B2063_LO_CALIB_OVAL2 B43_LP_RADIO(0x090) /* LO Calibration OVAL 2 */ +#define B2063_LO_CALIB_OVAL3 B43_LP_RADIO(0x091) /* LO Calibration OVAL 3 */ +#define B2063_LO_CALIB_OVAL4 B43_LP_RADIO(0x092) /* LO Calibration OVAL 4 */ +#define B2063_LO_CALIB_OVAL5 B43_LP_RADIO(0x093) /* LO Calibration OVAL 5 */ +#define B2063_LO_CALIB_OVAL6 B43_LP_RADIO(0x094) /* LO Calibration OVAL 6 */ +#define B2063_LO_CALIB_OVAL7 B43_LP_RADIO(0x095) /* LO Calibration OVAL 7 */ +#define B2063_LO_CALIB_CALVLD1 B43_LP_RADIO(0x096) /* LO Calibration CALVLD 1 */ +#define B2063_LO_CALIB_CALVLD2 B43_LP_RADIO(0x097) /* LO Calibration CALVLD 2 */ +#define B2063_LO_CALIB_CVAL1 B43_LP_RADIO(0x098) /* LO Calibration CVAL 1 */ +#define B2063_LO_CALIB_CVAL2 B43_LP_RADIO(0x099) /* LO Calibration CVAL 2 */ +#define B2063_LO_CALIB_CVAL3 B43_LP_RADIO(0x09A) /* LO Calibration CVAL 3 */ +#define B2063_LO_CALIB_CVAL4 B43_LP_RADIO(0x09B) /* LO Calibration CVAL 4 */ +#define B2063_LO_CALIB_CVAL5 B43_LP_RADIO(0x09C) /* LO Calibration CVAL 5 */ +#define B2063_LO_CALIB_CVAL6 B43_LP_RADIO(0x09D) /* LO Calibration CVAL 6 */ +#define B2063_LO_CALIB_CVAL7 B43_LP_RADIO(0x09E) /* LO Calibration CVAL 7 */ +#define B2063_LOGEN_CALIB_EN B43_LP_RADIO(0x09F) /* LOGEN Calibration EN */ +#define B2063_LOGEN_PEAKDET1 B43_LP_RADIO(0x0A0) /* LOGEN PEAKDET 1 */ +#define B2063_LOGEN_RCCR1 B43_LP_RADIO(0x0A1) /* LOGEN RCCR 1 */ +#define B2063_LOGEN_VCOBUF1 B43_LP_RADIO(0x0A2) /* LOGEN VCOBUF 1 */ +#define B2063_LOGEN_MIXER1 B43_LP_RADIO(0x0A3) /* LOGEN MIXER 1 */ +#define B2063_LOGEN_MIXER2 B43_LP_RADIO(0x0A4) /* LOGEN MIXER 2 */ +#define B2063_LOGEN_BUF1 B43_LP_RADIO(0x0A5) /* LOGEN BUF 1 */ +#define B2063_LOGEN_BUF2 B43_LP_RADIO(0x0A6) /* LOGEN BUF 2 */ +#define B2063_LOGEN_DIV1 B43_LP_RADIO(0x0A7) /* LOGEN DIV 1 */ +#define B2063_LOGEN_DIV2 B43_LP_RADIO(0x0A8) /* LOGEN DIV 2 */ +#define B2063_LOGEN_DIV3 B43_LP_RADIO(0x0A9) /* LOGEN DIV 3 */ +#define B2063_LOGEN_CBUFRX1 B43_LP_RADIO(0x0AA) /* LOGEN CBUFRX 1 */ +#define B2063_LOGEN_CBUFRX2 B43_LP_RADIO(0x0AB) /* LOGEN CBUFRX 2 */ +#define B2063_LOGEN_CBUFTX1 B43_LP_RADIO(0x0AC) /* LOGEN CBUFTX 1 */ +#define B2063_LOGEN_CBUFTX2 B43_LP_RADIO(0x0AD) /* LOGEN CBUFTX 2 */ +#define B2063_LOGEN_IDAC1 B43_LP_RADIO(0x0AE) /* LOGEN IDAC 1 */ +#define B2063_LOGEN_SPARE1 B43_LP_RADIO(0x0AF) /* LOGEN SPARE 1 */ +#define B2063_LOGEN_SPARE2 B43_LP_RADIO(0x0B0) /* LOGEN SPARE 2 */ +#define B2063_LOGEN_SPARE3 B43_LP_RADIO(0x0B1) /* LOGEN SPARE 3 */ +#define B2063_G_RX_1ST1 B43_LP_RADIO(0x0B2) /* G RX 1ST 1 */ +#define B2063_G_RX_1ST2 B43_LP_RADIO(0x0B3) /* G RX 1ST 2 */ +#define B2063_G_RX_1ST3 B43_LP_RADIO(0x0B4) /* G RX 1ST 3 */ +#define B2063_G_RX_2ND1 B43_LP_RADIO(0x0B5) /* G RX 2ND 1 */ +#define B2063_G_RX_2ND2 B43_LP_RADIO(0x0B6) /* G RX 2ND 2 */ +#define B2063_G_RX_2ND3 B43_LP_RADIO(0x0B7) /* G RX 2ND 3 */ +#define B2063_G_RX_2ND4 B43_LP_RADIO(0x0B8) /* G RX 2ND 4 */ +#define B2063_G_RX_2ND5 B43_LP_RADIO(0x0B9) /* G RX 2ND 5 */ +#define B2063_G_RX_2ND6 B43_LP_RADIO(0x0BA) /* G RX 2ND 6 */ +#define B2063_G_RX_2ND7 B43_LP_RADIO(0x0BB) /* G RX 2ND 7 */ +#define B2063_G_RX_2ND8 B43_LP_RADIO(0x0BC) /* G RX 2ND 8 */ +#define B2063_G_RX_PS1 B43_LP_RADIO(0x0BD) /* G RX PS 1 */ +#define B2063_G_RX_PS2 B43_LP_RADIO(0x0BE) /* G RX PS 2 */ +#define B2063_G_RX_PS3 B43_LP_RADIO(0x0BF) /* G RX PS 3 */ +#define B2063_G_RX_PS4 B43_LP_RADIO(0x0C0) /* G RX PS 4 */ +#define B2063_G_RX_PS5 B43_LP_RADIO(0x0C1) /* G RX PS 5 */ +#define B2063_G_RX_MIX1 B43_LP_RADIO(0x0C2) /* G RX MIX 1 */ +#define B2063_G_RX_MIX2 B43_LP_RADIO(0x0C3) /* G RX MIX 2 */ +#define B2063_G_RX_MIX3 B43_LP_RADIO(0x0C4) /* G RX MIX 3 */ +#define B2063_G_RX_MIX4 B43_LP_RADIO(0x0C5) /* G RX MIX 4 */ +#define B2063_G_RX_MIX5 B43_LP_RADIO(0x0C6) /* G RX MIX 5 */ +#define B2063_G_RX_MIX6 B43_LP_RADIO(0x0C7) /* G RX MIX 6 */ +#define B2063_G_RX_MIX7 B43_LP_RADIO(0x0C8) /* G RX MIX 7 */ +#define B2063_G_RX_MIX8 B43_LP_RADIO(0x0C9) /* G RX MIX 8 */ +#define B2063_G_RX_PDET1 B43_LP_RADIO(0x0CA) /* G RX PDET 1 */ +#define B2063_G_RX_SPARES1 B43_LP_RADIO(0x0CB) /* G RX SPARES 1 */ +#define B2063_G_RX_SPARES2 B43_LP_RADIO(0x0CC) /* G RX SPARES 2 */ +#define B2063_G_RX_SPARES3 B43_LP_RADIO(0x0CD) /* G RX SPARES 3 */ +#define B2063_A_RX_1ST1 B43_LP_RADIO(0x0CE) /* A RX 1ST 1 */ +#define B2063_A_RX_1ST2 B43_LP_RADIO(0x0CF) /* A RX 1ST 2 */ +#define B2063_A_RX_1ST3 B43_LP_RADIO(0x0D0) /* A RX 1ST 3 */ +#define B2063_A_RX_1ST4 B43_LP_RADIO(0x0D1) /* A RX 1ST 4 */ +#define B2063_A_RX_1ST5 B43_LP_RADIO(0x0D2) /* A RX 1ST 5 */ +#define B2063_A_RX_2ND1 B43_LP_RADIO(0x0D3) /* A RX 2ND 1 */ +#define B2063_A_RX_2ND2 B43_LP_RADIO(0x0D4) /* A RX 2ND 2 */ +#define B2063_A_RX_2ND3 B43_LP_RADIO(0x0D5) /* A RX 2ND 3 */ +#define B2063_A_RX_2ND4 B43_LP_RADIO(0x0D6) /* A RX 2ND 4 */ +#define B2063_A_RX_2ND5 B43_LP_RADIO(0x0D7) /* A RX 2ND 5 */ +#define B2063_A_RX_2ND6 B43_LP_RADIO(0x0D8) /* A RX 2ND 6 */ +#define B2063_A_RX_2ND7 B43_LP_RADIO(0x0D9) /* A RX 2ND 7 */ +#define B2063_A_RX_PS1 B43_LP_RADIO(0x0DA) /* A RX PS 1 */ +#define B2063_A_RX_PS2 B43_LP_RADIO(0x0DB) /* A RX PS 2 */ +#define B2063_A_RX_PS3 B43_LP_RADIO(0x0DC) /* A RX PS 3 */ +#define B2063_A_RX_PS4 B43_LP_RADIO(0x0DD) /* A RX PS 4 */ +#define B2063_A_RX_PS5 B43_LP_RADIO(0x0DE) /* A RX PS 5 */ +#define B2063_A_RX_PS6 B43_LP_RADIO(0x0DF) /* A RX PS 6 */ +#define B2063_A_RX_MIX1 B43_LP_RADIO(0x0E0) /* A RX MIX 1 */ +#define B2063_A_RX_MIX2 B43_LP_RADIO(0x0E1) /* A RX MIX 2 */ +#define B2063_A_RX_MIX3 B43_LP_RADIO(0x0E2) /* A RX MIX 3 */ +#define B2063_A_RX_MIX4 B43_LP_RADIO(0x0E3) /* A RX MIX 4 */ +#define B2063_A_RX_MIX5 B43_LP_RADIO(0x0E4) /* A RX MIX 5 */ +#define B2063_A_RX_MIX6 B43_LP_RADIO(0x0E5) /* A RX MIX 6 */ +#define B2063_A_RX_MIX7 B43_LP_RADIO(0x0E6) /* A RX MIX 7 */ +#define B2063_A_RX_MIX8 B43_LP_RADIO(0x0E7) /* A RX MIX 8 */ +#define B2063_A_RX_PWRDET1 B43_LP_RADIO(0x0E8) /* A RX PWRDET 1 */ +#define B2063_A_RX_SPARE1 B43_LP_RADIO(0x0E9) /* A RX SPARE 1 */ +#define B2063_A_RX_SPARE2 B43_LP_RADIO(0x0EA) /* A RX SPARE 2 */ +#define B2063_A_RX_SPARE3 B43_LP_RADIO(0x0EB) /* A RX SPARE 3 */ +#define B2063_RX_TIA_CTL1 B43_LP_RADIO(0x0EC) /* RX TIA Control 1 */ +#define B2063_RX_TIA_CTL2 B43_LP_RADIO(0x0ED) /* RX TIA Control 2 */ +#define B2063_RX_TIA_CTL3 B43_LP_RADIO(0x0EE) /* RX TIA Control 3 */ +#define B2063_RX_TIA_CTL4 B43_LP_RADIO(0x0EF) /* RX TIA Control 4 */ +#define B2063_RX_TIA_CTL5 B43_LP_RADIO(0x0F0) /* RX TIA Control 5 */ +#define B2063_RX_TIA_CTL6 B43_LP_RADIO(0x0F1) /* RX TIA Control 6 */ +#define B2063_RX_BB_CTL1 B43_LP_RADIO(0x0F2) /* RX BB Control 1 */ +#define B2063_RX_BB_CTL2 B43_LP_RADIO(0x0F3) /* RX BB Control 2 */ +#define B2063_RX_BB_CTL3 B43_LP_RADIO(0x0F4) /* RX BB Control 3 */ +#define B2063_RX_BB_CTL4 B43_LP_RADIO(0x0F5) /* RX BB Control 4 */ +#define B2063_RX_BB_CTL5 B43_LP_RADIO(0x0F6) /* RX BB Control 5 */ +#define B2063_RX_BB_CTL6 B43_LP_RADIO(0x0F7) /* RX BB Control 6 */ +#define B2063_RX_BB_CTL7 B43_LP_RADIO(0x0F8) /* RX BB Control 7 */ +#define B2063_RX_BB_CTL8 B43_LP_RADIO(0x0F9) /* RX BB Control 8 */ +#define B2063_RX_BB_CTL9 B43_LP_RADIO(0x0FA) /* RX BB Control 9 */ +#define B2063_TX_RF_CTL1 B43_LP_RADIO(0x0FB) /* TX RF Control 1 */ +#define B2063_TX_RF_IDAC_LO_RF_I B43_LP_RADIO(0x0FC) /* TX RF IDAC LO RF I */ +#define B2063_TX_RF_IDAC_LO_RF_Q B43_LP_RADIO(0x0FD) /* TX RF IDAC LO RF Q */ +#define B2063_TX_RF_IDAC_LO_BB_I B43_LP_RADIO(0x0FE) /* TX RF IDAC LO BB I */ +#define B2063_TX_RF_IDAC_LO_BB_Q B43_LP_RADIO(0x0FF) /* TX RF IDAC LO BB Q */ +#define B2063_TX_RF_CTL2 B43_LP_RADIO(0x100) /* TX RF Control 2 */ +#define B2063_TX_RF_CTL3 B43_LP_RADIO(0x101) /* TX RF Control 3 */ +#define B2063_TX_RF_CTL4 B43_LP_RADIO(0x102) /* TX RF Control 4 */ +#define B2063_TX_RF_CTL5 B43_LP_RADIO(0x103) /* TX RF Control 5 */ +#define B2063_TX_RF_CTL6 B43_LP_RADIO(0x104) /* TX RF Control 6 */ +#define B2063_TX_RF_CTL7 B43_LP_RADIO(0x105) /* TX RF Control 7 */ +#define B2063_TX_RF_CTL8 B43_LP_RADIO(0x106) /* TX RF Control 8 */ +#define B2063_TX_RF_CTL9 B43_LP_RADIO(0x107) /* TX RF Control 9 */ +#define B2063_TX_RF_CTL10 B43_LP_RADIO(0x108) /* TX RF Control 10 */ +#define B2063_TX_RF_CTL14 B43_LP_RADIO(0x109) /* TX RF Control 14 */ +#define B2063_TX_RF_CTL15 B43_LP_RADIO(0x10A) /* TX RF Control 15 */ +#define B2063_PA_CTL1 B43_LP_RADIO(0x10B) /* PA Control 1 */ +#define B2063_PA_CTL2 B43_LP_RADIO(0x10C) /* PA Control 2 */ +#define B2063_PA_CTL3 B43_LP_RADIO(0x10D) /* PA Control 3 */ +#define B2063_PA_CTL4 B43_LP_RADIO(0x10E) /* PA Control 4 */ +#define B2063_PA_CTL5 B43_LP_RADIO(0x10F) /* PA Control 5 */ +#define B2063_PA_CTL6 B43_LP_RADIO(0x110) /* PA Control 6 */ +#define B2063_PA_CTL7 B43_LP_RADIO(0x111) /* PA Control 7 */ +#define B2063_PA_CTL8 B43_LP_RADIO(0x112) /* PA Control 8 */ +#define B2063_PA_CTL9 B43_LP_RADIO(0x113) /* PA Control 9 */ +#define B2063_PA_CTL10 B43_LP_RADIO(0x114) /* PA Control 10 */ +#define B2063_PA_CTL11 B43_LP_RADIO(0x115) /* PA Control 11 */ +#define B2063_PA_CTL12 B43_LP_RADIO(0x116) /* PA Control 12 */ +#define B2063_PA_CTL13 B43_LP_RADIO(0x117) /* PA Control 13 */ +#define B2063_TX_BB_CTL1 B43_LP_RADIO(0x118) /* TX BB Control 1 */ +#define B2063_TX_BB_CTL2 B43_LP_RADIO(0x119) /* TX BB Control 2 */ +#define B2063_TX_BB_CTL3 B43_LP_RADIO(0x11A) /* TX BB Control 3 */ +#define B2063_TX_BB_CTL4 B43_LP_RADIO(0x11B) /* TX BB Control 4 */ +#define B2063_GPIO_CTL1 B43_LP_RADIO(0x11C) /* GPIO Control 1 */ +#define B2063_VREG_CTL1 B43_LP_RADIO(0x11D) /* VREG Control 1 */ +#define B2063_AMUX_CTL1 B43_LP_RADIO(0x11E) /* AMUX Control 1 */ +#define B2063_IQ_CALIB_GVAR B43_LP_RADIO(0x11F) /* IQ Calibration GVAR */ +#define B2063_IQ_CALIB_CTL1 B43_LP_RADIO(0x120) /* IQ Calibration Control 1 */ +#define B2063_IQ_CALIB_CTL2 B43_LP_RADIO(0x121) /* IQ Calibration Control 2 */ +#define B2063_TEMPSENSE_CTL1 B43_LP_RADIO(0x122) /* TEMPSENSE Control 1 */ +#define B2063_TEMPSENSE_CTL2 B43_LP_RADIO(0x123) /* TEMPSENSE Control 2 */ +#define B2063_TX_RX_LOOPBACK1 B43_LP_RADIO(0x124) /* TX/RX LOOPBACK 1 */ +#define B2063_TX_RX_LOOPBACK2 B43_LP_RADIO(0x125) /* TX/RX LOOPBACK 2 */ +#define B2063_EXT_TSSI_CTL1 B43_LP_RADIO(0x126) /* EXT TSSI Control 1 */ +#define B2063_EXT_TSSI_CTL2 B43_LP_RADIO(0x127) /* EXT TSSI Control 2 */ +#define B2063_AFE_CTL B43_LP_RADIO(0x128) /* AFE Control */ + + + struct b43_phy_lp { bool initialised; }; -- cgit v1.2.3 From 0c25970dc1b0d46f2357e7c4b267ab7b93eb7cdd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 31 Aug 2008 22:15:40 +0200 Subject: p54pci: increase ring buffer index counter when skipping I'm afraid, I forgot to add the following lines to 7262d59366 ("p54pci: rx tasklet refactoring"). These changes are necessary to ensure loop termination. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54pci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index e9db4495c62..a0395af74c2 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -301,9 +301,11 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, len = le16_to_cpu(desc->len); skb = rx_buf[i]; - if (!skb) + if (!skb) { + i++; + i %= ring_limit; continue; - + } skb_put(skb, len); if (p54_rx(dev, skb)) { -- cgit v1.2.3 From 4e416a6f49b710bfe162f0cb24bc68c74493d2a0 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Sep 2008 22:48:41 +0200 Subject: p54: enhance firmware parser to reduce memory waste This patch greatly reduces one of biggest memory waste in the driver. The firmware headers provides the right values for extra head-/tailroom and mtu size which are usually much lower than the old hardcoded ones. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 6 ++++-- drivers/net/wireless/p54/p54common.c | 36 ++++++++++++++++++++++++------------ drivers/net/wireless/p54/p54common.h | 11 +++++++++++ drivers/net/wireless/p54/p54pci.c | 23 +++++++++++++++-------- drivers/net/wireless/p54/p54usb.c | 20 +++++++++++++++----- 5 files changed, 69 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index fca8762fa06..b03d13edc61 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -39,7 +39,6 @@ struct p54_control_hdr { } __attribute__ ((packed)); #define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) -#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 ) #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -53,6 +52,9 @@ struct p54_common { 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]; @@ -70,7 +72,7 @@ struct p54_common { }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); -void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); +int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); 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 6da98e6e6a9..fa61749b467 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -66,8 +66,7 @@ static struct ieee80211_supported_band band_2GHz = { .n_bitrates = ARRAY_SIZE(p54_rates), }; - -void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) +int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) { struct p54_common *priv = dev->priv; struct bootrec_exp_if *exp_if; @@ -79,7 +78,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) int i; if (priv->rx_start) - return; + return 0; while (data < end_data && *data) data++; @@ -117,11 +116,22 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (strnlen((unsigned char*)bootrec->data, 24) < 24) fw_version = (unsigned char*)bootrec->data; break; - case BR_CODE_DESCR: - priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]); + case BR_CODE_DESCR: { + struct bootrec_desc *desc = + (struct bootrec_desc *)bootrec->data; + priv->rx_start = le32_to_cpu(desc->rx_start); /* FIXME add sanity checking */ - priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500; + priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; + priv->headroom = desc->headroom; + priv->tailroom = desc->tailroom; + if (bootrec->len == 11) + priv->rx_mtu = (size_t) le16_to_cpu( + (__le16)bootrec->data[10]); + else + priv->rx_mtu = (size_t) + 0x620 - priv->tx_hdr_len; break; + } case BR_CODE_EXPOSED_IF: exp_if = (struct bootrec_exp_if *) bootrec->data; for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) @@ -152,6 +162,8 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->tx_stats[7].limit = 1; dev->queues = 4; } + + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -428,7 +440,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) 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 sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; - u32 addr = le32_to_cpu(hdr->req_id) - 0x70; + u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct memrecord *range = NULL; u32 freed = 0; u32 last_addr = priv->rx_start; @@ -550,7 +562,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, u32 target_addr = priv->rx_start; unsigned long flags; unsigned int left; - len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */ + len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; spin_lock_irqsave(&priv->tx_queue.lock, flags); left = skb_queue_len(&priv->tx_queue); @@ -585,13 +597,14 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, range->start_addr = target_addr; range->end_addr = target_addr + len; __skb_queue_after(&priv->tx_queue, target_skb, skb); - if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + + if (largest_hole < priv->rx_mtu + priv->headroom + + priv->tailroom + sizeof(struct p54_control_hdr)) ieee80211_stop_queues(dev); } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - data->req_id = cpu_to_le32(target_addr + 0x70); + data->req_id = cpu_to_le32(target_addr + priv->headroom); } static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) @@ -704,7 +717,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter->antenna = antenna; filter->magic3 = cpu_to_le32(magic3); filter->rx_addr = cpu_to_le32(priv->rx_end); - filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */ + filter->max_rx = cpu_to_le16(priv->rx_mtu); filter->rxhw = priv->rxhw; filter->magic8 = cpu_to_le16(magic8); filter->magic9 = cpu_to_le16(magic9); @@ -1084,7 +1097,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv->tx_stats[3].limit = 1; priv->tx_stats[4].limit = 5; dev->queues = 1; - dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + sizeof(struct p54_tx_control_allocdata); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index a79c1a14691..5f2af515250 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -29,6 +29,17 @@ struct bootrec_exp_if { __le16 top_compat; } __attribute__((packed)); +struct bootrec_desc { + __le16 modes; + __le16 flags; + __le32 rx_start; + __le32 rx_end; + u8 headroom; + u8 tailroom; + u8 unimportant[6]; + u8 rates[16]; +} __attribute__((packed)); + #define BR_CODE_MIN 0x80000000 #define BR_CODE_COMPONENT_ID 0x80000001 #define BR_CODE_COMPONENT_VERSION 0x80000002 diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index a0395af74c2..fdfc7189f0f 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -81,7 +81,11 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) return err; } - p54_parse_firmware(dev, fw_entry); + err = p54_parse_firmware(dev, fw_entry); + if (err) { + release_firmware(fw_entry); + return err; + } data = (__le32 *) fw_entry->data; remains = fw_entry->size; @@ -258,17 +262,17 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev, if (!desc->host_addr) { struct sk_buff *skb; dma_addr_t mapping; - skb = dev_alloc_skb(MAX_RX_SIZE); + skb = dev_alloc_skb(priv->common.rx_mtu + 32); if (!skb) break; mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), - MAX_RX_SIZE, + priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); desc->host_addr = cpu_to_le32(mapping); desc->device_addr = 0; // FIXME: necessary? - desc->len = cpu_to_le16(MAX_RX_SIZE); + desc->len = cpu_to_le16(priv->common.rx_mtu + 32); desc->flags = 0; rx_buf[i] = skb; } @@ -311,12 +315,13 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, if (p54_rx(dev, skb)) { pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); rx_buf[i] = NULL; desc->host_addr = 0; } else { skb_trim(skb, 0); - desc->len = cpu_to_le16(MAX_RX_SIZE); + desc->len = cpu_to_le16(priv->common.rx_mtu + 32); } i++; @@ -534,7 +539,8 @@ static void p54p_stop(struct ieee80211_hw *dev) if (desc->host_addr) pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); kfree_skb(priv->rx_buf_data[i]); priv->rx_buf_data[i] = NULL; } @@ -544,7 +550,8 @@ static void p54p_stop(struct ieee80211_hw *dev) if (desc->host_addr) pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + priv->common.rx_mtu + 32, + PCI_DMA_FROMDEVICE); kfree_skb(priv->rx_buf_mgmt[i]); priv->rx_buf_mgmt[i] = NULL; } diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 8a420df605a..4dca209a6e0 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -95,7 +95,7 @@ static void p54u_rx_cb(struct urb *urb) skb_pull(skb, sizeof(struct net2280_tx_hdr)); if (p54_rx(dev, skb)) { - skb = dev_alloc_skb(MAX_RX_SIZE); + skb = dev_alloc_skb(priv->common.rx_mtu + 32); if (unlikely(!skb)) { usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ @@ -145,7 +145,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) struct p54u_rx_info *info; while (skb_queue_len(&priv->rx_queue) < 32) { - skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL); + skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL); if (!skb) break; entry = usb_alloc_urb(0, GFP_KERNEL); @@ -153,7 +153,10 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) kfree_skb(skb); break; } - usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb); + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), + skb_tail_pointer(skb), + priv->common.rx_mtu + 32, p54u_rx_cb, skb); info = (struct p54u_rx_info *) skb->cb; info->urb = entry; info->dev = dev; @@ -412,7 +415,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) goto err_req_fw_failed; } - p54_parse_firmware(dev, fw_entry); + err = p54_parse_firmware(dev, fw_entry); + if (err) + goto err_upload_failed; left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); strcpy(buf, start_string); @@ -549,7 +554,12 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return err; } - p54_parse_firmware(dev, fw_entry); + err = p54_parse_firmware(dev, fw_entry); + if (err) { + kfree(buf); + release_firmware(fw_entry); + return err; + } #define P54U_WRITE(type, addr, data) \ do {\ -- cgit v1.2.3 From 7cb770729ba895f73253dfcd46c3fcba45d896f9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 1 Sep 2008 22:48:51 +0200 Subject: p54: move eeprom code into common library Both p54pci and p54usb uses a good chunk of device specific code to get the data from the device's eeprom into the drivers memory. So, this patch reduces the code size and will it make life easier if someone wants to implement ethtool eeprom dumping features. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 9 ++- drivers/net/wireless/p54/p54common.c | 131 ++++++++++++++++++++++++++----- drivers/net/wireless/p54/p54pci.c | 144 ++++------------------------------- drivers/net/wireless/p54/p54usb.c | 88 ++------------------- 4 files changed, 137 insertions(+), 235 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index b03d13edc61..3d44ab34ee6 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -38,7 +38,7 @@ struct p54_control_hdr { u8 data[0]; } __attribute__ ((packed)); -#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) +#define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -63,18 +63,19 @@ struct p54_common { struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; - __le16 rxhw; + u16 rxhw; u8 version; unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; struct ieee80211_tx_queue_stats tx_stats[8]; + void *eeprom; + struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); -int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); -void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); +int p54_read_eeprom(struct ieee80211_hw *dev); struct ieee80211_hw *p54_init_common(size_t priv_data_len); void p54_free_common(struct ieee80211_hw *dev); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index fa61749b467..6d8248eac6e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -249,6 +249,9 @@ static int p54_convert_rev1(struct ieee80211_hw *dev, return 0; } +const char* p54_rf_chips[] = { "NULL", "Indigo?", "Duette", + "Frisbee", "Xbow", "Longbow" }; + int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -258,6 +261,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) void *tmp; int err; u8 *end = (u8 *)eeprom + len; + DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -339,7 +343,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) while ((u8 *)tmp < entry->data + data_len) { struct bootrec_exp_if *exp_if = tmp; if (le16_to_cpu(exp_if->if_id) == 0xF) - priv->rxhw = exp_if->variant & cpu_to_le16(0x07); + priv->rxhw = le16_to_cpu(exp_if->variant) & 0x07; tmp += sizeof(struct bootrec_exp_if); } break; @@ -365,6 +369,37 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } + switch (priv->rxhw) { + case 4: /* XBow */ + case 1: /* Indigo? */ + case 2: /* Duette */ + /* TODO: 5GHz initialization goes here */ + + case 3: /* Frisbee */ + case 5: /* Longbow */ + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + break; + default: + printk(KERN_ERR "%s: unsupported RF-Chip\n", + wiphy_name(dev->wiphy)); + err = -EINVAL; + goto err; + } + + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + u8 perm_addr[ETH_ALEN]; + + printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n", + wiphy_name(dev->wiphy)); + random_ether_addr(perm_addr); + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + } + + printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n", + wiphy_name(dev->wiphy), + print_mac(mac, dev->wiphy->perm_addr), + priv->version, p54_rf_chips[priv->rxhw]); + return 0; err: @@ -388,20 +423,6 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) } EXPORT_SYMBOL_GPL(p54_parse_eeprom); -void p54_fill_eeprom_readback(struct p54_control_hdr *hdr) -{ - struct p54_eeprom_lm86 *eeprom_hdr; - - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000); - 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->offset = 0x0; - eeprom_hdr->len = cpu_to_le16(0x2000); -} -EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback); - static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; @@ -499,6 +520,21 @@ out: 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_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; + struct p54_common *priv = dev->priv; + + if (!priv->eeprom) + return ; + + memcpy(priv->eeprom, eeprom->data, eeprom->len); + + complete(&priv->eeprom_comp); +} + static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; @@ -509,6 +545,9 @@ static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) break; case P54_CONTROL_TYPE_BBP: break; + case P54_CONTROL_TYPE_EEPROM_READBACK: + p54_rx_eeprom_readback(dev, skb); + break; default: printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); @@ -607,6 +646,64 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, data->req_id = cpu_to_le32(target_addr + priv->headroom); } +int p54_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr = NULL; + struct p54_eeprom_lm86 *eeprom_hdr; + size_t eeprom_size = 0x2020, offset = 0, blocksize; + int ret = -ENOMEM; + void *eeprom = NULL; + + hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + + sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); + if (!hdr) + 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; + + 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, hdr->len + sizeof(*hdr)); + priv->tx(dev, hdr, hdr->len + sizeof(*hdr), 0); + + if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { + printk(KERN_ERR "%s: device does not respond!\n", + wiphy_name(dev->wiphy)); + ret = -EBUSY; + goto free; + } + + memcpy(eeprom + offset, priv->eeprom, blocksize); + offset += blocksize; + eeprom_size -= blocksize; + } + + ret = p54_parse_eeprom(dev, eeprom, offset); +free: + kfree(priv->eeprom); + priv->eeprom = NULL; + kfree(hdr); + kfree(eeprom); + + return ret; +} +EXPORT_SYMBOL_GPL(p54_read_eeprom); + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -718,7 +815,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter->magic3 = cpu_to_le32(magic3); filter->rx_addr = cpu_to_le32(priv->rx_end); filter->max_rx = cpu_to_le16(priv->rx_mtu); - filter->rxhw = priv->rxhw; + filter->rxhw = cpu_to_le16(priv->rxhw); filter->magic8 = cpu_to_le16(magic8); filter->magic9 = cpu_to_le16(magic9); @@ -1081,7 +1178,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_INVALID; skb_queue_head_init(&priv->tx_queue); - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_UNSPEC; @@ -1101,6 +1197,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) sizeof(struct p54_tx_control_allocdata); mutex_init(&priv->conf_mutex); + init_completion(&priv->eeprom_comp); return dev; } diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index fdfc7189f0f..1594786205f 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -72,8 +72,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - mdelay(50); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); if (err) { printk(KERN_ERR "%s (p54pci): cannot find firmware " @@ -126,120 +124,10 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) wmb(); udelay(10); - return 0; -} - -static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id) -{ - struct p54p_priv *priv = (struct p54p_priv *) dev_id; - __le32 reg; - - reg = P54P_READ(int_ident); - P54P_WRITE(int_ack, reg); - - if (reg & P54P_READ(int_enable)) - complete(&priv->boot_comp); - - return IRQ_HANDLED; -} - -static int p54p_read_eeprom(struct ieee80211_hw *dev) -{ - struct p54p_priv *priv = dev->priv; - struct p54p_ring_control *ring_control = priv->ring_control; - int err; - struct p54_control_hdr *hdr; - void *eeprom; - dma_addr_t rx_mapping, tx_mapping; - u16 alen; - - init_completion(&priv->boot_comp); - err = request_irq(priv->pdev->irq, &p54p_simple_interrupt, - IRQF_SHARED, "p54pci", priv); - if (err) { - printk(KERN_ERR "%s (p54pci): failed to register IRQ handler\n", - pci_name(priv->pdev)); - return err; - } - - eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!eeprom) { - printk(KERN_ERR "%s (p54pci): no memory for eeprom!\n", - pci_name(priv->pdev)); - err = -ENOMEM; - goto out; - } - - memset(ring_control, 0, sizeof(*ring_control)); - P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma)); - P54P_READ(ring_control_base); - udelay(10); - - P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); - P54P_READ(int_enable); - udelay(10); - - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); - - if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { - printk(KERN_ERR "%s (p54pci): Cannot boot firmware!\n", - pci_name(priv->pdev)); - err = -EINVAL; - goto out; - } - - P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); - P54P_READ(int_enable); - - hdr = eeprom + 0x2010; - p54_fill_eeprom_readback(hdr); - hdr->req_id = cpu_to_le32(priv->common.rx_start); - - rx_mapping = pci_map_single(priv->pdev, eeprom, - 0x2010, PCI_DMA_FROMDEVICE); - tx_mapping = pci_map_single(priv->pdev, (void *)hdr, - EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); - - ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); - ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); - ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); - ring_control->tx_data[0].device_addr = hdr->req_id; - ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); - - ring_control->host_idx[2] = cpu_to_le32(1); - ring_control->host_idx[1] = cpu_to_le32(1); - - wmb(); + /* wait for the firmware to boot properly */ mdelay(100); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); - - wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); - wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); - - pci_unmap_single(priv->pdev, tx_mapping, - EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); - pci_unmap_single(priv->pdev, rx_mapping, - 0x2010, PCI_DMA_FROMDEVICE); - - alen = le16_to_cpu(ring_control->rx_mgmt[0].len); - if (le32_to_cpu(ring_control->device_idx[2]) != 1 || - alen < 0x10) { - printk(KERN_ERR "%s (p54pci): Cannot read eeprom!\n", - pci_name(priv->pdev)); - err = -EINVAL; - goto out; - } - p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10); - - out: - kfree(eeprom); - P54P_WRITE(int_enable, cpu_to_le32(0)); - P54P_READ(int_enable); - udelay(10); - free_irq(priv->pdev->irq, priv); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); - return err; + return 0; } static void p54p_refill_rx_ring(struct ieee80211_hw *dev, @@ -473,6 +361,11 @@ static int p54p_open(struct ieee80211_hw *dev) } memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + err = p54p_upload_firmware(dev); + if (err) { + free_irq(priv->pdev->irq, dev); + return err; + } priv->rx_idx_data = priv->tx_idx_data = 0; priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0; @@ -482,8 +375,6 @@ static int p54p_open(struct ieee80211_hw *dev) p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt, ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt); - p54p_upload_firmware(dev); - P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma)); P54P_READ(ring_control_base); wmb(); @@ -658,16 +549,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_iounmap; } - memset(priv->ring_control, 0, sizeof(*priv->ring_control)); - - err = p54p_upload_firmware(dev); - if (err) - goto err_free_desc; - - err = p54p_read_eeprom(dev); - if (err) - goto err_free_desc; - priv->common.open = p54p_open; priv->common.stop = p54p_stop; priv->common.tx = p54p_tx; @@ -675,6 +556,12 @@ 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); + p54p_open(dev); + err = p54_read_eeprom(dev); + p54p_stop(dev); + if (err) + goto err_free_desc; + err = ieee80211_register_hw(dev); if (err) { printk(KERN_ERR "%s (p54pci): Cannot register netdevice\n", @@ -682,11 +569,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, goto err_free_common; } - printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", - wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), - priv->common.version); - return 0; err_free_common: diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 4dca209a6e0..eca858c40b1 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -315,73 +315,6 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, data, len, &alen, 2000); } -static int p54u_read_eeprom(struct ieee80211_hw *dev) -{ - struct p54u_priv *priv = dev->priv; - void *buf; - struct p54_control_hdr *hdr; - int err, alen; - size_t offset = priv->hw_type ? 0x10 : 0x20; - - buf = kmalloc(0x2020, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "p54usb: cannot allocate memory for " - "eeprom readback!\n"); - return -ENOMEM; - } - - if (priv->hw_type) { - *((u32 *) buf) = priv->common.rx_start; - err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); - if (err) { - printk(KERN_ERR "p54usb: addr send failed\n"); - goto fail; - } - } else { - struct net2280_reg_write *reg = buf; - reg->port = cpu_to_le16(NET2280_DEV_U32); - reg->addr = cpu_to_le32(P54U_DEV_BASE); - reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg)); - if (err) { - printk(KERN_ERR "p54usb: dev_int send failed\n"); - goto fail; - } - } - - hdr = buf + priv->common.tx_hdr_len; - p54_fill_eeprom_readback(hdr); - hdr->req_id = cpu_to_le32(priv->common.rx_start); - if (priv->common.tx_hdr_len) { - struct net2280_tx_hdr *tx_hdr = buf; - tx_hdr->device_addr = hdr->req_id; - tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN); - } - - /* we can just pretend to send 0x2000 bytes of nothing in the headers */ - err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, - EEPROM_READBACK_LEN + priv->common.tx_hdr_len); - if (err) { - printk(KERN_ERR "p54usb: eeprom req send failed\n"); - goto fail; - } - - err = usb_bulk_msg(priv->udev, - usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), - buf, 0x2020, &alen, 1000); - if (!err && alen > offset) { - p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset); - } else { - printk(KERN_ERR "p54usb: eeprom read failed!\n"); - err = -EINVAL; - goto fail; - } - - fail: - kfree(buf); - return err; -} - static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) { static char start_string[] = "~~~~<\r"; @@ -861,31 +794,20 @@ static int __devinit p54u_probe(struct usb_interface *intf, if (err) goto err_free_dev; - err = p54u_read_eeprom(dev); + skb_queue_head_init(&priv->rx_queue); + + p54u_open(dev); + err = p54_read_eeprom(dev); + p54u_stop(dev); if (err) goto err_free_dev; - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - u8 perm_addr[ETH_ALEN]; - - printk(KERN_WARNING "p54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); - random_ether_addr(perm_addr); - SET_IEEE80211_PERM_ADDR(dev, perm_addr); - } - - skb_queue_head_init(&priv->rx_queue); - err = ieee80211_register_hw(dev); if (err) { printk(KERN_ERR "p54usb: Cannot register netdevice\n"); goto err_free_dev; } - printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", - wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), - priv->common.version); - return 0; err_free_dev: -- cgit v1.2.3 From fb11137af83b7b66c7aab8dbc5f09d2c95684fed Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 2 Sep 2008 13:00:34 +0200 Subject: b43: Split PHY alloc and init This splits the PHY allocation from the PHY init. This is needed in order to properly support Analog handling. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 36 ++++++++----- drivers/net/wireless/b43/phy_a.c | 46 +++++++++++------ drivers/net/wireless/b43/phy_a.h | 2 - drivers/net/wireless/b43/phy_common.c | 8 ++- drivers/net/wireless/b43/phy_common.h | 29 ++++++++--- drivers/net/wireless/b43/phy_g.c | 96 +++++++++++++++++++++++------------ drivers/net/wireless/b43/phy_g.h | 2 - drivers/net/wireless/b43/phy_lp.c | 29 ++++++----- drivers/net/wireless/b43/phy_lp.h | 2 +- drivers/net/wireless/b43/phy_n.c | 35 ++++++------- drivers/net/wireless/b43/phy_n.h | 2 - 11 files changed, 178 insertions(+), 109 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fda9492d588..156e8f3151d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1091,8 +1091,12 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ msleep(1); - /* Turn Analog ON */ - b43_switch_analog(dev, 1); + /* Turn Analog ON, but only if we already know the PHY-type. + * This protects against very early setup where we don't know the + * PHY-type, yet. wireless_core_reset will be called once again later, + * when we know the PHY-type. */ + if (dev->phy.ops) + b43_switch_analog(dev, 1); macctl = b43_read32(dev, B43_MMIO_MACCTL); macctl &= ~B43_MACCTL_GMODE; @@ -2694,6 +2698,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { + b43_phy_exit(dev); b43_gpio_cleanup(dev); /* firmware is released later */ } @@ -3952,7 +3957,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) dev_kfree_skb_any(dev->wl->current_beacon); dev->wl->current_beacon = NULL; } - b43_phy_exit(dev); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(dev->dev->bus); @@ -3979,24 +3983,23 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_wireless_core_reset(dev, tmp); } + /* Reset all data structures. */ setup_struct_wldev_for_init(dev); - err = b43_phy_operations_setup(dev); - if (err) - goto err_busdown; + phy->ops->prepare_structs(dev); /* Enable IRQ routing to this device. */ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); b43_imcfglo_timeouts_workaround(dev); b43_bluetooth_coext_disable(dev); - if (phy->ops->prepare) { - err = phy->ops->prepare(dev); + if (phy->ops->prepare_hardware) { + err = phy->ops->prepare_hardware(dev); if (err) - goto err_phy_exit; + goto err_busdown; } err = b43_chip_init(dev); if (err) - goto err_phy_exit; + goto err_busdown; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_WLCOREREV, dev->dev->id.revision); hf = b43_hf_read(dev); @@ -4064,8 +4067,6 @@ out: err_chip_exit: b43_chip_exit(dev); -err_phy_exit: - b43_phy_exit(dev); err_busdown: ssb_bus_may_powerdown(bus); B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); @@ -4342,6 +4343,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev) /* We release firmware that late to not be required to re-request * is all the time when we reinit the core. */ b43_release_firmware(dev); + b43_phy_free(dev); } static int b43_wireless_core_attach(struct b43_wldev *dev) @@ -4415,16 +4417,20 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } } + err = b43_phy_allocate(dev); + if (err) + goto err_powerdown; + dev->phy.gmode = have_2ghz_phy; tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); err = b43_validate_chipaccess(dev); if (err) - goto err_powerdown; + goto err_phy_free; err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy); if (err) - goto err_powerdown; + goto err_phy_free; /* Now set some default "current_dev" */ if (!wl->current_dev) @@ -4438,6 +4444,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) out: return err; +err_phy_free: + b43_phy_free(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 2ca8353aa9a..c9f00ace46a 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -391,8 +391,6 @@ static int b43_aphy_op_allocate(struct b43_wldev *dev) return -ENOMEM; dev->phy.a = aphy; - //TODO init struct b43_phy_a - err = b43_aphy_init_tssi2dbm_table(dev); if (err) goto err_free_aphy; @@ -406,30 +404,47 @@ err_free_aphy: return err; } -static int b43_aphy_op_init(struct b43_wldev *dev) +static void b43_aphy_op_prepare_structs(struct b43_wldev *dev) { - struct b43_phy_a *aphy = dev->phy.a; + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; + const void *tssi2dbm; + int tgt_idle_tssi; - b43_phy_inita(dev); - aphy->initialised = 1; + /* tssi2dbm table is constant, so it is initialized at alloc time. + * Save a copy of the pointer. */ + tssi2dbm = aphy->tssi2dbm; + tgt_idle_tssi = aphy->tgt_idle_tssi; + + /* Zero out the whole PHY structure. */ + memset(aphy, 0, sizeof(*aphy)); + + aphy->tssi2dbm = tssi2dbm; + aphy->tgt_idle_tssi = tgt_idle_tssi; + + //TODO init struct b43_phy_a - return 0; } -static void b43_aphy_op_exit(struct b43_wldev *dev) +static void b43_aphy_op_free(struct b43_wldev *dev) { - struct b43_phy_a *aphy = dev->phy.a; + struct b43_phy *phy = &dev->phy; + struct b43_phy_a *aphy = phy->a; - if (aphy->initialised) { - //TODO - aphy->initialised = 0; - } - //TODO kfree(aphy->tssi2dbm); + aphy->tssi2dbm = NULL; + kfree(aphy); dev->phy.a = NULL; } +static int b43_aphy_op_init(struct b43_wldev *dev) +{ + b43_phy_inita(dev); + + return 0; +} + static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) { /* OFDM registers are base-registers for the A-PHY. */ @@ -608,8 +623,9 @@ static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) const struct b43_phy_operations b43_phyops_a = { .allocate = b43_aphy_op_allocate, + .free = b43_aphy_op_free, + .prepare_structs = b43_aphy_op_prepare_structs, .init = b43_aphy_op_init, - .exit = b43_aphy_op_exit, .phy_read = b43_aphy_op_read, .phy_write = b43_aphy_op_write, .radio_read = b43_aphy_op_radio_read, diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h index 583da0e416e..5cfaab7b16e 100644 --- a/drivers/net/wireless/b43/phy_a.h +++ b/drivers/net/wireless/b43/phy_a.h @@ -103,8 +103,6 @@ void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, struct b43_phy_a { - bool initialised; - /* Pointer to the table used to convert a * TSSI value to dBm-Q5.2 */ const s8 *tssi2dbm; diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index b3762d8163c..e12fca69a97 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -35,7 +35,7 @@ #include "main.h" -int b43_phy_operations_setup(struct b43_wldev *dev) +int b43_phy_allocate(struct b43_wldev *dev) { struct b43_phy *phy = &(dev->phy); int err; @@ -70,6 +70,12 @@ int b43_phy_operations_setup(struct b43_wldev *dev) return err; } +void b43_phy_free(struct b43_wldev *dev) +{ + dev->phy.ops->free(dev); + dev->phy.ops = NULL; +} + int b43_phy_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index a876e169cc8..4a1795f5fc2 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -74,11 +74,21 @@ enum b43_txpwr_result { /** * struct b43_phy_operations - Function pointers for PHY ops. * - * @prepare: Prepare the PHY. This is called before @init. + * @allocate: Allocate and initialise the PHY data structures. + * Must not be NULL. + * @free: Destroy and free the PHY data structures. + * Must not be NULL. + * + * @prepare_structs: Prepare the PHY data structures. + * The data structures allocated in @allocate are + * initialized here. + * Must not be NULL. + * @prepare_hardware: Prepare the PHY. This is called before b43_chip_init to + * do some early early PHY hardware init. * Can be NULL, if not required. * @init: Initialize the PHY. * Must not be NULL. - * @exit: Shutdown the PHY and free all data structures. + * @exit: Shutdown the PHY. * Can be NULL, if not required. * * @phy_read: Read from a PHY register. @@ -133,7 +143,9 @@ enum b43_txpwr_result { struct b43_phy_operations { /* Initialisation */ int (*allocate)(struct b43_wldev *dev); - int (*prepare)(struct b43_wldev *dev); + void (*free)(struct b43_wldev *dev); + void (*prepare_structs)(struct b43_wldev *dev); + int (*prepare_hardware)(struct b43_wldev *dev); int (*init)(struct b43_wldev *dev); void (*exit)(struct b43_wldev *dev); @@ -237,10 +249,15 @@ struct b43_phy { /** - * b43_phy_operations_setup - Initialize the PHY operations datastructure - * based on the current PHY type. + * b43_phy_allocate - Allocate PHY structs + * Allocate the PHY data structures, based on the current dev->phy.type + */ +int b43_phy_allocate(struct b43_wldev *dev); + +/** + * b43_phy_free - Free PHY structs */ -int b43_phy_operations_setup(struct b43_wldev *dev); +void b43_phy_free(struct b43_wldev *dev); /** * b43_phy_init - Initialise the PHY diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 063db5c00ce..b44740b24e7 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2635,7 +2635,7 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev) { struct b43_phy_g *gphy; struct b43_txpower_lo_control *lo; - int err, i; + int err; gphy = kzalloc(sizeof(*gphy), GFP_KERNEL); if (!gphy) { @@ -2644,6 +2644,51 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev) } dev->phy.g = gphy; + lo = kzalloc(sizeof(*lo), GFP_KERNEL); + if (!lo) { + err = -ENOMEM; + goto err_free_gphy; + } + gphy->lo_control = lo; + + err = b43_gphy_init_tssi2dbm_table(dev); + if (err) + goto err_free_lo; + + return 0; + +err_free_lo: + kfree(lo); +err_free_gphy: + kfree(gphy); +error: + return err; +} + +static void b43_gphy_op_prepare_structs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + const void *tssi2dbm; + int tgt_idle_tssi; + struct b43_txpower_lo_control *lo; + unsigned int i; + + /* tssi2dbm table is constant, so it is initialized at alloc time. + * Save a copy of the pointer. */ + tssi2dbm = gphy->tssi2dbm; + tgt_idle_tssi = gphy->tgt_idle_tssi; + /* Save the LO pointer. */ + lo = gphy->lo_control; + + /* Zero out the whole PHY structure. */ + memset(gphy, 0, sizeof(*gphy)); + + /* Restore pointers. */ + gphy->tssi2dbm = tssi2dbm; + gphy->tgt_idle_tssi = tgt_idle_tssi; + gphy->lo_control = lo; + memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig)); /* NRSSI */ @@ -2662,31 +2707,28 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev) gphy->average_tssi = 0xFF; - lo = kzalloc(sizeof(*lo), GFP_KERNEL); - if (!lo) { - err = -ENOMEM; - goto err_free_gphy; - } - gphy->lo_control = lo; - + /* Local Osciallator structure */ lo->tx_bias = 0xFF; INIT_LIST_HEAD(&lo->calib_list); +} - err = b43_gphy_init_tssi2dbm_table(dev); - if (err) - goto err_free_lo; +static void b43_gphy_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; - return 0; + kfree(gphy->lo_control); + + if (gphy->dyn_tssi_tbl) + kfree(gphy->tssi2dbm); + gphy->dyn_tssi_tbl = 0; + gphy->tssi2dbm = NULL; -err_free_lo: - kfree(lo); -err_free_gphy: kfree(gphy); -error: - return err; + dev->phy.g = NULL; } -static int b43_gphy_op_prepare(struct b43_wldev *dev) +static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -2718,28 +2760,14 @@ static int b43_gphy_op_prepare(struct b43_wldev *dev) static int b43_gphy_op_init(struct b43_wldev *dev) { - struct b43_phy_g *gphy = dev->phy.g; - b43_phy_initg(dev); - gphy->initialised = 1; return 0; } static void b43_gphy_op_exit(struct b43_wldev *dev) { - struct b43_phy_g *gphy = dev->phy.g; - - if (gphy->initialised) { - //TODO - gphy->initialised = 0; - } b43_lo_g_cleanup(dev); - kfree(gphy->lo_control); - if (gphy->dyn_tssi_tbl) - kfree(gphy->tssi2dbm); - kfree(gphy); - dev->phy.g = NULL; } static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg) @@ -3232,7 +3260,9 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) const struct b43_phy_operations b43_phyops_g = { .allocate = b43_gphy_op_allocate, - .prepare = b43_gphy_op_prepare, + .free = b43_gphy_op_free, + .prepare_structs = b43_gphy_op_prepare_structs, + .prepare_hardware = b43_gphy_op_prepare_hardware, .init = b43_gphy_op_init, .exit = b43_gphy_op_exit, .phy_read = b43_gphy_op_read, diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 913eb13e8fb..718947fd41a 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -114,8 +114,6 @@ static inline bool b43_compare_bbatt(const struct b43_bbatt *a, struct b43_txpower_lo_control; struct b43_phy_g { - bool initialised; - /* ACI (adjacent channel interference) flags. */ bool aci_enable; bool aci_wlan_automatic; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index e769ca0b29a..41994f1f0f0 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -36,34 +36,34 @@ static int b43_lpphy_op_allocate(struct b43_wldev *dev) return -ENOMEM; dev->phy.lp = lpphy; - //TODO - return 0; } -static int b43_lpphy_op_init(struct b43_wldev *dev) +static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev) { - struct b43_phy_lp *lpphy = dev->phy.lp; + struct b43_phy *phy = &dev->phy; + struct b43_phy_lp *lpphy = phy->lp; - //TODO - lpphy->initialised = 1; + memset(lpphy, 0, sizeof(*lpphy)); - return 0; + //TODO } -static void b43_lpphy_op_exit(struct b43_wldev *dev) +static void b43_lpphy_op_free(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; - if (lpphy->initialised) { - //TODO - lpphy->initialised = 0; - } - kfree(lpphy); dev->phy.lp = NULL; } +static int b43_lpphy_op_init(struct b43_wldev *dev) +{ + //TODO + + return 0; +} + static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) { b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); @@ -138,8 +138,9 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev, const struct b43_phy_operations b43_phyops_lp = { .allocate = b43_lpphy_op_allocate, + .free = b43_lpphy_op_free, + .prepare_structs = b43_lpphy_op_prepare_structs, .init = b43_lpphy_op_init, - .exit = b43_lpphy_op_exit, .phy_read = b43_lpphy_op_read, .phy_write = b43_lpphy_op_write, .radio_read = b43_lpphy_op_radio_read, diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 9a0da355f28..b0b5357abf9 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -530,7 +530,7 @@ struct b43_phy_lp { - bool initialised; + //TODO }; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8162fd7792f..617724dc6aa 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -499,35 +499,31 @@ static int b43_nphy_op_allocate(struct b43_wldev *dev) return -ENOMEM; dev->phy.n = nphy; - //TODO init struct b43_phy_n - return 0; } -static int b43_nphy_op_init(struct b43_wldev *dev) +static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) { - struct b43_phy_n *nphy = dev->phy.n; - int err; + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; - err = b43_phy_initn(dev); - if (err) - return err; - nphy->initialised = 1; + memset(nphy, 0, sizeof(*nphy)); - return 0; + //TODO init struct b43_phy_n } -static void b43_nphy_op_exit(struct b43_wldev *dev) +static void b43_nphy_op_free(struct b43_wldev *dev) { - struct b43_phy_n *nphy = dev->phy.n; + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; - if (nphy->initialised) { - //TODO - nphy->initialised = 0; - } - //TODO kfree(nphy); - dev->phy.n = NULL; + phy->n = NULL; +} + +static int b43_nphy_op_init(struct b43_wldev *dev) +{ + return b43_phy_initn(dev); } static inline void check_phyreg(struct b43_wldev *dev, u16 offset) @@ -610,8 +606,9 @@ static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) const struct b43_phy_operations b43_phyops_n = { .allocate = b43_nphy_op_allocate, + .free = b43_nphy_op_free, + .prepare_structs = b43_nphy_op_prepare_structs, .init = b43_nphy_op_init, - .exit = b43_nphy_op_exit, .phy_read = b43_nphy_op_read, .phy_write = b43_nphy_op_write, .radio_read = b43_nphy_op_radio_read, diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 3d1f65ed201..1749aef4147 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -920,8 +920,6 @@ struct b43_wldev; struct b43_phy_n { - bool initialised; - //TODO lots of missing stuff }; -- cgit v1.2.3 From d203b8ef8e5acf9dad5a53d7067ef146e6b2e837 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 2 Sep 2008 12:07:56 -0700 Subject: ath9k: uses/needs led_classdev_[un]register ath9k uses LED classdev functions, so it needs to either select or depend on them. This patch uses the same selects that ath5k uses... drivers/built-in.o: In function `ath_unregister_led': main.c:(.text+0x138c1d): undefined reference to `led_classdev_unregister' drivers/built-in.o: In function `ath_register_led': main.c:(.text+0x139c16): undefined reference to `led_classdev_register' make[1]: *** [.tmp_vmlinux1] Error 1 Signed-off-by: Randy Dunlap cc: Jouni Malinen Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 9e19dcceb3a..80a69243041 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath9k/Kconfig @@ -1,6 +1,9 @@ config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS ---help--- This module adds support for wireless adapters based on Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. -- cgit v1.2.3 From 2b80848e3818fb1c8ccddc105b065a86c68afa9d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 4 Sep 2008 12:29:38 +0200 Subject: p54usb: support LM87 firmwares This patch adds the necessary changes to support LM87 firmwares. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 6 +++ drivers/net/wireless/p54/p54common.c | 5 ++- drivers/net/wireless/p54/p54common.h | 5 --- drivers/net/wireless/p54/p54usb.c | 72 +++++++++++++++++++++++++++++------- drivers/net/wireless/p54/p54usb.h | 5 +++ 5 files changed, 73 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 3d44ab34ee6..cd2a39f544b 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -42,6 +42,11 @@ struct p54_control_hdr { #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 +#define FW_FMAC 0x464d4143 +#define FW_LM86 0x4c4d3836 +#define FW_LM87 0x4c4d3837 +#define FW_LM20 0x4c4d3230 + struct p54_common { u32 rx_start; u32 rx_end; @@ -68,6 +73,7 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; + unsigned int fw_interface; struct ieee80211_tx_queue_stats tx_stats[8]; void *eeprom; struct completion eeprom_comp; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 6d8248eac6e..e96bf1a8f84 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -93,7 +93,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) u32 code = le32_to_cpu(bootrec->code); switch (code) { case BR_CODE_COMPONENT_ID: - switch (be32_to_cpu(*(__be32 *)bootrec->data)) { + priv->fw_interface = be32_to_cpup(bootrec->data); + switch (priv->fw_interface) { case FW_FMAC: printk(KERN_INFO "p54: FreeMAC firmware\n"); break; @@ -104,7 +105,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) printk(KERN_INFO "p54: LM86 firmware\n"); break; case FW_LM87: - printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n"); + printk(KERN_INFO "p54: LM87 firmware\n"); break; default: printk(KERN_INFO "p54: unknown firmware\n"); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 5f2af515250..c24b5cddf46 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -50,11 +50,6 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF -#define FW_FMAC 0x464d4143 -#define FW_LM86 0x4c4d3836 -#define FW_LM87 0x4c4d3837 -#define FW_LM20 0x4c4d3230 - /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ struct pda_entry { diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index eca858c40b1..7444f372977 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -91,8 +91,13 @@ static void p54u_rx_cb(struct urb *urb) skb_unlink(skb, &priv->rx_queue); skb_put(skb, urb->actual_length); - if (!priv->hw_type) - skb_pull(skb, sizeof(struct net2280_tx_hdr)); + + if (priv->hw_type == P54U_NET2280) + skb_pull(skb, priv->common.tx_hdr_len); + if (priv->common.fw_interface == FW_LM87) { + skb_pull(skb, 4); + skb_put(skb, 4); + } if (p54_rx(dev, skb)) { skb = dev_alloc_skb(priv->common.rx_mtu + 32); @@ -109,9 +114,12 @@ static void p54u_rx_cb(struct urb *urb) urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); } else { - if (!priv->hw_type) - skb_push(skb, sizeof(struct net2280_tx_hdr)); - + if (priv->hw_type == P54U_NET2280) + skb_push(skb, priv->common.tx_hdr_len); + if (priv->common.fw_interface == FW_LM87) { + skb_push(skb, 4); + skb_put(skb, 4); + } skb_reset_tail_pointer(skb); skb_trim(skb, 0); if (urb->transfer_buffer != skb_tail_pointer(skb)) { @@ -210,6 +218,42 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, usb_submit_urb(data_urb, GFP_ATOMIC); } +__le32 p54u_lm87_chksum(const u32 *data, size_t length) +{ + __le32 chk = 0; + + length >>= 2; + while (length--) { + chk ^= cpu_to_le32(*data++); + chk = (chk >> 5) ^ (chk << 3); + } + + return chk; +} + +static void p54u_tx_lm87(struct ieee80211_hw *dev, + struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54u_priv *priv = dev->priv; + struct urb *data_urb; + struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + + 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; + + 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); +} + static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, size_t len, int free_on_tx) { @@ -776,21 +820,23 @@ static int __devinit p54u_probe(struct usb_interface *intf, } } priv->common.open = p54u_open; - + priv->common.stop = p54u_stop; if (recognized_pipes < P54U_PIPE_NUMBER) { priv->hw_type = P54U_3887; - priv->common.tx = p54u_tx_3887; + err = p54u_upload_firmware_3887(dev); + if (priv->common.fw_interface == FW_LM87) { + dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); + priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); + priv->common.tx = p54u_tx_lm87; + } else + priv->common.tx = p54u_tx_3887; } else { + priv->hw_type = P54U_NET2280; dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); priv->common.tx = p54u_tx_net2280; - } - priv->common.stop = p54u_stop; - - if (priv->hw_type) - err = p54u_upload_firmware_3887(dev); - else err = p54u_upload_firmware_net2280(dev); + } if (err) goto err_free_dev; diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 1baaff058c5..5b8fe91379c 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -72,6 +72,11 @@ struct net2280_tx_hdr { u8 padding[8]; } __attribute__((packed)); +struct lm87_tx_hdr { + __le32 device_addr; + __le32 chksum; +} __attribute__((packed)); + /* Some flags for the isl hardware registers controlling DMA inside the * chip */ #define ISL38XX_DMA_STATUS_DONE 0x00000001 -- cgit v1.2.3 From cb24f57fe6f94a445fad8fab6ebdde7c51857895 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 3 Sep 2008 12:12:20 +0200 Subject: b43: Move Analog switching into phy code This moves the Analog switching code into the PHY files. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 23 +++-------------------- drivers/net/wireless/b43/phy_a.c | 1 + drivers/net/wireless/b43/phy_common.c | 5 +++++ drivers/net/wireless/b43/phy_common.h | 12 ++++++++++++ drivers/net/wireless/b43/phy_g.c | 1 + drivers/net/wireless/b43/phy_lp.c | 1 + drivers/net/wireless/b43/phy_n.c | 7 +++++++ 7 files changed, 30 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 156e8f3151d..ab9fa8126b7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1052,23 +1052,6 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } -/* Turn the Analog ON/OFF */ -static void b43_switch_analog(struct b43_wldev *dev, int on) -{ - switch (dev->phy.type) { - case B43_PHYTYPE_A: - case B43_PHYTYPE_G: - b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); - break; - case B43_PHYTYPE_N: - b43_phy_write(dev, B43_NPHY_AFECTL_OVER, - on ? 0 : 0x7FFF); - break; - default: - B43_WARN_ON(1); - } -} - void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) { u32 tmslow; @@ -1096,7 +1079,7 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) * PHY-type, yet. wireless_core_reset will be called once again later, * when we know the PHY-type. */ if (dev->phy.ops) - b43_switch_analog(dev, 1); + dev->phy.ops->switch_analog(dev, 1); macctl = b43_read32(dev, B43_MMIO_MACCTL); macctl &= ~B43_MACCTL_GMODE; @@ -3952,7 +3935,7 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) b43_dma_free(dev); b43_pio_free(dev); b43_chip_exit(dev); - b43_switch_analog(dev, 0); + dev->phy.ops->switch_analog(dev, 0); if (dev->wl->current_beacon) { dev_kfree_skb_any(dev->wl->current_beacon); dev->wl->current_beacon = NULL; @@ -4437,7 +4420,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_switch_analog(dev, 0); + dev->phy.ops->switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index c9f00ace46a..0f1a84c9de6 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -632,6 +632,7 @@ const struct b43_phy_operations b43_phyops_a = { .radio_write = b43_aphy_op_radio_write, .supports_hwpctl = b43_aphy_op_supports_hwpctl, .software_rfkill = b43_aphy_op_software_rfkill, + .switch_analog = b43_phyop_switch_analog_generic, .switch_channel = b43_aphy_op_switch_channel, .get_default_chan = b43_aphy_op_get_default_chan, .set_rx_antenna = b43_aphy_op_set_rx_antenna, diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e12fca69a97..4d4345d76ab 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -374,3 +374,8 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) return average; } + +void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) +{ + b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 4a1795f5fc2..c9f5430d1d7 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -108,6 +108,8 @@ enum b43_txpwr_result { * RFKILL_STATE_SOFT_BLOCKED or * RFKILL_STATE_UNBLOCKED * Must not be NULL. + * @switch_analog: Turn the Analog on/off. + * Must not be NULL. * @switch_channel: Switch the radio to another channel. * Must not be NULL. * @get_default_chan: Just returns the default channel number. @@ -158,6 +160,7 @@ struct b43_phy_operations { /* Radio */ bool (*supports_hwpctl)(struct b43_wldev *dev); void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + void (*switch_analog)(struct b43_wldev *dev, bool on); int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); unsigned int (*get_default_chan)(struct b43_wldev *dev); void (*set_rx_antenna)(struct b43_wldev *dev, int antenna); @@ -397,5 +400,14 @@ void b43_phy_txpower_adjust_work(struct work_struct *work); */ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); +/** + * b43_phy_switch_analog_generic - Generic PHY operation for switching the Analog. + * + * It does the switching based on the PHY0 core register. + * Do _not_ call this directly. Only use it as a switch_analog callback + * for struct b43_phy_operations. + */ +void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); + #endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index b44740b24e7..e8c012c9abb 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -3271,6 +3271,7 @@ const struct b43_phy_operations b43_phyops_g = { .radio_write = b43_gphy_op_radio_write, .supports_hwpctl = b43_gphy_op_supports_hwpctl, .software_rfkill = b43_gphy_op_software_rfkill, + .switch_analog = b43_phyop_switch_analog_generic, .switch_channel = b43_gphy_op_switch_channel, .get_default_chan = b43_gphy_op_get_default_chan, .set_rx_antenna = b43_gphy_op_set_rx_antenna, diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 41994f1f0f0..c5d9dc3667c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -146,6 +146,7 @@ const struct b43_phy_operations b43_phyops_lp = { .radio_read = b43_lpphy_op_radio_read, .radio_write = b43_lpphy_op_radio_write, .software_rfkill = b43_lpphy_op_software_rfkill, + .switch_analog = b43_phyop_switch_analog_generic, .switch_channel = b43_lpphy_op_switch_channel, .get_default_chan = b43_lpphy_op_get_default_chan, .set_rx_antenna = b43_lpphy_op_set_rx_antenna, diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 617724dc6aa..8bcfda5f3f0 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -583,6 +583,12 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, {//TODO } +static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) +{ + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, + on ? 0 : 0x7FFF); +} + static int b43_nphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { @@ -614,6 +620,7 @@ const struct b43_phy_operations b43_phyops_n = { .radio_read = b43_nphy_op_radio_read, .radio_write = b43_nphy_op_radio_write, .software_rfkill = b43_nphy_op_software_rfkill, + .switch_analog = b43_nphy_op_switch_analog, .switch_channel = b43_nphy_op_switch_channel, .get_default_chan = b43_nphy_op_get_default_chan, .recalc_txpower = b43_nphy_op_recalc_txpower, -- cgit v1.2.3 From 0b7dcd9652c8d6b2a0dd04f3a3e6ca0574560042 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 3 Sep 2008 12:31:54 +0200 Subject: b43: Replace hardcoded Analog switch Replace a hardcoded Analog switch (which breaks on N-PHY) by a call to the switch_analog PHY operation. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ab9fa8126b7..c836beceb10 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2718,7 +2718,8 @@ static int b43_chip_init(struct b43_wldev *dev) if (err) goto err_gpio_clean; - b43_write16(dev, 0x03E6, 0x0000); + /* Turn the Analog on and initialize the PHY. */ + phy->ops->switch_analog(dev, 1); err = b43_phy_init(dev); if (err) goto err_gpio_clean; -- cgit v1.2.3 From e0a58eacf540c65763288c81caa74013f62d7234 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 3 Sep 2008 22:25:20 +0200 Subject: p54: set_filter refactoring p54_set_filter has a way too many unnecessary "magic" parameters and values. This patch axes all superfluous parameters and gives most of the magic values appropriate names. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 ++ drivers/net/wireless/p54/p54common.c | 39 +++++++++++++++++------------------- drivers/net/wireless/p54/p54common.h | 16 +++++++-------- 3 files changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index cd2a39f544b..fd54b273cd9 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -63,6 +63,7 @@ struct p54_common { 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; @@ -70,6 +71,7 @@ struct p54_common { struct pda_pa_curve_data *curve_data; u16 rxhw; u8 version; + u8 rx_antenna; unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index e96bf1a8f84..f742abab759 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -786,8 +786,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) } static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *dst, const u8 *src, u8 antenna, - u32 magic3, u32 magic8, u32 magic9) + const u8 *bssid) { struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; @@ -806,19 +805,19 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); - filter->filter_type = cpu_to_le16(filter_type); - memcpy(filter->dst, dst, ETH_ALEN); - if (!src) - memset(filter->src, ~0, ETH_ALEN); + 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->src, src, ETH_ALEN); - filter->antenna = antenna; - filter->magic3 = cpu_to_le32(magic3); + memcpy(filter->bssid, bssid, ETH_ALEN); + + filter->rx_antenna = priv->rx_antenna; + filter->basic_rate_mask = cpu_to_le32(0x15F); filter->rx_addr = cpu_to_le32(priv->rx_end); filter->max_rx = cpu_to_le16(priv->rx_mtu); filter->rxhw = cpu_to_le16(priv->rxhw); - filter->magic8 = cpu_to_le16(magic8); - filter->magic9 = cpu_to_le16(magic9); + filter->wakeup_timer = cpu_to_le16(500); priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1); return 0; @@ -1044,12 +1043,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); - p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); + p54_set_filter(dev, 0, NULL); switch (conf->type) { case IEEE80211_IF_TYPE_STA: - p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); + p54_set_filter(dev, 1, NULL); break; default: BUG(); /* impossible */ @@ -1067,7 +1065,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_MNTR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0); + p54_set_filter(dev, 0, NULL); } static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -1076,6 +1074,8 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + priv->rx_antenna = (conf->antenna_sel_rx == 0) ? + 2 : conf->antenna_sel_tx - 1; ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); mutex_unlock(&priv->conf_mutex); @@ -1089,8 +1089,7 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); - p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); - p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); + 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); mutex_unlock(&priv->conf_mutex); @@ -1108,11 +1107,9 @@ static void p54_configure_filter(struct ieee80211_hw *dev, if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, 0, priv->mac_addr, - NULL, 2, 0, 0, 0); + p54_set_filter(dev, 0, NULL); else - p54_set_filter(dev, 0, priv->mac_addr, - priv->bssid, 2, 0, 0, 0); + p54_set_filter(dev, 0, priv->bssid); } } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index c24b5cddf46..7b4ba37abe9 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -214,17 +214,17 @@ struct p54_tx_control_allocdata { struct p54_tx_control_filter { __le16 filter_type; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - u8 antenna; - u8 debug; - __le32 magic3; - u8 rates[8]; // FIXME: what's this for? + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 rx_antenna; + u8 rx_align; + __le32 basic_rate_mask; + u8 rts_rates[8]; __le32 rx_addr; __le16 max_rx; __le16 rxhw; - __le16 magic8; - __le16 magic9; + __le16 wakeup_timer; + __le16 unalloc; } __attribute__ ((packed)); struct p54_tx_control_channel { -- cgit v1.2.3 From 19c19d54b6bfa57746f3ec805d1d7951eefa353b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 3 Sep 2008 22:25:25 +0200 Subject: p54: better firmware support This patch hopefully contains all necessary changes to support firmwares for all devices up to atleast 2.13.3.0. (or: LowerMAC Protocol Rev: 5.5 ) And this is a big win, since: * newer firmwares are more stable and reliable than the old ones. * no problems anymore with packages > 1399 octets (without lowering the MTU). * monitor mode finally works on USB for more than just a few seconds. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 15 ++++++- drivers/net/wireless/p54/p54common.c | 85 +++++++++++++++++++++--------------- drivers/net/wireless/p54/p54common.h | 51 +++++++++++++++++----- 3 files changed, 103 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index fd54b273cd9..98d4f8e7d84 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -19,13 +19,24 @@ enum control_frame_types { P54_CONTROL_TYPE_CHANNEL_CHANGE, P54_CONTROL_TYPE_FREQDONE, P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_FREEQUEUE = 7, + P54_CONTROL_TYPE_ENCRYPTION, + P54_CONTROL_TYPE_TIM, + P54_CONTROL_TYPE_POWERMGT, + P54_CONTROL_TYPE_FREEQUEUE, P54_CONTROL_TYPE_TXDONE, P54_CONTROL_TYPE_PING, P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_EEPROM_READBACK, - P54_CONTROL_TYPE_LED + P54_CONTROL_TYPE_LED, + P54_CONTROL_TYPE_GPIO, + P54_CONTROL_TYPE_TIMER, + P54_CONTROL_TYPE_MODULATION, + P54_CONTROL_TYPE_SYNTH_CONFIG, + P54_CONTROL_TYPE_DETECTOR_VALUE, + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + P54_CONTROL_TYPE_CCE_QUIET, + P54_CONTROL_TYPE_PSM_STA_UNLOCK, }; struct p54_control_hdr { diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index f742abab759..f96f7c7e6af 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -424,11 +424,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) } EXPORT_SYMBOL_GPL(p54_parse_eeprom); -static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) +static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); + size_t header_len = sizeof(*hdr); rx_status.signal = hdr->rssi; /* XX correct? */ @@ -440,10 +441,15 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.mactime = le64_to_cpu(hdr->timestamp); rx_status.flag |= RX_FLAG_TSFT; - skb_pull(skb, sizeof(*hdr)); + if (hdr->magic & cpu_to_le16(0x4000)) + header_len += hdr->align[0]; + + skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); ieee80211_rx_irqsafe(dev, skb, &rx_status); + + return -1; } static void inline p54_wake_free_queues(struct ieee80211_hw *dev) @@ -536,7 +542,7 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, complete(&priv->eeprom_comp); } -static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) +static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; @@ -554,31 +560,19 @@ static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); break; } + + return 0; } /* 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; - switch (type) { - case 0x00: - case 0x01: - p54_rx_data(dev, skb); - return -1; - case 0x4d: - /* TODO: do something better... but then again, I've never seen this happen */ - printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n", - wiphy_name(dev->wiphy)); - break; - case 0x80: - p54_rx_control(dev, skb); - break; - default: - printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n", - wiphy_name(dev->wiphy), type); - break; - } - return 0; + + if (type == 0x80) + return p54_rx_control(dev, skb); + else + return p54_rx_data(dev, skb); } EXPORT_SYMBOL_GPL(p54_rx); @@ -791,6 +785,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, struct p54_common *priv = dev->priv; struct p54_control_hdr *hdr; struct p54_tx_control_filter *filter; + size_t data_len; hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + priv->tx_hdr_len, GFP_ATOMIC); @@ -801,8 +796,6 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, filter = (struct p54_tx_control_filter *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*filter)); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); @@ -813,13 +806,25 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, memcpy(filter->bssid, bssid, ETH_ALEN); filter->rx_antenna = priv->rx_antenna; - filter->basic_rate_mask = cpu_to_le32(0x15F); - filter->rx_addr = cpu_to_le32(priv->rx_end); - filter->max_rx = cpu_to_le16(priv->rx_mtu); - filter->rxhw = cpu_to_le16(priv->rxhw); - filter->wakeup_timer = cpu_to_le16(500); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1); + if (priv->fw_var < 0x500) { + data_len = P54_TX_CONTROL_FILTER_V1_LEN; + filter->v1.basic_rate_mask = cpu_to_le32(0x15F); + filter->v1.rx_addr = cpu_to_le32(priv->rx_end); + filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); + filter->v1.rxhw = cpu_to_le16(priv->rxhw); + filter->v1.wakeup_timer = cpu_to_le16(500); + } else { + data_len = P54_TX_CONTROL_FILTER_V2_LEN; + filter->v2.rx_addr = cpu_to_le32(priv->rx_end); + filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); + filter->v2.rxhw = cpu_to_le16(priv->rxhw); + filter->v2.timer = cpu_to_le16(1000); + } + + hdr->len = cpu_to_le16(data_len); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); + priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); return 0; } @@ -829,6 +834,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) struct p54_control_hdr *hdr; struct p54_tx_control_channel *chan; unsigned int i; + size_t data_len; void *entry; hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + @@ -841,9 +847,8 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) chan = (struct p54_tx_control_channel *) hdr->data; hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*chan)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan)); chan->flags = cpu_to_le16(0x1); chan->dwell = cpu_to_le16(0x0); @@ -895,10 +900,20 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) break; } - chan->rssical_mul = cpu_to_le16(130); - chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */ + if (priv->fw_var < 0x500) { + data_len = P54_TX_CONTROL_CHANNEL_V1_LEN; + chan->v1.rssical_mul = cpu_to_le16(130); + chan->v1.rssical_add = cpu_to_le16(0xfe70); + } else { + 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); + } - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1); + 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); return 0; err: diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 7b4ba37abe9..73a9a2c923d 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -186,7 +186,7 @@ struct p54_rx_hdr { u8 quality; u16 unknown2; __le64 timestamp; - u8 data[0]; + u8 align[0]; } __attribute__ ((packed)); struct p54_frame_sent_hdr { @@ -218,15 +218,30 @@ struct p54_tx_control_filter { u8 bssid[ETH_ALEN]; u8 rx_antenna; u8 rx_align; - __le32 basic_rate_mask; - u8 rts_rates[8]; - __le32 rx_addr; - __le16 max_rx; - __le16 rxhw; - __le16 wakeup_timer; - __le16 unalloc; + union { + struct { + __le32 basic_rate_mask; + u8 rts_rates[8]; + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 wakeup_timer; + __le16 unalloc0; + } v1 __attribute__ ((packed)); + struct { + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 timer; + __le16 unalloc0; + __le32 unalloc1; + } v2 __attribute__ ((packed)); + } __attribute__ ((packed)); } __attribute__ ((packed)); +#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter)) +#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8) + struct p54_tx_control_channel { __le16 flags; __le16 dwell; @@ -238,15 +253,29 @@ struct p54_tx_control_channel { u8 val_qpsk; u8 val_16qam; u8 val_64qam; - struct pda_pa_curve_data_sample_rev1 curve_data[8]; + struct p54_pa_curve_data_sample curve_data[8]; u8 dup_bpsk; u8 dup_qpsk; u8 dup_16qam; u8 dup_64qam; - __le16 rssical_mul; - __le16 rssical_add; + union { + struct { + __le16 rssical_mul; + __le16 rssical_add; + } v1 __attribute__ ((packed)); + + struct { + __le32 basic_rate_mask; + u8 rts_rates[8]; + __le16 rssical_mul; + __le16 rssical_add; + } v2 __attribute__ ((packed)); + } __attribute__ ((packed)); } __attribute__ ((packed)); +#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12) +#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel)) + struct p54_tx_control_led { __le16 mode; __le16 led_temporary; -- cgit v1.2.3 From cd56d3313dedaf68ec393974339edaacab74f82f Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Sep 2008 11:26:21 +0800 Subject: iwlwifi : Added bss_info_changed callback to 3945 Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 74 ++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cee3045f160..7e3e5bfed68 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6320,11 +6320,8 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl3945_bg_post_associate(struct work_struct *data) +static void iwl3945_post_associate(struct iwl3945_priv *priv) { - struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, - post_associate.work); - int rc = 0; struct ieee80211_conf *conf = NULL; DECLARE_MAC_BUF(mac); @@ -6342,8 +6339,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - mutex_lock(&priv->mutex); - if (!priv->vif || !priv->is_open) { mutex_unlock(&priv->mutex); return; @@ -6419,6 +6414,15 @@ static void iwl3945_bg_post_associate(struct work_struct *data) /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; +} + +static void iwl3945_bg_post_associate(struct work_struct *data) +{ + struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, + post_associate.work); + + mutex_lock(&priv->mutex); + iwl3945_post_associate(priv); mutex_unlock(&priv->mutex); } @@ -6948,6 +6952,63 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("leave\n"); } +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) + +static void iwl3945_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl3945_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + } + + if (changes & BSS_CHANGED_ERP_CTS_PROT) { + IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) + priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + } + + if (changes & BSS_CHANGED_ASSOC) { + IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); + /* This should never happen as this function should + * never be called from interrupt context. */ + if (WARN_ON_ONCE(in_interrupt())) + return; + if (bss_conf->assoc) { + priv->assoc_id = bss_conf->aid; + priv->beacon_int = bss_conf->beacon_int; + priv->timestamp0 = bss_conf->timestamp & 0xFFFFFFFF; + priv->timestamp1 = (bss_conf->timestamp >> 32) & + 0xFFFFFFFF; + priv->assoc_capability = bss_conf->assoc_capability; + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + mutex_lock(&priv->mutex); + iwl3945_post_associate(priv); + mutex_unlock(&priv->mutex); + } else { + priv->assoc_id = 0; + IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); + } + } else if (changes && iwl3945_is_associated(priv) && priv->assoc_id) { + IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); + iwl3945_send_rxon_assoc(priv); + } + +} + static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) { int rc = 0; @@ -7828,6 +7889,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .conf_tx = iwl3945_mac_conf_tx, .get_tsf = iwl3945_mac_get_tsf, .reset_tsf = iwl3945_mac_reset_tsf, + .bss_info_changed = iwl3945_bss_info_changed, .hw_scan = iwl3945_mac_hw_scan }; -- cgit v1.2.3 From cb43dc251ab14fc047eb91944e8376d1611b95b2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:23 +0800 Subject: iwlwifi: clean up hw scan handler This patch cleans up iwl_mac_hw_scan handler. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 35 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 676fc0acede..575c1d97828 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3179,9 +3179,9 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } -static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) { - int rc = 0; + int ret; unsigned long flags; struct iwl_priv *priv = hw->priv; @@ -3191,41 +3191,38 @@ static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) spin_lock_irqsave(&priv->lock, flags); if (!iwl_is_ready_rf(priv)) { - rc = -EIO; + ret = -EIO; IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); goto out_unlock; } if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ - rc = -EIO; + ret = -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)) { - rc = -EAGAIN; + time_after(priv->next_scan_jiffies, jiffies)) { + ret = -EAGAIN; goto out_unlock; } /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + - IWL_DELAY_NEXT_SCAN, jiffies)) { - rc = -EAGAIN; + if (priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { + ret = -EAGAIN; goto out_unlock; } - if (len) { - IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl_escape_essid(ssid, len), (int)len); - + if (ssid_len) { priv->one_direct_scan = 1; - priv->direct_ssid_len = (u8) - min((u8) len, (u8) IW_ESSID_MAX_SIZE); + priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); - } else + } else { priv->one_direct_scan = 0; + } - rc = iwl_scan_initiate(priv); + ret = iwl_scan_initiate(priv); IWL_DEBUG_MAC80211("leave\n"); @@ -3233,7 +3230,7 @@ out_unlock: spin_unlock_irqrestore(&priv->lock, flags); mutex_unlock(&priv->mutex); - return rc; + return ret; } static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, @@ -4140,7 +4137,7 @@ static struct ieee80211_ops iwl4965_hw_ops = { .reset_tsf = iwl4965_mac_reset_tsf, .bss_info_changed = iwl4965_bss_info_changed, .ampdu_action = iwl4965_mac_ampdu_action, - .hw_scan = iwl4965_mac_hw_scan + .hw_scan = iwl_mac_hw_scan }; static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -- cgit v1.2.3 From 7c0399d3fde0a9958fb8e9a067a463643cf235b5 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 3 Sep 2008 11:26:24 +0800 Subject: iwlwifi: remove obsolete 4965 forward declarations This patch removes unused forward declarations functions. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f46e9cd1ca1..0711b35b9ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -637,12 +637,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) struct iwl_priv; -/* - * Forward declare iwl-4965.c functions for iwl-base.c - */ -extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); -int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, - u8 tid, int txq_id); /* Structures, enum, and defines specific to the 4965 */ -- cgit v1.2.3 From 681c0050ea3ac2e90c83d5af397d73eed848a372 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 3 Sep 2008 11:26:25 +0800 Subject: iwlwifi: allow consecutive scans in unassociated state This patch allows consecutive scans requests when driver is in unassociated state. Signed-off-by: Ron Rindjunsky Signed-off-by: Esti Kummer Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 575c1d97828..7b8af9609e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3205,12 +3205,14 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) /* we don't schedule scan within next_scan_jiffies period */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { + IWL_DEBUG_SCAN("scan rejected: within next scan period\n"); ret = -EAGAIN; goto out_unlock; } /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && + if (iwl_is_associated(priv) && priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { + IWL_DEBUG_SCAN("scan rejected: within previous scan period\n"); ret = -EAGAIN; goto out_unlock; } -- cgit v1.2.3 From 17e72782f02fe732d687e5bc2bb0ce10424d2819 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:26 +0800 Subject: iwlwifi: align set channel with mac80211 This patch makes use of mac80211 defaults for channel and band. Older code that uses G band channel 6 was removed. This patch also changes iwl_set_rxon_channel signature. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 11 +++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 4 +--- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7b8af9609e0..df5763c77af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2841,7 +2841,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co ) priv->staging_rxon.flags = 0; - iwl_set_rxon_channel(priv, conf->channel->band, channel); + iwl_set_rxon_channel(priv, conf->channel); iwl_set_flags_for_band(priv, conf->channel->band); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0a511ef8e35..0f9f8b65bf5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -773,7 +773,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_set_rxon_chain); /** - * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON + * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz * @channel: Any channel valid for the requested phymode @@ -782,10 +782,11 @@ EXPORT_SYMBOL(iwl_set_rxon_chain); * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -int iwl_set_rxon_channel(struct iwl_priv *priv, - enum ieee80211_band band, - u16 channel) +int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch) { + enum ieee80211_band band = ch->band; + u16 channel = ieee80211_frequency_to_channel(ch->center_freq); + if (!iwl_get_channel_info(priv, band, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", channel, band); @@ -910,8 +911,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; - iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 64f139e9744..ff86abc668b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -189,9 +189,7 @@ void iwl_clear_stations_table(struct iwl_priv *priv); void iwl_free_calib_results(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, - enum ieee80211_band band, - u16 channel); +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); -- cgit v1.2.3 From 322a9811a3ac1db7ddd11c959e8d9e438e97e8e6 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Sep 2008 11:26:27 +0800 Subject: iwl3945: fix unbalanced mutex The patch removes unlocking of mutex from post_associate. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7e3e5bfed68..ed5e625fe4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6339,10 +6339,9 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->vif || !priv->is_open) { - mutex_unlock(&priv->mutex); + if (!priv->vif || !priv->is_open) return; - } + iwl3945_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); -- cgit v1.2.3 From 35d55b5cde00b7cae145b42ac2de741ca0a7e5a8 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Sep 2008 11:26:28 +0800 Subject: iwl3945: replace association and beacon hooks with bss_info_changed cb Let mac80211 and bss_info_changed callback handle the association and beacon changes. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 81 --------------------------------- 1 file changed, 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8dc26adc197..1377c8190ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -688,87 +688,6 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: - switch (le16_to_cpu(header->frame_control) & - IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_BEACON:{ - /* If this is a beacon or probe response for - * our network then cache the beacon - * timestamp */ - if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA) - && !compare_ether_addr(header->addr2, - priv->bssid)) || - ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - && !compare_ether_addr(header->addr3, - priv->bssid)))) { - struct ieee80211_mgmt *mgmt = - (struct ieee80211_mgmt *)header; - __le32 *pos; - pos = (__le32 *)&mgmt->u.beacon. - timestamp; - priv->timestamp0 = le32_to_cpu(pos[0]); - priv->timestamp1 = le32_to_cpu(pos[1]); - priv->beacon_int = le16_to_cpu( - mgmt->u.beacon.beacon_int); - if (priv->call_post_assoc_from_beacon && - (priv->iw_mode == - IEEE80211_IF_TYPE_STA)) - queue_work(priv->workqueue, - &priv->post_associate.work); - - priv->call_post_assoc_from_beacon = 0; - } - - break; - } - - case IEEE80211_STYPE_ACTION: - /* TODO: Parse 802.11h frames for CSA... */ - break; - - /* - * TODO: Use the new callback function from - * mac80211 instead of sniffing these packets. - */ - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP:{ - struct ieee80211_mgmt *mgnt = - (struct ieee80211_mgmt *)header; - - /* We have just associated, give some - * time for the 4-way handshake if - * any. Don't start scan too early. */ - priv->next_scan_jiffies = jiffies + - IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; - - priv->assoc_id = (~((1 << 15) | (1 << 14)) & - le16_to_cpu(mgnt->u. - assoc_resp.aid)); - priv->assoc_capability = - le16_to_cpu(mgnt->u.assoc_resp.capab_info); - if (priv->beacon_int) - queue_work(priv->workqueue, - &priv->post_associate.work); - else - priv->call_post_assoc_from_beacon = 1; - break; - } - - case IEEE80211_STYPE_PROBE_REQ:{ - DECLARE_MAC_BUF(mac1); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - IWL_DEBUG_DROP - ("Dropping (non network): %s" - ", %s, %s\n", - print_mac(mac1, header->addr1), - print_mac(mac2, header->addr2), - print_mac(mac3, header->addr3)); - return; - } - } - case IEEE80211_FTYPE_DATA: /* fall through */ default: -- cgit v1.2.3 From dc4b1e7dda331c64dacd794a9380d4cff8547cce Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Sep 2008 11:26:30 +0800 Subject: iwl3945: removed bg_post_associate work This patch removes bg_post_associate work. A direct call iwl3945_post_associate is made to avoid the waiting by userspace programs. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 18 +----------------- 2 files changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 4dd3f0dbe07..9bbbc9d7c0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -894,7 +894,6 @@ struct iwl3945_priv { struct delayed_work thermal_periodic; struct delayed_work gather_stats; struct delayed_work scan_check; - struct delayed_work post_associate; #define IWL_DEFAULT_TX_POWER 0x0F s8 user_txpower_limit; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ed5e625fe4e..f0081ded6dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6415,16 +6415,6 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } -static void iwl3945_bg_post_associate(struct work_struct *data) -{ - struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, - post_associate.work); - - mutex_lock(&priv->mutex); - iwl3945_post_associate(priv); - mutex_unlock(&priv->mutex); -} - static void iwl3945_bg_abort_scan(struct work_struct *work) { struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv, abort_scan); @@ -6570,7 +6560,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) */ mutex_lock(&priv->mutex); iwl3945_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); mutex_unlock(&priv->mutex); } @@ -6936,7 +6925,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, if (iwl3945_is_ready_rf(priv)) { iwl3945_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl3945_commit_rxon(priv); } @@ -7240,8 +7228,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) iwl3945_reset_qos(priv); - cancel_delayed_work(&priv->post_associate); - spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = 0; priv->assoc_capability = 0; @@ -7326,7 +7312,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl3945_reset_qos(priv); - queue_work(priv->workqueue, &priv->post_associate.work); + iwl3945_post_associate(priv); mutex_unlock(&priv->mutex); @@ -7825,7 +7811,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) 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->post_associate, iwl3945_bg_post_associate); 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); @@ -7843,7 +7828,6 @@ static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv) cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); cancel_delayed_work(&priv->alive_start); - cancel_delayed_work(&priv->post_associate); cancel_work_sync(&priv->beacon_update); } -- cgit v1.2.3 From 8f4807a122d3ef680ae85c71f0b49ba8ec6d904a Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Sep 2008 11:26:31 +0800 Subject: iwl3945: avoid redundant iwl3945_get_active_dwell_time iwl3945_get_active_dwell_time is called twice within the same context. The patch removes one instance. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f0081ded6dd..e3be7f4c648 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4814,7 +4814,6 @@ static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, enum ieee80211_band band) { - u16 active = iwl3945_get_active_dwell_time(priv, band); u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; @@ -4829,9 +4828,6 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; } - if (passive <= active) - passive = active + 1; - return passive; } @@ -4856,6 +4852,9 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, active_dwell = iwl3945_get_active_dwell_time(priv, band); passive_dwell = iwl3945_get_passive_dwell_time(priv, band); + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + for (i = 0, added = 0; i < sband->n_channels; i++) { if (channels[i].flags & IEEE80211_CHAN_DISABLED) continue; -- cgit v1.2.3 From 9257746f260fadf864df90bb9b439bf457e14266 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:32 +0800 Subject: iwlwifi: use strict_strtoul instead of simple_strtoul This patch makes use of strict_srtoul in sysfs code. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 49 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index df5763c77af..b9798fa519f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3619,11 +3619,11 @@ static ssize_t store_debug_level(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = d->driver_data; - char *p = (char *)buf; - u32 val; + unsigned long val; + int ret; - val = simple_strtoul(p, &p, 0); - if (p == buf) + ret = strict_strtoul(buf, 0, &val); + if (ret) printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else @@ -3695,11 +3695,11 @@ static ssize_t store_tx_power(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - char *p = (char *)buf; - u32 val; + unsigned long val; + int ret; - val = simple_strtoul(p, &p, 10); - if (p == buf) + ret = strict_strtoul(buf, 10, &val); + if (ret) printk(KERN_INFO DRV_NAME ": %s is not in decimal form.\n", buf); else @@ -3723,7 +3723,12 @@ static ssize_t store_flags(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - u32 flags = simple_strtoul(buf, NULL, 0); + unsigned long val; + u32 flags; + int ret = strict_strtoul(buf, 0, &val); + if (!ret) + return ret; + flags = (u32)val; mutex_lock(&priv->mutex); if (le32_to_cpu(priv->staging_rxon.flags) != flags) { @@ -3731,8 +3736,7 @@ static ssize_t store_flags(struct device *d, if (iwl_scan_cancel_timeout(priv, 100)) IWL_WARNING("Could not cancel scan.\n"); else { - IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", - flags); + IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); iwl4965_commit_rxon(priv); } @@ -3758,7 +3762,12 @@ static ssize_t store_filter_flags(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - u32 filter_flags = simple_strtoul(buf, NULL, 0); + unsigned long val; + u32 filter_flags; + int ret = strict_strtoul(buf, 0, &val); + if (!ret) + return ret; + filter_flags = (u32)val; mutex_lock(&priv->mutex); if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { @@ -3859,10 +3868,12 @@ static ssize_t store_retry_rate(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = dev_get_drvdata(d); + long val; + int ret = strict_strtol(buf, 10, &val); + if (!ret) + return ret; - priv->retry_rate = simple_strtoul(buf, NULL, 0); - if (priv->retry_rate <= 0) - priv->retry_rate = 1; + priv->retry_rate = (val > 0) ? val : 1; return count; } @@ -3883,9 +3894,9 @@ static ssize_t store_power_level(struct device *d, { struct iwl_priv *priv = dev_get_drvdata(d); int ret; - int mode; + unsigned long mode; + - mode = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); if (!iwl_is_ready(priv)) { @@ -3893,6 +3904,10 @@ static ssize_t store_power_level(struct device *d, goto out; } + ret = strict_strtoul(buf, 10, &mode); + if (!ret) + goto out; + ret = iwl_power_set_user_mode(priv, mode); if (ret) { IWL_DEBUG_MAC80211("failed setting power mode.\n"); -- cgit v1.2.3 From f5efde3b1deb301ff31d61bbe5a33f3115c39284 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:34 +0800 Subject: iwlwifi: replace readl and writel with io/read/write/32 This patch replaces readl and writel with more cross platform ioread32 and iowrite32. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-io.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 0b947511461..98740e8842f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -59,7 +59,7 @@ * */ -#define _iwl3945_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs)) +#define _iwl3945_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs)) #ifdef CONFIG_IWL3945_DEBUG static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *priv, u32 ofs, u32 val) @@ -73,14 +73,14 @@ static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv * #define iwl3945_write32(priv, ofs, val) _iwl3945_write32(priv, ofs, val) #endif -#define _iwl3945_read32(priv, ofs) readl((priv)->hw_base + (ofs)) +#define _iwl3945_read32(priv, ofs) ioread32((priv)->hw_base + (ofs)) #ifdef CONFIG_IWL3945_DEBUG static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *priv, u32 ofs) { IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); return _iwl3945_read32(priv, ofs); } -#define iwl3945_read32(priv, ofs) __iwl3945_read32(__FILE__, __LINE__, priv, ofs) +#define iwl3945_read32(priv, ofs)__iwl3945_read32(__FILE__, __LINE__, priv, ofs) #else #define iwl3945_read32(p, o) _iwl3945_read32(p, o) #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 5bc3df432d2..17fb4e2e7c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -61,7 +61,7 @@ * */ -#define _iwl_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs)) +#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs)) #ifdef CONFIG_IWLWIFI_DEBUG static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, u32 ofs, u32 val) @@ -75,7 +75,7 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, #define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) #endif -#define _iwl_read32(priv, ofs) readl((priv)->hw_base + (ofs)) +#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs)) #ifdef CONFIG_IWLWIFI_DEBUG static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) { -- cgit v1.2.3 From 7c95168aba66bd11bf9efaf45e16e83ae869401d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:35 +0800 Subject: iwlwifi: remove rfkill warning from iwl-io The patch removes the warning since registers might be accessed also during rfkill. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-io.h | 18 ------------------ drivers/net/wireless/iwlwifi/iwl-io.h | 18 ------------------ 2 files changed, 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index 98740e8842f..b3fe48de3ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -153,28 +153,10 @@ static inline void __iwl3945_clear_bit(const char *f, u32 l, static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv) { int ret; - u32 gp_ctl; - #ifdef CONFIG_IWL3945_DEBUG if (atomic_read(&priv->restrict_refcnt)) return 0; #endif - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("WARNING: Requesting MAC access during RFKILL " - "wakes up NIC\n"); - - /* 10 msec allows time for NIC to complete its data save */ - gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL); - if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { - IWL_DEBUG_RF_KILL("Wait for complete power-down, " - "gpctl = 0x%08x\n", gp_ctl); - mdelay(10); - } else - IWL_DEBUG_RF_KILL("power-down complete, " - "gpctl = 0x%08x\n", gp_ctl); - } - /* this bit wakes up the NIC */ _iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL, diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 17fb4e2e7c2..9740fcc1805 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -155,28 +155,10 @@ static inline void __iwl_clear_bit(const char *f, u32 l, static inline int _iwl_grab_nic_access(struct iwl_priv *priv) { int ret; - u32 gp_ctl; - #ifdef CONFIG_IWLWIFI_DEBUG if (atomic_read(&priv->restrict_refcnt)) return 0; #endif - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("WARNING: Requesting MAC access during RFKILL " - "wakes up NIC\n"); - - /* 10 msec allows time for NIC to complete its data save */ - gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL); - if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { - IWL_DEBUG_RF_KILL("Wait for complete power-down, " - "gpctl = 0x%08x\n", gp_ctl); - mdelay(10); - } else - IWL_DEBUG_RF_KILL("power-down complete, " - "gpctl = 0x%08x\n", gp_ctl); - } - /* this bit wakes up the NIC */ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, -- cgit v1.2.3 From 6e21f2c109edd746a10e08186484bae8168cdd0c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:37 +0800 Subject: iwlwifi: generic init calibrations framework This patch allows variable number of init calibrations and allows addition new HW. This patch also fixes critical bug. Only last calibration result was applied. On reception of one calibration result all the calibration was freed. Signed-off-by: Tomas Winkler Signed-off-by: Emmanuel Grumbach Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000-hw.h | 7 ++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 63 +++++------------------------- drivers/net/wireless/iwlwifi/iwl-calib.c | 60 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 19 +-------- drivers/net/wireless/iwlwifi/iwl-core.h | 8 +++- drivers/net/wireless/iwlwifi/iwl-dev.h | 14 +++---- 6 files changed, 90 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 17d4f31c593..c479ee211c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -129,6 +129,13 @@ struct iwl5000_shared { __le32 padding2; } __attribute__ ((packed)); +/* calibrations defined for 5000 */ +/* defines the order in which results should be sent to the runtime uCode */ +enum iwl5000_calib { + IWL5000_CALIB_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 cbc01a00eaf..8b6a72949ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -444,48 +444,6 @@ static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) sizeof(cal_cmd), &cal_cmd); } -static int iwl5000_send_calib_results(struct iwl_priv *priv) -{ - int ret = 0; - - struct iwl_host_cmd hcmd = { - .id = REPLY_PHY_CALIBRATION_CMD, - .meta.flags = CMD_SIZE_HUGE, - }; - - if (priv->calib_results.lo_res) { - hcmd.len = priv->calib_results.lo_res_len; - hcmd.data = priv->calib_results.lo_res; - ret = iwl_send_cmd_sync(priv, &hcmd); - - if (ret) - goto err; - } - - if (priv->calib_results.tx_iq_res) { - hcmd.len = priv->calib_results.tx_iq_res_len; - hcmd.data = priv->calib_results.tx_iq_res; - ret = iwl_send_cmd_sync(priv, &hcmd); - - if (ret) - goto err; - } - - if (priv->calib_results.tx_iq_perd_res) { - hcmd.len = priv->calib_results.tx_iq_perd_res_len; - hcmd.data = priv->calib_results.tx_iq_perd_res; - ret = iwl_send_cmd_sync(priv, &hcmd); - - if (ret) - goto err; - } - - return 0; -err: - IWL_ERROR("Error %d\n", ret); - return ret; -} - static int iwl5000_send_calib_cfg(struct iwl_priv *priv) { struct iwl5000_calib_cfg_cmd calib_cfg_cmd; @@ -510,33 +468,30 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; - - iwl_free_calib_results(priv); + int index; /* reduce the size of the length field itself */ len -= 4; + /* Define the order in which the results will be sent to the runtime + * 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: - priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC); - priv->calib_results.lo_res_len = len; - memcpy(priv->calib_results.lo_res, pkt->u.raw, len); + index = IWL5000_CALIB_LO; break; case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: - priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC); - priv->calib_results.tx_iq_res_len = len; - memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len); + index = IWL5000_CALIB_TX_IQ; break; case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: - priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC); - priv->calib_results.tx_iq_perd_res_len = len; - memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len); + index = IWL5000_CALIB_TX_IQ_PERD; break; default: IWL_ERROR("Unknown calibration notification %d\n", hdr->op_code); return; } + iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } static void iwl5000_rx_calib_complete(struct iwl_priv *priv, @@ -834,7 +789,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_Xtal_calib(priv); if (priv->ucode_type == UCODE_RT) - iwl5000_send_calib_results(priv); + iwl_send_calib_results(priv); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index ef49440bd7f..35fb4a4f737 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -66,6 +66,66 @@ #include "iwl-core.h" #include "iwl-calib.h" +/***************************************************************************** + * INIT calibrations framework + *****************************************************************************/ + + int iwl_send_calib_results(struct iwl_priv *priv) +{ + int ret = 0; + int i = 0; + + struct iwl_host_cmd hcmd = { + .id = REPLY_PHY_CALIBRATION_CMD, + .meta.flags = CMD_SIZE_HUGE, + }; + + for (i = 0; i < IWL_CALIB_MAX; i++) + if (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: + IWL_ERROR("Error %d iteration %d\n", ret, i); + return ret; +} +EXPORT_SYMBOL(iwl_send_calib_results); + +int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) +{ + if (res->buf_len != len) { + kfree(res->buf); + res->buf = kzalloc(len, GFP_ATOMIC); + } + if (unlikely(res->buf == NULL)) + return -ENOMEM; + + res->buf_len = len; + memcpy(res->buf, buf, len); + return 0; +} +EXPORT_SYMBOL(iwl_calib_set); + +void iwl_calib_free_results(struct iwl_priv *priv) +{ + int i; + + for (i = 0; i < IWL_CALIB_MAX; i++) { + kfree(priv->calib_results[i].buf); + priv->calib_results[i].buf = NULL; + priv->calib_results[i].buf_len = 0; + } +} + +/***************************************************************************** + * RUNTIME calibrations framework + *****************************************************************************/ + /* "false alarms" are signals that our DSP tries to lock onto, * but then determines that they are either noise, or transmissions * from a distant wireless network (also "noise", really) that get diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0f9f8b65bf5..1c5406487b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -937,22 +937,6 @@ err: } EXPORT_SYMBOL(iwl_init_drv); -void iwl_free_calib_results(struct iwl_priv *priv) -{ - kfree(priv->calib_results.lo_res); - priv->calib_results.lo_res = NULL; - priv->calib_results.lo_res_len = 0; - - kfree(priv->calib_results.tx_iq_res); - priv->calib_results.tx_iq_res = NULL; - priv->calib_results.tx_iq_res_len = 0; - - kfree(priv->calib_results.tx_iq_perd_res); - priv->calib_results.tx_iq_perd_res = NULL; - priv->calib_results.tx_iq_perd_res_len = 0; -} -EXPORT_SYMBOL(iwl_free_calib_results); - int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; @@ -980,10 +964,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) } EXPORT_SYMBOL(iwl_set_tx_power); - void iwl_uninit_drv(struct iwl_priv *priv) { - iwl_free_calib_results(priv); + iwl_calib_free_results(priv); iwlcore_free_geos(priv); iwl_free_channel_map(priv); kfree(priv->scan); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ff86abc668b..b5db050b22d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -186,7 +186,6 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, void iwl_hw_detect(struct iwl_priv *priv); void iwl_clear_stations_table(struct iwl_priv *priv); -void iwl_free_calib_results(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); @@ -289,6 +288,13 @@ int iwl_scan_initiate(struct iwl_priv *priv); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); +/******************************************************************************* + * Calibrations - implemented in iwl-calib.c + ******************************************************************************/ +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); + /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0711b35b9ad..5a55c876917 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -728,13 +728,10 @@ struct statistics_general_data { u32 beacon_energy_c; }; -struct iwl_calib_results { - void *tx_iq_res; - void *tx_iq_perd_res; - void *lo_res; - u32 tx_iq_res_len; - u32 tx_iq_perd_res_len; - u32 lo_res_len; +/* Opaque calibration results */ +struct iwl_calib_result { + void *buf; + size_t buf_len; }; enum ucode_type { @@ -796,6 +793,7 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ +#define IWL_CALIB_MAX 3 struct iwl_priv { @@ -839,7 +837,7 @@ struct iwl_priv { s32 last_temperature; /* init calibration results */ - struct iwl_calib_results calib_results; + struct iwl_calib_result calib_results[IWL_CALIB_MAX]; /* Scan related variables */ unsigned long last_scan_jiffies; -- cgit v1.2.3 From 926f0b2ef24041db876ec7213fbddd7cd4555951 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 3 Sep 2008 11:26:39 +0800 Subject: iwlwifi: fix strict_strtoul error checking This patch fixes handling of strcit_strtoul return value "0 == sucess". Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b9798fa519f..ffaf3f2e8a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3726,7 +3726,7 @@ static ssize_t store_flags(struct device *d, unsigned long val; u32 flags; int ret = strict_strtoul(buf, 0, &val); - if (!ret) + if (ret) return ret; flags = (u32)val; @@ -3765,7 +3765,7 @@ static ssize_t store_filter_flags(struct device *d, unsigned long val; u32 filter_flags; int ret = strict_strtoul(buf, 0, &val); - if (!ret) + if (ret) return ret; filter_flags = (u32)val; @@ -3905,7 +3905,7 @@ static ssize_t store_power_level(struct device *d, } ret = strict_strtoul(buf, 10, &mode); - if (!ret) + if (ret) goto out; ret = iwl_power_set_user_mode(priv, mode); -- cgit v1.2.3 From e7b635814b640c6fd9dca1c254dc22fac6fb9a1a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:49 +0800 Subject: iwlwifi: cleanup PCI register handling This patch cleans up pci registers handling. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 13 +++++++------ drivers/net/wireless/iwlwifi/iwl-4965.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-agn.c | 9 +++++---- drivers/net/wireless/iwlwifi/iwl-commands.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-power.c | 27 +++++++++++---------------- 6 files changed, 31 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index fce950f4163..f4793a60944 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -98,16 +98,17 @@ #define IWL_RSSI_OFFSET 44 -#include "iwl-commands.h" /* PCI registers */ -#define PCI_LINK_CTRL 0x0F0 /* 1 byte */ -#define PCI_POWER_SOURCE 0x0C8 -#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_RETRY_TIMEOUT 0x041 +#define PCI_CFG_POWER_SOURCE 0x0C8 +#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_LINK_CTRL 0x0F0 /* PCI register values */ -#define PCI_LINK_VAL_L0S_EN 0x01 -#define PCI_LINK_VAL_L1_EN 0x02 +#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01 +#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02 +#define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) #define TFD_QUEUE_SIZE_MAX (256) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e2581229d8b..46e076af8f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -399,7 +399,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv) unsigned long flags; u32 val; u16 radio_cfg; - u8 val_link; + u16 link; spin_lock_irqsave(&priv->lock, flags); @@ -410,10 +410,10 @@ static void iwl4965_nic_config(struct iwl_priv *priv) val & ~(1 << 11)); } - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link); /* L1 is enabled by BIOS */ - if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) /* diable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8b6a72949ac..ef9d3399dfd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -208,14 +208,14 @@ static void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; - u8 val_link; + u16 link; spin_lock_irqsave(&priv->lock, flags); - pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link); /* L1 is enabled by BIOS */ - if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN) + if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) /* diable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ffaf3f2e8a9..250473138f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1273,7 +1273,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) if (src == IWL_PWR_SRC_VAUX) { u32 val; - ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE, &val); if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) @@ -4229,9 +4229,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_drvdata(pdev, priv); - /* 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 @@ -4251,6 +4248,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); + /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 28b5b09996e..fbd8cc1f51d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2026,8 +2026,8 @@ struct iwl4965_spectrum_notification { * bit 2 - '0' PM have to walk up every DTIM * '1' PM could sleep over DTIM till listen Interval. * PCI power managed - * bit 3 - '0' (PCI_LINK_CTRL & 0x1) - * '1' !(PCI_LINK_CTRL & 0x1) + * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) + * '1' !(PCI_CFG_LINK_CTRL & 0x1) * Force sleep Modes * bit 31/30- '00' use both mac/xtal sleeps * '01' force Mac sleep diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index a099c9e30e5..eb6312d867d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -152,9 +152,10 @@ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) /* initialize to default */ static int iwl_power_init_handle(struct iwl_priv *priv) { - int ret = 0, i; struct iwl_power_mgr *pow_data; int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; + struct iwl_powertable_cmd *cmd; + int i; u16 pci_pm; IWL_DEBUG_POWER("Initialize power \n"); @@ -167,25 +168,19 @@ static int iwl_power_init_handle(struct iwl_priv *priv) memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); - ret = pci_read_config_word(priv->pci_dev, - PCI_LINK_CTRL, &pci_pm); - if (ret != 0) - return 0; - else { - struct iwl_powertable_cmd *cmd; + pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm); - IWL_DEBUG_POWER("adjust power command flags\n"); + IWL_DEBUG_POWER("adjust power command flags\n"); - for (i = 0; i < IWL_POWER_MAX; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; + for (i = 0; i < IWL_POWER_MAX; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; - if (pci_pm & 0x1) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } + if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; } - return ret; + return 0; } /* adjust power command according to dtim period and power level*/ -- cgit v1.2.3 From c90a74bae10dc2a4677d1bd06b6400db229d3e1e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 3 Sep 2008 11:26:50 +0800 Subject: iwlwifi: allow association on radar channel in power save This patch disables power save upon association and enables it back after association. This allows to associate to AP on a radar channel if power save is enabled. Radar and passive channels are not allowed for TX (required for association) unless RX is received but PS may close the radio and no RX will be received effectively failing association. Signed-off-by: Emmanuel Grumbach Signed-off-by: Mohamed Abbas Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 24 ++++++++++++++++---- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-power.c | 39 +++++++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-power.h | 4 +++- 4 files changed, 61 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 250473138f3..ab92e19f0b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2486,6 +2486,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) if (!priv->vif || !priv->is_open) return; + iwl_power_cancel_timeout(priv); iwl_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); @@ -2550,10 +2551,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) break; } - /* Enable Rx differential gain and sensitivity calibrations */ - iwl_chain_noise_reset(priv); - priv->start_calib = 1; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) priv->assoc_station_added = 1; @@ -2561,7 +2558,12 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl_activate_qos(priv, 0); spin_unlock_irqrestore(&priv->lock, flags); - iwl_power_update_mode(priv, 0); + iwl_power_enable_management(priv); + + /* Enable Rx differential gain and sensitivity calibrations */ + iwl_chain_noise_reset(priv); + priv->start_calib = 1; + /* we have just associated, don't start scan too early */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } @@ -3535,6 +3537,16 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) /* Per mac80211.h: This is only used in IBSS mode... */ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + /* switch to CAM during association period. + * the ucode will block any association/authentication + * frome during assiciation period if it can not hear + * the AP because of PM. the timer enable PM back is + * association do not complete + */ + if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_RADAR)) + iwl_power_disable_management(priv, 3000); + IWL_DEBUG_MAC80211("leave - not in IBSS\n"); mutex_unlock(&priv->mutex); return; @@ -4087,6 +4099,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) /* FIXME : remove when resolved PENDING */ INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); iwl_setup_scan_deferred_work(priv); + iwl_setup_power_deferred_work(priv); if (priv->cfg->ops->lib->setup_deferred_work) priv->cfg->ops->lib->setup_deferred_work(priv); @@ -4106,6 +4119,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); + cancel_delayed_work_sync(&priv->set_power_save); cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->beacon_update); del_timer_sync(&priv->statistics_periodic); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5a55c876917..edf3d0f3f9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1024,6 +1024,7 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; + struct delayed_work set_power_save; struct delayed_work init_alive_start; struct delayed_work alive_start; struct delayed_work scan_check; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index eb6312d867d..16f834d0c48 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -319,7 +319,7 @@ EXPORT_SYMBOL(iwl_power_update_mode); * this will be usefull for rate scale to disable PM during heavy * Tx/Rx activities */ -int iwl_power_disable_management(struct iwl_priv *priv) +int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) { u16 prev_mode; int ret = 0; @@ -332,6 +332,11 @@ int iwl_power_disable_management(struct iwl_priv *priv) ret = iwl_power_update_mode(priv, 0); priv->power_data.power_disabled = 1; priv->power_data.user_power_setting = prev_mode; + cancel_delayed_work(&priv->set_power_save); + if (ms) + queue_delayed_work(priv->workqueue, &priv->set_power_save, + msecs_to_jiffies(ms)); + return ret; } @@ -426,3 +431,35 @@ int iwl_power_temperature_change(struct iwl_priv *priv) return ret; } EXPORT_SYMBOL(iwl_power_temperature_change); + +static void iwl_bg_set_power_save(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, + struct iwl_priv, set_power_save.work); + IWL_DEBUG(IWL_DL_STATE, "update power\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + /* on starting association we disable power managment + * until association, if association failed then this + * timer will expire and enable PM again. + */ + if (!iwl_is_associated(priv)) + iwl_power_enable_management(priv); + + mutex_unlock(&priv->mutex); +} +void iwl_setup_power_deferred_work(struct iwl_priv *priv) +{ + INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save); +} +EXPORT_SYMBOL(iwl_setup_power_deferred_work); + +void iwl_power_cancel_timeout(struct iwl_priv *priv) +{ + cancel_delayed_work(&priv->set_power_save); +} +EXPORT_SYMBOL(iwl_power_cancel_timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index abcbbf96a84..aa99f3647de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -78,8 +78,10 @@ struct iwl_power_mgr { u8 power_disabled; /* flag to disable using power saving level */ }; +void iwl_setup_power_deferred_work(struct iwl_priv *priv); +void iwl_power_cancel_timeout(struct iwl_priv *priv); int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); -int iwl_power_disable_management(struct iwl_priv *priv); +int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); int iwl_power_enable_management(struct iwl_priv *priv); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode); -- cgit v1.2.3 From 9734cb23a02f8de5fa99225ca61c7019ca9f232f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:52 +0800 Subject: iwlwifi: fix host command header according the HW spec This patch aligns definition of host command with the spec. The inaccuracies weren't critical though. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 20 ++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index fbd8cc1f51d..8d04e966ad4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -163,6 +163,13 @@ enum { /* iwl_cmd_header flags value */ #define IWL_CMD_FAILED_MSK 0x40 +#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) +#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) + /** * struct iwl_cmd_header * @@ -171,7 +178,7 @@ enum { */ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 flags; /* IWL_CMD_* */ + u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ /* * The driver sets up the sequence number to values of its chosing. * uCode does not use this value, but passes it back to the driver @@ -187,11 +194,12 @@ struct iwl_cmd_header { * * The Linux driver uses the following format: * - * 0:7 index/position within Tx queue - * 8:13 Tx queue selection - * 14:14 driver sets this to indicate command is in the 'huge' - * storage at the end of the command buffers, i.e. scan cmd - * 15:15 uCode sets this in uCode-originated response/notification + * 0:7 tfd index - position within TX queue + * 8:12 TX queue id + * 13 reserved + * 14 huge - driver sets this to indicate command is in the + * 'huge' storage at the end of the command buffers + * 15 unsolicited RX or uCode-originated notification */ __le16 sequence; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index edf3d0f3f9c..1943de3f764 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -225,12 +225,6 @@ struct iwl_frame { struct list_head list; }; -#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) -#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) -#define SEQ_TO_INDEX(x) ((u8)(x & 0xff)) -#define INDEX_TO_SEQ(x) ((u8)(x & 0xff)) -#define SEQ_HUGE_FRAME (0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 6cba5e9c54e..a004cc8ab8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1057,7 +1057,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | INDEX_TO_SEQ(q->write_ptr)); if (out_cmd->meta.flags & CMD_SIZE_HUGE) - out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + 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, @@ -1192,8 +1192,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); - int huge = sequence & SEQ_HUGE_FRAME; int cmd_index; + bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); struct iwl_cmd *cmd; /* If a Tx command is being handled and it isn't in the actual -- cgit v1.2.3 From 68d12b7ca7aff20190a9751a732dfc49220ae396 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 3 Sep 2008 11:26:54 +0800 Subject: iwlwifi: take a fresh set of supported rates at each cycle This patch fixes regression in iwlwifi IBSS rate scaling caused by the patch named "mac80211: eliminate IBSS warning in rate_lowest_index()" by Vladimir Koutny . Signed-off-by: Emmanuel Grumbach Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 754fef5b592..3dc57f53f5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1668,6 +1668,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, return; lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); -- cgit v1.2.3 From 05ecc2c1033677e6324965831af1ba6cefbdfa76 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:55 +0800 Subject: iwlwifi: remove bad language from the comments This patch removes bad language in the comments in iwl-agn-rs.c. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3dc57f53f5d..35a6aeefaa2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2217,8 +2217,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, sta->txrate_idx = i; sta->last_txrate_idx = sta->txrate_idx; - /* WTF is with this bogus comment? A doesn't have cck rates */ - /* For MODE_IEEE80211A, cck rates are at end of rate table */ + /* For MODE_IEEE80211A, skip over cck rates in global rate table */ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; -- cgit v1.2.3 From f93405206557077d6508682b624117ec68ea48f6 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 3 Sep 2008 11:26:58 +0800 Subject: iwl3945: enable active scanning on active channels This patch enables active scanning on active channels. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 54 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e3be7f4c648..cbbe73a1288 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4782,8 +4782,11 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses * from more than one AP. */ -#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ -#define IWL_ACTIVE_DWELL_TIME_52 (10) +#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (20) + +#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) +#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) /* For faster active scanning, scan will move to the next channel if fewer than * PLCP_QUIET_THRESH packets are heard on this channel within @@ -4792,7 +4795,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) * no other traffic). * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ #define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ -#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */ /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. * Must be set longer than active dwell time. @@ -4802,13 +4805,18 @@ 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)))) + static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, - enum ieee80211_band band) + enum ieee80211_band band, + u8 n_probes) { if (band == IEEE80211_BAND_5GHZ) - return IWL_ACTIVE_DWELL_TIME_52; + return IWL_ACTIVE_DWELL_TIME_52 + + IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); else - return IWL_ACTIVE_DWELL_TIME_24; + return IWL_ACTIVE_DWELL_TIME_24 + + IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); } static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, @@ -4833,7 +4841,7 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, enum ieee80211_band band, - u8 is_active, u8 direct_mask, + u8 is_active, u8 n_probes, struct iwl3945_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; @@ -4849,7 +4857,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, channels = sband->channels; - active_dwell = iwl3945_get_active_dwell_time(priv, band); + active_dwell = iwl3945_get_active_dwell_time(priv, band, n_probes); passive_dwell = iwl3945_get_passive_dwell_time(priv, band); if (passive_dwell <= active_dwell) @@ -4874,8 +4882,8 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, else scan_ch->type = 1; /* active */ - if (scan_ch->type & 1) - scan_ch->type |= (direct_mask << 1); + 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); @@ -6092,7 +6100,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) int rc = 0; struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; - u8 direct_mask; + u8 n_probes = 2; enum ieee80211_band band; conf = ieee80211_get_hw_conf(priv->hw); @@ -6200,7 +6208,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); - direct_mask = 1; + 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", @@ -6208,11 +6216,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data) 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); - direct_mask = 1; - } else { + n_probes++; + } else IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); - direct_mask = 0; - } /* We don't build a direct scan probe request; the uCode will do * that based on the direct_mask added to each channel entry */ @@ -6245,18 +6251,10 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; - if (direct_mask) - scan->channel_count = - iwl3945_get_channels_for_scan( - priv, band, 1, /* active */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); - else - scan->channel_count = - iwl3945_get_channels_for_scan( - priv, band, 0, /* passive */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + scan->channel_count = + iwl3945_get_channels_for_scan(priv, band, 1, /* active */ + n_probes, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl3945_scan_channel); -- cgit v1.2.3 From d10c4ec8b4bc02f3874c7ef3c3539e4e7e123969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefanik=20G=C3=A1bor?= Date: Wed, 3 Sep 2008 11:26:59 +0800 Subject: iwlwifi: enable packet injection for iwlagn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle station IDs of transmitted packets when in monitor mode, and remove the various anti-injection checks from the iwl4965 driver. This makes injection work on iwl4965 and iwl5000. Tested on both cards. Note: To inject management frames with encryption, HW crypto support must be disabled using the "swcrypto=1" modparam (or "swcrypto50=1" for iwl5000). Otherwise most management frames won't be transmitted. Signed-off-by: Gábor Stefanik Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ------ drivers/net/wireless/iwlwifi/iwl-sta.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-tx.c | 13 +++++-------- 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ab92e19f0b6..5cce894dc1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2722,12 +2722,6 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MACDUMP("enter\n"); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - IWL_DEBUG_MAC80211("leave - monitor\n"); - dev_kfree_skb_any(skb); - return 0; - } - IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 6283a3a707f..5b7b05c8773 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -968,6 +968,11 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; + /* If we are in monitor mode, use BCAST. This is required for + * packet injection. */ + case IEEE80211_IF_TYPE_MNTR: + return priv->hw_params.bcast_sta_id; + default: IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode); return priv->hw_params.bcast_sta_id; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a004cc8ab8f..452938c299a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -789,11 +789,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - if (!priv->vif) { - IWL_DEBUG_DROP("Dropping - !priv->vif\n"); - goto drop_unlock; - } - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); @@ -815,9 +810,11 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || - !priv->assoc_station_added)) { + (priv->iw_mode != IEEE80211_IF_TYPE_MNTR || + !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ + (!iwl_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || + !priv->assoc_station_added)) { IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); goto drop_unlock; } -- cgit v1.2.3 From 00c5ae2fa0f8191a1b204e71f0ee11359e3b2c06 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 3 Sep 2008 11:26:42 +0800 Subject: mac80211: change MIMO_PS to SM_PS This patch follows 11n spec naming more rigorously replacing MIMO_PS with SM_PS (Spatial Multiplexing Power Save). (Originally submitted as 4 patches, "mac80211: change MIMO_PS to SM_PS", "iwlwifi: change MIMO_PS to SM_PS", "ath9k: change MIMO_PS to SM_PS", and "iwlwifi: remove double definition of SM PS". -- JWL) Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 16 ++++++++-------- drivers/net/wireless/iwlwifi/iwl-dev.h | 5 ----- drivers/net/wireless/iwlwifi/iwl-sta.c | 8 ++++---- 6 files changed, 16 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 245b7308a9a..57d7cc87cb0 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -224,7 +224,7 @@ static void setup_ht_cap(struct ieee80211_ht_info *ht_info) ht_info->ht_supported = 1; ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH - |(u16)IEEE80211_HT_CAP_MIMO_PS + |(u16)IEEE80211_HT_CAP_SM_PS |(u16)IEEE80211_HT_CAP_SGI_40 |(u16)IEEE80211_HT_CAP_DSSSCCK40; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 98f2c843b99..4fc3a0f1d8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1153,8 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, !sta->ht_info.ht_supported) return -1; - if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2) - == IWL_MIMO_PS_STATIC) + if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + == WLAN_HT_CAP_SM_PS_STATIC) return -1; /* Need both Tx chains/antennas to support MIMO */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1547122e66f..27ddf6cb1c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -564,7 +564,7 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, if (!iwl_conf->is_ht) return; - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) iwl_conf->sgf |= HT_SHORT_GI_20MHZ; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a0b86af25c8..789556db684 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -399,8 +399,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, 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_MIMO_PS & - (IWL_MIMO_PS_NONE << 2)); + ht_info->cap |= (u16)(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)) { @@ -709,7 +709,7 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) + if (is_single || (!is_cam && (priv->ps_mode == WLAN_HT_CAP_SM_PS_STATIC))) return 2; else return 3; @@ -721,14 +721,14 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # Rx chains when idling and maybe trying to save power */ switch (priv->ps_mode) { - case IWL_MIMO_PS_STATIC: - case IWL_MIMO_PS_DYNAMIC: + case WLAN_HT_CAP_SM_PS_STATIC: + case WLAN_HT_CAP_SM_PS_DYNAMIC: idle_cnt = (is_cam) ? 2 : 1; break; - case IWL_MIMO_PS_NONE: + case WLAN_HT_CAP_SM_PS_DISABLED: idle_cnt = (is_cam) ? active_cnt : 1; break; - case IWL_MIMO_PS_INVALID: + case WLAN_HT_CAP_SM_PS_INVALID: default: IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode); WARN_ON(1); @@ -912,7 +912,7 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = IEEE80211_IF_TYPE_STA; priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->ps_mode = IWL_MIMO_PS_NONE; + priv->ps_mode = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 640ceea913c..f302e93b779 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -644,11 +644,6 @@ struct iwl_kw { #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 -#define IWL_MIMO_PS_STATIC 0 -#define IWL_MIMO_PS_NONE 3 -#define IWL_MIMO_PS_DYNAMIC 1 -#define IWL_MIMO_PS_INVALID 2 - #define IWL_OPERATION_MODE_AUTO 0 #define IWL_OPERATION_MODE_HT_ONLY 1 #define IWL_OPERATION_MODE_MIXED 2 diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 5b7b05c8773..a72569f1acb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -191,20 +191,20 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, if (!sta_ht_inf || !sta_ht_inf->ht_supported) goto done; - mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; + mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; sta_flags = priv->stations[index].sta.station_flags; sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); switch (mimo_ps_mode) { - case WLAN_HT_CAP_MIMO_PS_STATIC: + case WLAN_HT_CAP_SM_PS_STATIC: sta_flags |= STA_FLG_MIMO_DIS_MSK; break; - case WLAN_HT_CAP_MIMO_PS_DYNAMIC: + case WLAN_HT_CAP_SM_PS_DYNAMIC: sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; break; - case WLAN_HT_CAP_MIMO_PS_DISABLED: + case WLAN_HT_CAP_SM_PS_DISABLED: break; default: IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode); -- cgit v1.2.3 From 12837be1c127e6fba2e3f916a18fc202a9889af2 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 3 Sep 2008 11:26:47 +0800 Subject: iwlwifi: rename ps_mode to sm_ps This patch renames iwl_priv.ps_mode for clearer iwl_priv.current_ht_config.sm_ps (spatial multiplexing power save). Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-core.c | 10 ++++++---- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 27ddf6cb1c6..78902da3d51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -564,8 +564,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, if (!iwl_conf->is_ht) return; - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - 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) @@ -586,6 +584,8 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, 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); iwl_conf->control_channel = ht_bss_conf->primary_channel; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 789556db684..dbeaca15dda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -709,7 +709,8 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->ps_mode == WLAN_HT_CAP_SM_PS_STATIC))) + if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == + WLAN_HT_CAP_SM_PS_STATIC))) return 2; else return 3; @@ -720,7 +721,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) int idle_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); /* # Rx chains when idling and maybe trying to save power */ - switch (priv->ps_mode) { + switch (priv->current_ht_config.sm_ps) { case WLAN_HT_CAP_SM_PS_STATIC: case WLAN_HT_CAP_SM_PS_DYNAMIC: idle_cnt = (is_cam) ? 2 : 1; @@ -730,7 +731,8 @@ 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", priv->ps_mode); + IWL_ERROR("invalide mimo ps mode %d\n", + priv->current_ht_config.sm_ps); WARN_ON(1); idle_cnt = -1; break; @@ -912,7 +914,7 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = IEEE80211_IF_TYPE_STA; priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->ps_mode = WLAN_HT_CAP_SM_PS_DISABLED; + priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f302e93b779..7934f56f729 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -406,6 +406,7 @@ struct iwl_ht_info { /* self configuration data */ u8 is_ht; u8 supported_chan_width; + u8 sm_ps; u8 is_green_field; u8 sgf; /* HT_SHORT_GI_* short guard interval */ u8 max_amsdu_size; @@ -990,7 +991,6 @@ struct iwl_priv { * hardware */ u16 assoc_id; u16 assoc_capability; - u8 ps_mode; struct iwl_qos_info qos_data; -- cgit v1.2.3 From 04816448d8b77551834c9ea01e407ef5f0042f0f Mon Sep 17 00:00:00 2001 From: "Grumbach, Emmanuel" Date: Wed, 3 Sep 2008 11:26:53 +0800 Subject: iwlwifi: use the results from disconnected antenna algorithm This patch makes usage of the results from disconnected antenna alg to know how many antennas are connected. It also synchronizes between the chain noise alg and the W/A that disables power management during association. All the antennas must be enables during the chain noise algorithm. Hence, power management is restored only after the completion of the algorithm. In the future, we will need to update the AP that we don't support MIMO if there is only one antenna connected. We also need to update the rate scaling algorithm. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +++++- drivers/net/wireless/iwlwifi/iwl-calib.c | 15 ++++++++++---- drivers/net/wireless/iwlwifi/iwl-core.c | 35 +++++++++++++++++++++++++------- drivers/net/wireless/iwlwifi/iwl-dev.h | 10 +++++---- drivers/net/wireless/iwlwifi/iwl-power.c | 26 ++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-power.h | 2 +- 6 files changed, 64 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 78902da3d51..914a3ca5460 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2558,7 +2558,11 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl_activate_qos(priv, 0); spin_unlock_irqrestore(&priv->lock, flags); - iwl_power_enable_management(priv); + /* the chain noise calibration will enabled PM upon completion + * If chain noise has already been run, then we need to enable + * power management here */ + if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) + iwl_power_enable_management(priv); /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 35fb4a4f737..72fbf47229d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -808,13 +808,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, } } + /* Save for use within RXON, TX, SCAN commands, etc. */ + priv->chain_noise_data.active_chains = active_chains; IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", active_chains); - /* Save for use within RXON, TX, SCAN commands, etc. */ - /*priv->valid_antenna = active_chains;*/ - /*FIXME: should be reflected in RX chains in RXON */ - /* Analyze noise for rx balance */ average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); @@ -839,6 +837,15 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->utils->gain_computation(priv, average_noise, min_average_noise_antenna_i, min_average_noise); + + /* Some power changes may have been made during the calibration. + * Update and commit the RXON + */ + if (priv->cfg->ops->lib->update_chain_flags) + priv->cfg->ops->lib->update_chain_flags(priv); + + data->state = IWL_CHAIN_NOISE_DONE; + iwl_power_enable_management(priv); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index dbeaca15dda..46683eacfdc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -740,6 +740,17 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) return idle_cnt; } +/* up to 4 chains */ +static u8 iwl_count_chain_bitmap(u32 chain_bitmap) +{ + u8 res; + res = (chain_bitmap & BIT(0)) >> 0; + res += (chain_bitmap & BIT(1)) >> 1; + res += (chain_bitmap & BIT(2)) >> 2; + res += (chain_bitmap & BIT(4)) >> 4; + return res; +} + /** * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image * @@ -750,25 +761,35 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) { bool is_single = is_single_rx_stream(priv); bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - u8 idle_rx_cnt, active_rx_cnt; + u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; + u32 active_chains; u16 rx_chain; /* Tell uCode which antennas are actually connected. * Before first association, we assume all antennas are connected. * Just after first association, iwl_chain_noise_calibration() * checks which antennas actually *are* connected. */ - rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; + if (priv->chain_noise_data.active_chains) + active_chains = priv->chain_noise_data.active_chains; + else + active_chains = priv->hw_params.valid_rx_ant; + + rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; /* How many receivers should we use? */ active_rx_cnt = iwl_get_active_rx_chain_count(priv); idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); - /* correct rx chain count accoridng hw settings */ - if (priv->hw_params.rx_chains_num < active_rx_cnt) - active_rx_cnt = priv->hw_params.rx_chains_num; - if (priv->hw_params.rx_chains_num < idle_rx_cnt) - idle_rx_cnt = priv->hw_params.rx_chains_num; + /* correct rx chain count according hw settings + * and chain noise calibration + */ + valid_rx_cnt = iwl_count_chain_bitmap(active_chains); + if (valid_rx_cnt < active_rx_cnt) + active_rx_cnt = valid_rx_cnt; + + if (valid_rx_cnt < idle_rx_cnt) + idle_rx_cnt = valid_rx_cnt; rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7934f56f729..6e150f678c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -699,8 +699,9 @@ enum iwl4965_false_alarm_state { enum iwl4965_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ - IWL_CHAIN_NOISE_ACCUMULATE = 1, - IWL_CHAIN_NOISE_CALIBRATED = 2, + IWL_CHAIN_NOISE_ACCUMULATE, + IWL_CHAIN_NOISE_CALIBRATED, + IWL_CHAIN_NOISE_DONE, }; enum iwl4965_calib_enabled_state { @@ -758,17 +759,18 @@ struct iwl_sensitivity_data { /* Chain noise (differential Rx gain) calib data */ struct iwl_chain_noise_data { - u8 state; - u16 beacon_count; + u32 active_chains; u32 chain_noise_a; u32 chain_noise_b; u32 chain_noise_c; u32 chain_signal_a; u32 chain_signal_b; u32 chain_signal_c; + u16 beacon_count; u8 disconn_array[NUM_RX_CHAINS]; u8 delta_gain_code[NUM_RX_CHAINS]; u8 radio_write; + u8 state; }; #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 16f834d0c48..bd6f600027d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -252,12 +252,21 @@ static int iwl_update_power_command(struct iwl_priv *priv, /* * calucaute the final power mode index */ -int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) +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); + /* 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; + } + /* If on battery, set to 3, * if plugged into AC power, set to CAM ("continuously aware mode"), * else user level */ @@ -285,7 +294,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) final_mode = IWL_POWER_MODE_CAM; if (!iwl_is_rfkill(priv) && !setting->power_disabled && - ((setting->power_mode != final_mode) || refresh)) { + ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; if (final_mode != IWL_POWER_MODE_CAM) @@ -359,35 +368,26 @@ EXPORT_SYMBOL(iwl_power_enable_management); /* set user_power_setting */ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) { - int ret = 0; - if (mode > IWL_POWER_LIMIT) return -EINVAL; priv->power_data.user_power_setting = mode; - ret = iwl_power_update_mode(priv, 0); - - return ret; + return iwl_power_update_mode(priv, 0); } EXPORT_SYMBOL(iwl_power_set_user_mode); - /* set system_power_setting. This should be set by over all * PM application. */ int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) { - int ret = 0; - if (mode > IWL_POWER_LIMIT) return -EINVAL; priv->power_data.system_power_setting = mode; - ret = iwl_power_update_mode(priv, 0); - - return ret; + return iwl_power_update_mode(priv, 0); } EXPORT_SYMBOL(iwl_power_set_system_mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index aa99f3647de..a5c334f10e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -80,7 +80,7 @@ struct iwl_power_mgr { void iwl_setup_power_deferred_work(struct iwl_priv *priv); void iwl_power_cancel_timeout(struct iwl_priv *priv); -int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); +int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); int iwl_power_enable_management(struct iwl_priv *priv); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); -- cgit v1.2.3 From a33c2f47bd4618b0483d5ec4c5bc793e6d02c1f7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 3 Sep 2008 11:26:56 +0800 Subject: iwlwifi: remove uneeded declarations This patch cleans up iwlwifi by removing uneeded declarations and removing uneeded symbol export reducing the namespace pollution. It also fixes some typos in comments. Signed-off-by: Emmanuel Grumbach Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 9 +++---- drivers/net/wireless/iwlwifi/iwl-core.h | 10 +------ drivers/net/wireless/iwlwifi/iwl-dev.h | 45 +++++++++----------------------- drivers/net/wireless/iwlwifi/iwl-power.c | 8 +++--- drivers/net/wireless/iwlwifi/iwl-power.h | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-tx.c | 9 +++---- 9 files changed, 28 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d9c4fdbf7f7..d2569a271d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1607,8 +1607,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) return ret; } - -int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) +static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 914a3ca5460..31ea2885889 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -485,7 +485,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) return IWL_RATE_6M_PLCP; } -unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, +static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 46683eacfdc..36d08b0eec4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -801,7 +801,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) else priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; - IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n", + IWL_DEBUG_ASSOC("rx_chain=0x%X active=%d idle=%d\n", priv->staging_rxon.rx_chain, active_rx_cnt, idle_rx_cnt); @@ -1158,7 +1158,6 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); - static const char *desc_lookup(int i) { switch (i) { @@ -1239,9 +1238,9 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log); /** * iwl_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! + * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ -void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) { u32 i; @@ -1282,8 +1281,6 @@ void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, } } } -EXPORT_SYMBOL(iwl_print_event_log); - void iwl_dump_nic_event_log(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b5db050b22d..55a4b584ce0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -184,7 +184,6 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); void iwl_hw_detect(struct iwl_priv *priv); - void iwl_clear_stations_table(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); @@ -215,7 +214,6 @@ 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); -/* FIXME: remove when TX is moved to iwl core */ 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); @@ -234,11 +232,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, ******************************************************/ int iwl_txq_ctx_reset(struct iwl_priv *priv); int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); -/* FIXME: remove when free Tx is fully merged into iwlcore */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); void iwl_hw_txq_ctx_free(struct iwl_priv *priv); -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); 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); @@ -253,6 +247,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); * RF -Kill - here and not in iwl-rfkill.h to be available when * RF-kill subsystem is not compiled. ****************************************************/ +void iwl_rf_kill(struct iwl_priv *priv); void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); @@ -283,7 +278,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); -const char *iwl_escape_essid(const char *essid, u8 essid_len); int iwl_scan_initiate(struct iwl_priv *priv); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); @@ -316,8 +310,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /***************************************************** * Error Handling Debugging ******************************************************/ -void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode); void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6e150f678c6..1823687e582 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -565,50 +565,31 @@ struct iwl_hw_params { #define IWL_RX_STATS(x) (&x->u.rx_frame.stats) #define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) - -/****************************************************************************** - * - * Functions implemented in iwl-base.c which are forward declared here - * for use by iwl-*.c - * - *****************************************************************************/ -struct iwl_addsta_cmd; -extern int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_ht_info *ht_info); -extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); -extern void iwl4965_update_chain_flags(struct iwl_priv *priv); -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); -extern int iwl4965_set_power(struct iwl_priv *priv, void *cmd); - -extern const u8 iwl_bcast_addr[ETH_ALEN]; - /****************************************************************************** * - * Functions implemented in iwl-[34]*.c which are forward declared here - * for use by iwl-base.c + * Functions implemented in core module which are forward declared here + * for use by iwl-[4-5].c * - * NOTE: The implementation of these functions are hardware specific - * which is why they are in the hardware specific files (vs. iwl-base.c) + * NOTE: The implementation of these functions are not hardware specific + * which is why they are in the core module files. * * Naming convention -- - * iwl4965_ <-- Its part of iwlwifi (should be changed to iwl4965_) - * iwl4965_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * iwl_ <-- Is part of iwlwifi * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) * iwl4965_bg_ <-- Called from work queue context * 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 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); -extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate); -extern void iwl4965_disable_events(struct iwl_priv *priv); - -extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl_queue_space(const struct iwl_queue *q); static inline int iwl_queue_used(const struct iwl_queue *q, int i) { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index bd6f600027d..55ec31ec9e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -250,7 +250,7 @@ static int iwl_update_power_command(struct iwl_priv *priv, /* - * calucaute the final power mode index + * compute the final power mode index */ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { @@ -267,9 +267,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) return -EAGAIN; } - /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuously aware mode"), - * else user level */ + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuously aware mode"), + * else user level */ switch (setting->system_power_setting) { case IWL_POWER_SYS_AUTO: diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index a5c334f10e5..df484a90ae6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -72,7 +72,7 @@ struct iwl_power_mgr { /* final power level that used to calculate final power command */ u8 power_mode; u8 user_power_setting; /* set by user through mac80211 or sysfs */ - u8 system_power_setting; /* set by kernel syatem tools */ + u8 system_power_setting; /* set by kernel system tools */ u8 critical_power_setting; /* set if driver over heated */ u8 is_battery_active; /* DC/AC power */ u8 power_disabled; /* flag to disable using power saving level */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 6c8ac3a87d5..d026aaf6233 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -88,7 +88,7 @@ static int iwl_is_empty_essid(const char *essid, int essid_len) -const char *iwl_escape_essid(const char *essid, u8 essid_len) +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; @@ -111,7 +111,6 @@ const char *iwl_escape_essid(const char *essid, u8 essid_len) *d = '\0'; return escaped; } -EXPORT_SYMBOL(iwl_escape_essid); /** * iwl_scan_cancel - Cancel any currently executing HW scan diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9d485aadef9..9d5bcf46cbe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -63,7 +63,7 @@ static const u16 default_tid_to_tx_fifo[] = { * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +static int 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]; @@ -115,10 +115,8 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) } return 0; } -EXPORT_SYMBOL(iwl_hw_txq_free_tfd); - -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, +static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, dma_addr_t addr, u16 len) { int index, is_odd; @@ -151,7 +149,6 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, return 0; } -EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd); /** * iwl_txq_update_write_ptr - Send new write index to hardware @@ -478,7 +475,6 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); - /** * iwl_txq_ctx_reset - Reset TX queue context * Destroys all DMA structures and initialise them again @@ -545,6 +541,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error_kw: return ret; } + /** * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory */ -- cgit v1.2.3 From 3c9355222cc521ca2e8c355a9b05e773900c5dc0 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 3 Sep 2008 11:26:57 +0800 Subject: iwlwifi: fix compile warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch fixes compile warning for ‘iwl4965_hw_channel_switch’ defined but not used. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d2569a271d6..9838de5f436 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1607,6 +1607,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) return ret; } +#ifdef IEEE80211_CONF_CHANNEL_SWITCH static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; @@ -1647,6 +1648,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } +#endif static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) { -- cgit v1.2.3 From a0db663ff192e21ebb703f962308675f22fb38a8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Sep 2008 02:56:04 +0200 Subject: p54: 32-bit tsf timestamps tcpdump: 02:15:42.874518 61112184us tsft 48.0 Mb/s 2437 MHz (0x0480) antenna 1 [0x0000000e] CF +QoS Data IV 02:15:42.874557 >>>4356079526us<<< tsft 24.0 Mb/s 2437 MHz (0x0480) antenna 1 [0x0000000e] Acknowledgment 02:15:42.976844 61214513us tsft 1.0 Mb/s 2437 MHz (0x0480) antenna 0 [0x0000000e] Beacon as one can see on the huge jump, it's very plausible that firmware does not report the full 64-bit mac time, just the lower 32bit and some kinds of flags... Therefore if we want a useful timestamp we have to emulate the high bits. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 2 ++ drivers/net/wireless/p54/p54common.c | 11 ++++++++++- drivers/net/wireless/p54/p54common.h | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 98d4f8e7d84..36b8e584c6c 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -87,6 +87,8 @@ struct p54_common { void *cached_vdcf; unsigned int fw_var; unsigned int fw_interface; + u32 tsf_low32; + u32 tsf_high32; struct ieee80211_tx_queue_stats tx_stats[8]; void *eeprom; struct completion eeprom_comp; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index f96f7c7e6af..526d3a282b7 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -426,10 +426,12 @@ EXPORT_SYMBOL_GPL(p54_parse_eeprom); 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 ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); + u32 tsf32; rx_status.signal = hdr->rssi; /* XX correct? */ @@ -438,7 +440,13 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.freq = freq; rx_status.band = IEEE80211_BAND_2GHZ; rx_status.antenna = hdr->antenna; - rx_status.mactime = le64_to_cpu(hdr->timestamp); + + tsf32 = le32_to_cpu(hdr->tsf32); + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32; + priv->tsf_low32 = tsf32; + rx_status.flag |= RX_FLAG_TSFT; if (hdr->magic & cpu_to_le16(0x4000)) @@ -1037,6 +1045,7 @@ static void p54_stop(struct ieee80211_hw *dev) while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); priv->stop(dev); + priv->tsf_high32 = priv->tsf_low32 = 0; priv->mode = IEEE80211_IF_TYPE_INVALID; } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 73a9a2c923d..976cbf9689b 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -185,7 +185,8 @@ struct p54_rx_hdr { u8 rssi; u8 quality; u16 unknown2; - __le64 timestamp; + __le32 tsf32; + __le32 unalloc0; u8 align[0]; } __attribute__ ((packed)); -- cgit v1.2.3 From 78d57eb2b666617dd75aac0f1a420238004a98b3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Sep 2008 02:56:12 +0200 Subject: p54: add more rx filters This patch adds new filters settings to make the card more useful in monitor mode. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 36b8e584c6c..ea72b65428e 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -80,6 +80,7 @@ struct p54_common { struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; + unsigned int filter_flags; u16 rxhw; u8 version; u8 rx_antenna; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 526d3a282b7..300f97b1bfe 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -433,6 +433,13 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) size_t header_len = sizeof(*hdr); u32 tsf32; + if (!(hdr->magic & cpu_to_le16(0x0001))) { + if (priv->filter_flags & FIF_FCSFAIL) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + else + return 0; + } + rx_status.signal = hdr->rssi; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; @@ -1127,13 +1134,26 @@ static void p54_configure_filter(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - *total_flags &= FIF_BCN_PRBRESP_PROMISC; + *total_flags &= FIF_BCN_PRBRESP_PROMISC | + FIF_PROMISC_IN_BSS | + FIF_FCSFAIL; + + priv->filter_flags = *total_flags; if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, 0, NULL); + p54_set_filter(dev, priv->filter_type, NULL); + else + p54_set_filter(dev, priv->filter_type, priv->bssid); + } + + if (changed_flags & FIF_PROMISC_IN_BSS) { + if (*total_flags & FIF_PROMISC_IN_BSS) + p54_set_filter(dev, priv->filter_type | + cpu_to_le16(0x8), NULL); else - p54_set_filter(dev, 0, priv->bssid); + p54_set_filter(dev, priv->filter_type & + ~cpu_to_le16(0x8), priv->bssid); } } -- cgit v1.2.3 From cc6de669f648bc8820f1cf93ee311eb4eaab9fc5 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Sep 2008 02:56:23 +0200 Subject: p54: add lots of useful rx/tx statistics The firmware can provide lots of useful statistics about noise floor, mac time and lots of numbers about successful transfers and dropped frames. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 5 ++ drivers/net/wireless/p54/p54common.c | 92 ++++++++++++++++++++++++++++++++++-- drivers/net/wireless/p54/p54common.h | 13 +++++ 3 files changed, 105 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ea72b65428e..370202f6de2 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -91,6 +91,11 @@ struct p54_common { u32 tsf_low32; u32 tsf_high32; struct ieee80211_tx_queue_stats tx_stats[8]; + struct ieee80211_low_level_stats stats; + struct timer_list stats_timer; + struct completion stats_comp; + void *cached_stats; + int noise; void *eeprom; struct completion eeprom_comp; }; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 300f97b1bfe..670d7ad4120 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -424,6 +424,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) } EXPORT_SYMBOL_GPL(p54_parse_eeprom); +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; +} + static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; @@ -440,7 +446,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) return 0; } - rx_status.signal = hdr->rssi; + rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); + rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; rx_status.rate_idx = hdr->rate & 0xf; @@ -526,7 +533,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) info->status.excessive_retries = 1; } info->status.retry_count = payload->retries - 1; - info->status.ack_signal = le16_to_cpu(payload->ack_rssi); + 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; @@ -557,6 +565,27 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, complete(&priv->eeprom_comp); } +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_statistics *stats = (struct p54_statistics *) hdr->data; + u32 tsf32 = le32_to_cpu(stats->tsf32); + + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + priv->tsf_low32 = tsf32; + + priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); + priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); + 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); +} + static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; @@ -567,6 +596,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) break; case P54_CONTROL_TYPE_BBP: break; + case P54_CONTROL_TYPE_STAT_READBACK: + p54_rx_stats(dev, skb); + break; case P54_CONTROL_TYPE_EEPROM_READBACK: p54_rx_eeprom_readback(dev, skb); break; @@ -1036,12 +1068,25 @@ static int p54_start(struct ieee80211_hw *dev) return -ENOMEM; } + if (!priv->cached_stats) { + priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + + priv->tx_hdr_len + sizeof(struct p54_control_hdr), + GFP_KERNEL); + + if (!priv->cached_stats) { + kfree(priv->cached_vdcf); + priv->cached_vdcf = NULL; + return -ENOMEM; + } + } + err = priv->open(dev); if (!err) priv->mode = IEEE80211_IF_TYPE_MNTR; p54_init_vdcf(dev); + mod_timer(&priv->stats_timer, jiffies + HZ); return err; } @@ -1049,6 +1094,8 @@ static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct sk_buff *skb; + + del_timer(&priv->stats_timer); while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); priv->stop(dev); @@ -1177,10 +1224,40 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } +static void p54_statistics_timer(unsigned long data) +{ + struct ieee80211_hw *dev = (struct ieee80211_hw *) data; + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_statistics *stats; + + BUG_ON(!priv->cached_stats); + + hdr = (void *)priv->cached_stats + priv->tx_hdr_len; + 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)); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); +} + static int p54_get_stats(struct ieee80211_hw *dev, struct ieee80211_low_level_stats *stats) { - /* TODO */ + 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; } @@ -1222,12 +1299,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_queue); dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); dev->channel_change_time = 1000; /* TODO: find actual value */ - dev->max_signal = 127; priv->tx_stats[0].limit = 1; priv->tx_stats[1].limit = 1; @@ -1235,11 +1312,15 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv->tx_stats[3].limit = 1; priv->tx_stats[4].limit = 5; dev->queues = 1; + priv->noise = -94; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + sizeof(struct p54_tx_control_allocdata); 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); return dev; } @@ -1248,6 +1329,7 @@ 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); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 976cbf9689b..9e544ce59c3 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -301,4 +301,17 @@ struct p54_tx_control_vdcf { __le16 frameburst; } __attribute__ ((packed)); +struct p54_statistics { + __le32 rx_success; + __le32 rx_bad_fcs; + __le32 rx_abort; + __le32 rx_abort_phy; + __le32 rts_success; + __le32 rts_fail; + __le32 tsf32; + __le32 airtime; + __le32 noise; + __le32 unkn[10]; /* CCE / CCA / RADAR */ +} __attribute__ ((packed)); + #endif /* P54COMMON_H */ -- cgit v1.2.3 From 09adf284039f896401df8ea219ee1d13e80333a8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Sep 2008 14:25:53 +0200 Subject: p54: control output power levels I hope this patch is enough to cover at least the basic requirements of IEEE 802.11h's TPC. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 370202f6de2..1d0704fe146 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -88,6 +88,7 @@ struct p54_common { void *cached_vdcf; unsigned int fw_var; unsigned int fw_interface; + unsigned int output_power; u32 tsf_low32; u32 tsf_high32; struct ieee80211_tx_queue_stats tx_stats[8]; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 670d7ad4120..7ec695ca9ea 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -800,7 +800,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; - txhdr->output_power = 0x7f; // HW Maximum + txhdr->output_power = priv->output_power; txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cts_rate; if (padding) @@ -1154,6 +1154,7 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *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); mutex_unlock(&priv->conf_mutex); -- cgit v1.2.3 From 1b9975347e852c22a7c4c67b68814403ef16d2bd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Sep 2008 14:25:58 +0200 Subject: p54: 802.11a 5GHz phy support This patch brings the 5GHz Phy in any prism54 devices (of course, only those who have one) to life. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 124 +++++++++++++++++++++++++++++------ drivers/net/wireless/p54/p54common.h | 7 ++ 2 files changed, 111 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 7ec695ca9ea..da51786254d 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54common"); -static struct ieee80211_rate p54_rates[] = { +static struct ieee80211_rate p54_bgrates[] = { { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, @@ -42,7 +42,7 @@ static struct ieee80211_rate p54_rates[] = { { .bitrate = 540, .hw_value = 11, }, }; -static struct ieee80211_channel p54_channels[] = { +static struct ieee80211_channel p54_bgchannels[] = { { .center_freq = 2412, .hw_value = 1, }, { .center_freq = 2417, .hw_value = 2, }, { .center_freq = 2422, .hw_value = 3, }, @@ -60,10 +60,66 @@ static struct ieee80211_channel p54_channels[] = { }; static struct ieee80211_supported_band band_2GHz = { - .channels = p54_channels, - .n_channels = ARRAY_SIZE(p54_channels), - .bitrates = p54_rates, - .n_bitrates = ARRAY_SIZE(p54_rates), + .channels = p54_bgchannels, + .n_channels = ARRAY_SIZE(p54_bgchannels), + .bitrates = p54_bgrates, + .n_bitrates = ARRAY_SIZE(p54_bgrates), +}; + +static struct ieee80211_rate p54_arates[] = { + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_achannels[] = { + { .center_freq = 4920 }, + { .center_freq = 4940 }, + { .center_freq = 4960 }, + { .center_freq = 4980 }, + { .center_freq = 5040 }, + { .center_freq = 5060 }, + { .center_freq = 5080 }, + { .center_freq = 5170 }, + { .center_freq = 5180 }, + { .center_freq = 5190 }, + { .center_freq = 5200 }, + { .center_freq = 5210 }, + { .center_freq = 5220 }, + { .center_freq = 5230 }, + { .center_freq = 5240 }, + { .center_freq = 5260 }, + { .center_freq = 5280 }, + { .center_freq = 5300 }, + { .center_freq = 5320 }, + { .center_freq = 5500 }, + { .center_freq = 5520 }, + { .center_freq = 5540 }, + { .center_freq = 5560 }, + { .center_freq = 5580 }, + { .center_freq = 5600 }, + { .center_freq = 5620 }, + { .center_freq = 5640 }, + { .center_freq = 5660 }, + { .center_freq = 5680 }, + { .center_freq = 5700 }, + { .center_freq = 5745 }, + { .center_freq = 5765 }, + { .center_freq = 5785 }, + { .center_freq = 5805 }, + { .center_freq = 5825 }, +}; + +static struct ieee80211_supported_band band_5GHz = { + .channels = p54_achannels, + .n_channels = ARRAY_SIZE(p54_achannels), + .bitrates = p54_arates, + .n_bitrates = ARRAY_SIZE(p54_arates), }; int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) @@ -252,6 +308,7 @@ static int p54_convert_rev1(struct ieee80211_hw *dev, const char* p54_rf_chips[] = { "NULL", "Indigo?", "Duette", "Frisbee", "Xbow", "Longbow" }; +static int p54_init_xbow_synth(struct ieee80211_hw *dev); int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { @@ -371,20 +428,20 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) } switch (priv->rxhw) { - case 4: /* XBow */ - case 1: /* Indigo? */ - case 2: /* Duette */ - /* TODO: 5GHz initialization goes here */ - - case 3: /* Frisbee */ - case 5: /* Longbow */ - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - break; - default: - printk(KERN_ERR "%s: unsupported RF-Chip\n", - wiphy_name(dev->wiphy)); - err = -EINVAL; - goto err; + case 4: /* XBow */ + p54_init_xbow_synth(dev); + case 1: /* Indigo? */ + case 2: /* Duette */ + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; + case 3: /* Frisbee */ + case 5: /* Longbow */ + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + break; + default: + printk(KERN_ERR "%s: unsupported RF-Chip\n", + wiphy_name(dev->wiphy)); + err = -EINVAL; + goto err; } if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { @@ -1225,6 +1282,33 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } +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; + + hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + 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->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); + + return 0; +} + static void p54_statistics_timer(unsigned long data) { struct ieee80211_hw *dev = (struct ieee80211_hw *) data; diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 9e544ce59c3..4da736c789a 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -314,4 +314,11 @@ struct p54_statistics { __le32 unkn[10]; /* CCE / CCA / RADAR */ } __attribute__ ((packed)); +struct p54_tx_control_xbow_synth { + __le16 magic1; + __le16 magic2; + __le16 freq; + u32 padding[5]; +} __attribute__ ((packed)); + #endif /* P54COMMON_H */ -- cgit v1.2.3 From c40c1129106ab20c90b0f1516e79d7b5e7e29904 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 6 Sep 2008 16:21:47 +0200 Subject: b43: Fix QoS defaults This fixes the initialization of the default QoS parameters. This got broken by "wireless: fix warnings from QoS patch". Reported-by: Lorenzo Nava Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 56 +++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c836beceb10..79c25d6385c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3059,6 +3059,15 @@ static void b43_qos_params_upload(struct b43_wldev *dev, } } +/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */ +static const u16 b43_qos_shm_offsets[] = { + /* [mac80211-queue-nr] = SHM_OFFSET, */ + [0] = B43_QOS_VOICE, + [1] = B43_QOS_VIDEO, + [2] = B43_QOS_BESTEFFORT, + [3] = B43_QOS_BACKGROUND, +}; + /* Update the QOS parameters in hardware. */ static void b43_qos_update(struct b43_wldev *dev) { @@ -3067,14 +3076,8 @@ static void b43_qos_update(struct b43_wldev *dev) unsigned long flags; unsigned int i; - /* Mapping of mac80211 queues to b43 SHM offsets. */ - static const u16 qos_shm_offsets[] = { - [0] = B43_QOS_VOICE, - [1] = B43_QOS_VIDEO, - [2] = B43_QOS_BESTEFFORT, - [3] = B43_QOS_BACKGROUND, - }; - BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != + ARRAY_SIZE(wl->qos_params)); b43_mac_suspend(dev); spin_lock_irqsave(&wl->irq_lock, flags); @@ -3083,7 +3086,7 @@ static void b43_qos_update(struct b43_wldev *dev) params = &(wl->qos_params[i]); if (params->need_hw_update) { b43_qos_params_upload(dev, &(params->p), - qos_shm_offsets[i]); + b43_qos_shm_offsets[i]); params->need_hw_update = 0; } } @@ -3097,11 +3100,42 @@ static void b43_qos_clear(struct b43_wl *wl) struct b43_qos_params *params; unsigned int i; + /* Initialize QoS parameters to sane defaults. */ + + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != + ARRAY_SIZE(wl->qos_params)); + for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { params = &(wl->qos_params[i]); - memset(&(params->p), 0, sizeof(params->p)); - params->p.aifs = -1; + switch (b43_qos_shm_offsets[i]) { + case B43_QOS_VOICE: + params->p.txop = 0; + params->p.aifs = 2; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x0001; + break; + case B43_QOS_VIDEO: + params->p.txop = 0; + params->p.aifs = 2; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x0001; + break; + case B43_QOS_BESTEFFORT: + params->p.txop = 0; + params->p.aifs = 3; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x03FF; + break; + case B43_QOS_BACKGROUND: + params->p.txop = 0; + params->p.aifs = 7; + params->p.cw_min = 0x0001; + params->p.cw_max = 0x03FF; + break; + default: + B43_WARN_ON(1); + } params->need_hw_update = 1; } } -- cgit v1.2.3 From b338994dc2d0f8f1316ca12455fec3e5b0d44d3e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 6 Sep 2008 19:28:55 +0200 Subject: b43 G-PHY: Remove mmiowb() It causes compile errors on m68k and it is not needed. Remove it. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_g.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e8c012c9abb..232181f6333 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -386,7 +386,6 @@ static void b43_set_original_gains(struct b43_wldev *dev) void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); - mmiowb(); b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); } -- cgit v1.2.3 From 5a5f3b406a167cb5befa2110c6d9943898070aaf Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 6 Sep 2008 20:07:31 +0200 Subject: b43: Remove QoS update workqueue We don't need the workqueue anymore, as we can now sleep in the callback. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 7 +---- drivers/net/wireless/b43/main.c | 65 +++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f9c8161671d..07d2825458a 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -585,8 +585,6 @@ enum { struct b43_qos_params { /* The QOS parameters */ struct ieee80211_tx_queue_params p; - /* Does this need to get uploaded to hardware? */ - bool need_hw_update; }; struct b43_wldev; @@ -648,11 +646,8 @@ struct b43_wl { bool beacon_templates_virgin; /* Never wrote the templates? */ struct work_struct beacon_update_trigger; - /* The current QOS parameters for the 4 queues. - * This is protected by the irq_lock. */ + /* The current QOS parameters for the 4 queues. */ struct b43_qos_params qos_params[4]; - /* Workqueue for updating QOS parameters in hardware. */ - struct work_struct qos_update_work; /* Work for adjustment of the transmission power. * This is scheduled when we determine that the actual TX output diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 79c25d6385c..d4a356b1163 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3068,30 +3068,22 @@ static const u16 b43_qos_shm_offsets[] = { [3] = B43_QOS_BACKGROUND, }; -/* Update the QOS parameters in hardware. */ -static void b43_qos_update(struct b43_wldev *dev) +/* Update all QOS parameters in hardware. */ +static void b43_qos_upload_all(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; struct b43_qos_params *params; - unsigned long flags; unsigned int i; BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); b43_mac_suspend(dev); - spin_lock_irqsave(&wl->irq_lock, flags); - for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { params = &(wl->qos_params[i]); - if (params->need_hw_update) { - b43_qos_params_upload(dev, &(params->p), - b43_qos_shm_offsets[i]); - params->need_hw_update = 0; - } + b43_qos_params_upload(dev, &(params->p), + b43_qos_shm_offsets[i]); } - - spin_unlock_irqrestore(&wl->irq_lock, flags); b43_mac_enable(dev); } @@ -3136,20 +3128,14 @@ static void b43_qos_clear(struct b43_wl *wl) default: B43_WARN_ON(1); } - params->need_hw_update = 1; } } /* Initialize the core's QOS capabilities */ static void b43_qos_init(struct b43_wldev *dev) { - struct b43_wl *wl = dev->wl; - unsigned int i; - /* Upload the current QOS parameters. */ - for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) - wl->qos_params[i].need_hw_update = 1; - b43_qos_update(dev); + b43_qos_upload_all(dev); /* Enable QOS support. */ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); @@ -3158,25 +3144,13 @@ static void b43_qos_init(struct b43_wldev *dev) | B43_MMIO_IFSCTL_USE_EDCF); } -static void b43_qos_update_work(struct work_struct *work) -{ - struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); - struct b43_wldev *dev; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) - b43_qos_update(dev); - mutex_unlock(&wl->mutex); -} - static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; + struct b43_wldev *dev; unsigned int queue = (unsigned int)_queue; - struct b43_qos_params *p; + int err = -ENODEV; if (queue >= ARRAY_SIZE(wl->qos_params)) { /* Queue not available or don't support setting @@ -3184,16 +3158,25 @@ static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, * confuse mac80211. */ return 0; } + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != + ARRAY_SIZE(wl->qos_params)); - spin_lock_irqsave(&wl->irq_lock, flags); - p = &(wl->qos_params[queue]); - memcpy(&(p->p), params, sizeof(p->p)); - p->need_hw_update = 1; - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) + goto out_unlock; - queue_work(hw->workqueue, &wl->qos_update_work); + memcpy(&(wl->qos_params[queue].p), params, sizeof(*params)); + b43_mac_suspend(dev); + b43_qos_params_upload(dev, &(wl->qos_params[queue].p), + b43_qos_shm_offsets[queue]); + b43_mac_enable(dev); + err = 0; - return 0; +out_unlock: + mutex_unlock(&wl->mutex); + + return err; } static int b43_op_get_tx_stats(struct ieee80211_hw *hw, @@ -4220,7 +4203,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; b43_rfkill_exit(dev); - cancel_work_sync(&(wl->qos_update_work)); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -4619,7 +4601,6 @@ static int b43_wireless_init(struct ssb_device *dev) spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); - INIT_WORK(&wl->qos_update_work, b43_qos_update_work); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); -- cgit v1.2.3 From c6a2afdacccd56cc0be8e9a7977f0ed1509069f6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 6 Sep 2008 16:51:22 -0500 Subject: b43legacy: Fix failure in rate-adjustment mechanism A coding error present since b43legacy was incorporated into the kernel has prevented the driver from using the rate-setting mechanism of mac80211. The driver has been forced to remain at a 1 Mb/s rate. Signed-off-by: Larry Finger Cc: Stable [2.6.26], [2.6.25] Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index c5ca72aa59e..6835064758f 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -624,7 +624,7 @@ void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, tmp = hw->count; status.frame_count = (tmp >> 4); status.rts_count = (tmp & 0x0F); - tmp = hw->flags; + tmp = hw->flags << 1; status.supp_reason = ((tmp & 0x1C) >> 2); status.pm_indicated = !!(tmp & 0x80); status.intermediate = !!(tmp & 0x40); -- cgit v1.2.3 From 940b7a3a6c257391bda0950448591dd79efebf59 Mon Sep 17 00:00:00 2001 From: Ehud Gavron Date: Sat, 6 Sep 2008 21:30:00 -0700 Subject: b43legacy: Fix to enhance TX speed Recent changes in the specifications have improved the performance of the BCM4306/2 devices that use b43legacy as the driver. These "errors" in the specs have been present from the very first implementation of bcm43xx. Signed-off-by: Ehud Gavron Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/phy.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 768cccb9b1b..bed67a54250 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -595,12 +595,14 @@ static void b43legacy_phy_initb5(struct b43legacy_wldev *dev) 0x0035) & 0xFFC0) | 0x0064); b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + b43legacy_phy_write(dev, 0x5B, 0x0000); + b43legacy_phy_write(dev, 0x5C, 0x0000); } if (dev->bad_frames_preempt) b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, b43legacy_phy_read(dev, - B43legacy_PHY_RADIO_BITFIELD) | (1 << 11)); + B43legacy_PHY_RADIO_BITFIELD) | (1 << 12)); if (phy->analog == 1) { b43legacy_phy_write(dev, 0x0026, 0xCE00); @@ -753,7 +755,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_radio_write16(dev, 0x0050, 0x0020); } if (phy->radio_rev <= 2) { - b43legacy_radio_write16(dev, 0x007C, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0020); b43legacy_radio_write16(dev, 0x005A, 0x0070); b43legacy_radio_write16(dev, 0x005B, 0x007B); b43legacy_radio_write16(dev, 0x005C, 0x00B0); @@ -771,7 +773,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x002A, 0x8AC0); b43legacy_phy_write(dev, 0x0038, 0x0668); b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); - if (phy->radio_rev <= 5) + if (phy->radio_rev == 4 || phy->radio_rev == 5) b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, 0x005D) & 0xFF80) | 0x0003); if (phy->radio_rev <= 2) @@ -1010,7 +1012,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_initb5(dev); else b43legacy_phy_initb6(dev); - if (phy->rev >= 2 || phy->gmode) + if (phy->rev >= 2 && phy->gmode) b43legacy_phy_inita(dev); if (phy->rev >= 2) { @@ -1025,18 +1027,22 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0811, 0x0400); b43legacy_phy_write(dev, 0x0015, 0x00C0); } - if (phy->rev >= 2 || phy->gmode) { + if (phy->gmode) { tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; - if (tmp == 3 || tmp == 5) { + if (tmp == 3) { + b43legacy_phy_write(dev, 0x04C2, 0x1816); + b43legacy_phy_write(dev, 0x04C3, 0x8606); + } + if (tmp == 4 || tmp == 5) { b43legacy_phy_write(dev, 0x04C2, 0x1816); b43legacy_phy_write(dev, 0x04C3, 0x8006); - if (tmp == 5) - b43legacy_phy_write(dev, 0x04CC, - (b43legacy_phy_read(dev, - 0x04CC) & 0x00FF) | - 0x1F00); + b43legacy_phy_write(dev, 0x04CC, + (b43legacy_phy_read(dev, + 0x04CC) & 0x00FF) | + 0x1F00); } - b43legacy_phy_write(dev, 0x047E, 0x0078); + if (phy->rev >= 2) + b43legacy_phy_write(dev, 0x047E, 0x0078); } if (phy->radio_rev == 8) { b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) @@ -1078,7 +1084,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) else b43legacy_phy_write(dev, 0x002F, 0x0202); } - if (phy->gmode || phy->rev >= 2) { + if (phy->gmode) { b43legacy_phy_lo_adjust(dev, 0); b43legacy_phy_write(dev, 0x080F, 0x8078); } -- cgit v1.2.3 From 79636a5fbbdfb303dbf2bfe7a7fa396f40bfac31 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 8 Sep 2008 17:31:49 +0200 Subject: rt2x00: Revert "rt2x00: Fix the beacon length bug" This reverts: b93ce437eba7e0232683326f30d9d1167a872fad rt2x00: Fix the beacon length bug The workaround is no longer required since it has been correctly fixed in rt2x00usb now. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 12 ------------ drivers/net/wireless/rt2x00/rt73usb.c | 12 ------------ 2 files changed, 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 0e008b606f7..1cfda456b0e 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1133,7 +1133,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) int pipe = usb_sndbulkpipe(usb_dev, 1); int length; u16 reg; - u32 word, len; /* * Add the descriptor in front of the skb. @@ -1142,17 +1141,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); skbdesc->desc = entry->skb->data; - /* - * Adjust the beacon databyte count. The current number is - * calculated before this function gets called, but falsely - * assumes that the descriptor was already present in the SKB. - */ - rt2x00_desc_read(skbdesc->desc, 0, &word); - len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); - len += skbdesc->desc_len; - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); - rt2x00_desc_write(skbdesc->desc, 0, word); - /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e698ae0efbc..d9ef34c6670 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1572,7 +1572,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); unsigned int beacon_base; u32 reg; - u32 word, len; /* * Add the descriptor in front of the skb. @@ -1581,17 +1580,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); skbdesc->desc = entry->skb->data; - /* - * Adjust the beacon databyte count. The current number is - * calculated before this function gets called, but falsely - * assumes that the descriptor was already present in the SKB. - */ - rt2x00_desc_read(skbdesc->desc, 0, &word); - len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); - len += skbdesc->desc_len; - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); - rt2x00_desc_write(skbdesc->desc, 0, word); - /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. -- cgit v1.2.3 From 58169529986e81e0d477ce11eb8b91f025f649c1 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 8 Sep 2008 18:46:29 +0200 Subject: rt2x00: Make RFKILL enabled by default RFKILL should be enabled for _all_ hardware whether or not they feature a rfkill button or not. Remove driver specific RFKILL configuration options and make the rt2x00lib version depend on CONFIG_RFKILL and defaulting to 'y' to make sure it will always be enabled when RFKILL was enabled. This also fixes some bugs where RFKILL wasn't initialized and didn't respond to RFKILL key presses. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 30 ++---------------- drivers/net/wireless/rt2x00/rt2400pci.c | 8 ++--- drivers/net/wireless/rt2x00/rt2500pci.c | 8 ++--- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 50 +++++++++++++++++------------- drivers/net/wireless/rt2x00/rt61pci.c | 8 ++--- 5 files changed, 42 insertions(+), 62 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 11f590d63af..c896c990387 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -40,7 +40,8 @@ config RT2X00_LIB_CRYPTO config RT2X00_LIB_RFKILL boolean depends on RT2X00_LIB - select RFKILL + depends on RFKILL + default y config RT2X00_LIB_LEDS boolean @@ -57,15 +58,6 @@ config RT2400PCI When compiled as a module, this driver will be called "rt2400pci.ko". -config RT2400PCI_RFKILL - bool "Ralink rt2400 rfkill support" - depends on RT2400PCI - select RT2X00_LIB_RFKILL - ---help--- - This adds support for integrated rt2400 hardware that features a - hardware button to control the radio state. - This feature depends on the RF switch subsystem rfkill. - config RT2400PCI_LEDS bool "Ralink rt2400 leds support" depends on RT2400PCI && NEW_LEDS @@ -85,15 +77,6 @@ config RT2500PCI When compiled as a module, this driver will be called "rt2500pci.ko". -config RT2500PCI_RFKILL - bool "Ralink rt2500 rfkill support" - depends on RT2500PCI - select RT2X00_LIB_RFKILL - ---help--- - This adds support for integrated rt2500 hardware that features a - hardware button to control the radio state. - This feature depends on the RF switch subsystem rfkill. - config RT2500PCI_LEDS bool "Ralink rt2500 leds support" depends on RT2500PCI && NEW_LEDS @@ -116,15 +99,6 @@ config RT61PCI When compiled as a module, this driver will be called "rt61pci.ko". -config RT61PCI_RFKILL - bool "Ralink rt2501/rt61 rfkill support" - depends on RT61PCI - select RT2X00_LIB_RFKILL - ---help--- - This adds support for integrated rt61 hardware that features a - hardware button to control the radio state. - This feature depends on the RF switch subsystem rfkill. - config RT61PCI_LEDS bool "Ralink rt2501/rt61 leds support" depends on RT61PCI && NEW_LEDS diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 18b703c3fc2..0083e7e7dfc 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -231,7 +231,7 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2400PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -241,7 +241,7 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) } #else #define rt2400pci_rfkill_poll NULL -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2400PCI_LEDS static void rt2400pci_brightness_set(struct led_classdev *led_cdev, @@ -1386,10 +1386,10 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2400PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 2a96a011f2a..d8c9d67b8c8 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -231,7 +231,7 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2500PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -241,7 +241,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) } #else #define rt2500pci_rfkill_poll NULL -#endif /* CONFIG_RT2500PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2500PCI_LEDS static void rt2500pci_brightness_set(struct led_classdev *led_cdev, @@ -1545,10 +1545,10 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2500PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2500PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 8a2fefb365b..55eff58f188 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -45,16 +45,15 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) return 0; if (state == RFKILL_STATE_UNBLOCKED) { - INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); + INFO(rt2x00dev, "RFKILL event: enabling radio.\n"); clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); } else if (state == RFKILL_STATE_SOFT_BLOCKED) { - INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); + INFO(rt2x00dev, "RFKILL event: disabling radio.\n"); set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); } else { - WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", - state); + WARNING(rt2x00dev, "RFKILL event: unknown state %d.\n", state); } return retval; @@ -64,7 +63,12 @@ static int rt2x00rfkill_get_state(void *data, enum rfkill_state *state) { struct rt2x00_dev *rt2x00dev = data; - *state = rt2x00dev->rfkill->state; + /* + * rfkill_poll reports 1 when the key has been pressed and the + * radio should be blocked. + */ + *state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? + RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; return 0; } @@ -73,19 +77,18 @@ static void rt2x00rfkill_poll(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, rfkill_work.work); - int state; + enum rfkill_state state; - if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) + if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) || + !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return; /* - * rfkill_poll reports 1 when the key has been pressed and the - * radio should be blocked. + * Poll latest state and report it to rfkill who should sort + * out if the state should be toggled or not. */ - state = !rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; - - rfkill_force_state(rt2x00dev->rfkill, state); + if (!rt2x00rfkill_get_state(rt2x00dev, &state)) + rfkill_force_state(rt2x00dev->rfkill, state); queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL); @@ -93,8 +96,8 @@ static void rt2x00rfkill_poll(struct work_struct *work) void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || - !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || + test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) return; if (rfkill_register(rt2x00dev->rfkill)) { @@ -114,7 +117,7 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || + if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) return; @@ -127,21 +130,25 @@ void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy); + + if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) return; - rt2x00dev->rfkill = - rfkill_allocate(wiphy_dev(rt2x00dev->hw->wiphy), RFKILL_TYPE_WLAN); + rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN); if (!rt2x00dev->rfkill) { ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); return; } + __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state); + rt2x00dev->rfkill->name = rt2x00dev->ops->name; rt2x00dev->rfkill->data = rt2x00dev; rt2x00dev->rfkill->state = -1; rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; - rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); @@ -150,8 +157,7 @@ void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) || - !test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) + if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->flags)) return; cancel_delayed_work_sync(&rt2x00dev->rfkill_work); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d740f560ccd..a5c93520c37 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -271,7 +271,7 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT61PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -281,7 +281,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) } #else #define rt61pci_rfkill_poll NULL -#endif /* CONFIG_RT61PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT61PCI_LEDS static void rt61pci_brightness_set(struct led_classdev *led_cdev, @@ -2313,10 +2313,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT61PCI_RFKILL +#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT61PCI_RFKILL */ +#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Read frequency offset and RF programming sequence. -- cgit v1.2.3 From 771fd565195727d12f0b75d918b9fcb9f33a5476 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 8 Sep 2008 19:07:15 +0200 Subject: rt2x00: Make rt2x00 LEDS invisible config option There isn't really a good reason to have the LED configuration options selectable per driver, lets make it default 'y' and make it depend on the NEW_LEDS and LEDS_CLASS interface. Signed-off-by: Ivo van Doorn --- drivers/net/wireless/rt2x00/Kconfig | 45 +++------------------------------ drivers/net/wireless/rt2x00/rt2400pci.c | 8 +++--- drivers/net/wireless/rt2x00/rt2500pci.c | 8 +++--- drivers/net/wireless/rt2x00/rt2500usb.c | 8 +++--- drivers/net/wireless/rt2x00/rt61pci.c | 12 ++++----- drivers/net/wireless/rt2x00/rt73usb.c | 8 +++--- 6 files changed, 26 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index c896c990387..b686dc45483 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -45,7 +45,10 @@ config RT2X00_LIB_RFKILL config RT2X00_LIB_LEDS boolean - depends on RT2X00_LIB && NEW_LEDS + depends on RT2X00_LIB + depends on NEW_LEDS + depends on LEDS_CLASS + default y config RT2400PCI tristate "Ralink rt2400 (PCI/PCMCIA) support" @@ -58,14 +61,6 @@ config RT2400PCI When compiled as a module, this driver will be called "rt2400pci.ko". -config RT2400PCI_LEDS - bool "Ralink rt2400 leds support" - depends on RT2400PCI && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT2500PCI tristate "Ralink rt2500 (PCI/PCMCIA) support" depends on PCI @@ -77,14 +72,6 @@ config RT2500PCI When compiled as a module, this driver will be called "rt2500pci.ko". -config RT2500PCI_LEDS - bool "Ralink rt2500 leds support" - depends on RT2500PCI && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT61PCI tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" depends on PCI @@ -99,14 +86,6 @@ config RT61PCI When compiled as a module, this driver will be called "rt61pci.ko". -config RT61PCI_LEDS - bool "Ralink rt2501/rt61 leds support" - depends on RT61PCI && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB @@ -117,14 +96,6 @@ config RT2500USB When compiled as a module, this driver will be called "rt2500usb.ko". -config RT2500USB_LEDS - bool "Ralink rt2500 leds support" - depends on RT2500USB && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT73USB tristate "Ralink rt2501/rt73 (USB) support" depends on USB @@ -138,14 +109,6 @@ config RT73USB When compiled as a module, this driver will be called "rt73usb.ko". -config RT73USB_LEDS - bool "Ralink rt2501/rt73 leds support" - depends on RT73USB && NEW_LEDS - select LEDS_CLASS - select RT2X00_LIB_LEDS - ---help--- - This adds support for led triggers provided my mac80211. - config RT2X00_LIB_DEBUGFS bool "Ralink debugfs support" depends on RT2X00_LIB && MAC80211_DEBUGFS diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0083e7e7dfc..08cb9eec16a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -243,7 +243,7 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) #define rt2400pci_rfkill_poll NULL #endif /* CONFIG_RT2X00_LIB_RFKILL */ -#ifdef CONFIG_RT2400PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2400pci_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -288,7 +288,7 @@ static void rt2400pci_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2400pci_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT2400PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1374,14 +1374,14 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ -#ifdef CONFIG_RT2400PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); if (value == LED_MODE_TXRX_ACTIVITY) rt2400pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_ACTIVITY); -#endif /* CONFIG_RT2400PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Detect if this device has an hardware controlled radio. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index d8c9d67b8c8..ef42cc04a2d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -243,7 +243,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) #define rt2500pci_rfkill_poll NULL #endif /* CONFIG_RT2X00_LIB_RFKILL */ -#ifdef CONFIG_RT2500PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500pci_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -288,7 +288,7 @@ static void rt2500pci_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2500pci_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT2500PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1533,14 +1533,14 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ -#ifdef CONFIG_RT2500PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); if (value == LED_MODE_TXRX_ACTIVITY) rt2500pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_ACTIVITY); -#endif /* CONFIG_RT2500PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Detect if this device has an hardware controlled radio. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 1cfda456b0e..cb5f2d01a9c 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -288,7 +288,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2500USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500usb_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -333,7 +333,7 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt2500usb_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT2500USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1473,14 +1473,14 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led mode, for correct led behaviour. */ -#ifdef CONFIG_RT2500USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); if (value == LED_MODE_TXRX_ACTIVITY) rt2500usb_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_ACTIVITY); -#endif /* CONFIG_RT2500USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Check if the BBP tuning should be disabled. diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a5c93520c37..2c36b91ff4c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -163,7 +163,7 @@ rf_write: rt2x00_rf_write(rt2x00dev, word, value); } -#ifdef CONFIG_RT61PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS /* * This function is only called from rt61pci_led_brightness() * make gcc happy by placing this function inside the @@ -195,7 +195,7 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } -#endif /* CONFIG_RT61PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) { @@ -283,7 +283,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) #define rt61pci_rfkill_poll NULL #endif /* CONFIG_RT2X00_LIB_RFKILL */ -#ifdef CONFIG_RT61PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt61pci_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -348,7 +348,7 @@ static void rt61pci_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt61pci_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT61PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -2374,7 +2374,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * If the eeprom value is invalid, * switch to default led mode. */ -#ifdef CONFIG_RT61PCI_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); @@ -2408,7 +2408,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); -#endif /* CONFIG_RT61PCI_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ return 0; } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d9ef34c6670..27dde3e3460 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -292,7 +292,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT73USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS static void rt73usb_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -359,7 +359,7 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev, led->led_dev.blink_set = rt73usb_blink_set; led->flags = LED_INITIALIZED; } -#endif /* CONFIG_RT73USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ /* * Configuration handlers. @@ -1932,7 +1932,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Store led settings, for correct led behaviour. */ -#ifdef CONFIG_RT73USB_LEDS +#ifdef CONFIG_RT2X00_LIB_LEDS rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); @@ -1965,7 +1965,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_mcu_reg, MCU_LEDCS_POLARITY_READY_A, rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_RDY_A)); -#endif /* CONFIG_RT73USB_LEDS */ +#endif /* CONFIG_RT2X00_LIB_LEDS */ return 0; } -- cgit v1.2.3 From 71b35f3abeb8f7f7e0afd7573424540cc5aae2d5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 8 Sep 2008 16:34:40 -0400 Subject: libertas: clear current command on card removal If certain commands were in-flight when the card was pulled or the driver rmmod-ed, cleanup would block on the work queue stopping, but the work queue was in turn blocked on the current command being canceled, which didn't happen. Fix that. Signed-off-by: Dan Williams Cc: stable Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2436634b6b7..73dc8c72402 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1205,7 +1205,13 @@ void lbs_remove_card(struct lbs_private *priv) cancel_delayed_work_sync(&priv->scan_work); cancel_delayed_work_sync(&priv->assoc_work); cancel_work_sync(&priv->mcast_work); + + /* worker thread destruction blocks on the in-flight command which + * should have been cleared already in lbs_stop_card(). + */ + lbs_deb_main("destroying worker thread\n"); destroy_workqueue(priv->work_thread); + lbs_deb_main("done destroying worker thread\n"); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { priv->psmode = LBS802_11POWERMODECAM; @@ -1323,14 +1329,26 @@ void lbs_stop_card(struct lbs_private *priv) device_remove_file(&dev->dev, &dev_attr_lbs_rtap); } - /* Flush pending command nodes */ + /* Delete the timeout of the currently processing command */ del_timer_sync(&priv->command_timer); + + /* Flush pending command nodes */ spin_lock_irqsave(&priv->driver_lock, flags); + lbs_deb_main("clearing pending commands\n"); list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { cmdnode->result = -ENOENT; cmdnode->cmdwaitqwoken = 1; wake_up_interruptible(&cmdnode->cmdwait_q); } + + /* Flush the command the card is currently processing */ + if (priv->cur_cmd) { + lbs_deb_main("clearing current command\n"); + priv->cur_cmd->result = -ENOENT; + priv->cur_cmd->cmdwaitqwoken = 1; + wake_up_interruptible(&priv->cur_cmd->cmdwait_q); + } + lbs_deb_main("done clearing commands\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); unregister_netdev(dev); -- cgit v1.2.3 From 12e5e22d38577a5a16dd47e7144722817a55e52e Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Tue, 9 Sep 2008 10:54:52 +0800 Subject: iwl3945 : Code cleanup Simplify pass_packet_to_mac80211 code block. Signed-off-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1377c8190ec..3d100e89824 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -681,19 +681,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, priv->last_rx_noise = rx_status.noise; } - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); - return; - } - - switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_MGMT: - case IEEE80211_FTYPE_DATA: - /* fall through */ - default: - iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); - break; - } + iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); } int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr, -- cgit v1.2.3 From 90d7795e152f9b7095adef77b71a4448f092e3b6 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Tue, 9 Sep 2008 10:54:53 +0800 Subject: iwlwifi: fix searching for best rate in new search column This patch fixes a bug in Rate Scaling. When moving from SISO to MIMO we need to choose the lowest higher rate, instead of choosing the highest in MIMO. No doing this can lead to a high packet loss in the highest rate in MIMO, leading not to move MIMO although lower in MIMO could give a better TPT. Signed-off-by: Guy Cohen Signed-off-by: Emmanuel Grumbach Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 4fc3a0f1d8f..de00be1bffa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -436,7 +436,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, /* Shift bitmap by one frame (throw away oldest history), * OR in "1", and increment "success" if this * frame was successful. */ - window->data <<= 1;; + window->data <<= 1; if (successes > 0) { window->success_counter++; window->data |= 0x1; @@ -1128,6 +1128,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, /* Higher rate not available, use the original */ } else { + new_rate = rate; break; } } -- cgit v1.2.3 From 3110bef78cb4282c58245bc8fd6d95d9ccb19749 Mon Sep 17 00:00:00 2001 From: Guy Cohen Date: Tue, 9 Sep 2008 10:54:54 +0800 Subject: iwlwifi: Added support for 3 antennas Added support for 3 antennas for Legacy, SISO and MIMO2. MIMO3 is still not supported yet. Signed-off-by: Guy Cohen Signed-off-by: Emmanuel Grumbach Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 156 ++++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 29 +++--- 2 files changed, 122 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index de00be1bffa..c293e5b6cbb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1282,15 +1282,23 @@ static int rs_move_legacy_other(struct iwl_priv *priv, (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret = 0; for (; ;) { switch (tbl->action) { - case IWL_LEGACY_SWITCH_ANTENNA: + case IWL_LEGACY_SWITCH_ANTENNA1: + case IWL_LEGACY_SWITCH_ANTENNA2: IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); lq_sta->action_counter++; + if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && + tx_chains_num <= 1) || + (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && + tx_chains_num <= 2)) + break; + /* Don't change antenna if success has been great */ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; @@ -1300,7 +1308,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, search_tbl)) { - lq_sta->search_better_tbl = 1; + rs_set_expected_tpt_table(lq_sta, search_tbl); goto out; } break; @@ -1313,43 +1321,54 @@ static int rs_move_legacy_other(struct iwl_priv *priv, ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { - lq_sta->search_better_tbl = 1; lq_sta->action_counter = 0; goto out; } break; - case IWL_LEGACY_SWITCH_MIMO2: + case IWL_LEGACY_SWITCH_MIMO2_AB: + case IWL_LEGACY_SWITCH_MIMO2_AC: + case IWL_LEGACY_SWITCH_MIMO2_BC: IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ - /*FIXME:RS:need to check ant validity*/ + + if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) + search_tbl->ant_type = ANT_AB; + else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) + search_tbl->ant_type = ANT_AC; + else + search_tbl->ant_type = ANT_BC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); if (!ret) { - lq_sta->search_better_tbl = 1; lq_sta->action_counter = 0; goto out; } break; } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (tbl->action == start_action) break; } + search_tbl->lq_type = LQ_NONE; return 0; - out: +out: + lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; return 0; } @@ -1371,34 +1390,51 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret; for (;;) { lq_sta->action_counter++; switch (tbl->action) { - case IWL_SISO_SWITCH_ANTENNA: + case IWL_SISO_SWITCH_ANTENNA1: + case IWL_SISO_SWITCH_ANTENNA2: IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); + + if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 && + tx_chains_num <= 1) || + (tbl->action == IWL_SISO_SWITCH_ANTENNA2 && + tx_chains_num <= 2)) + break; + if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) { - lq_sta->search_better_tbl = 1; + &search_tbl->current_rate, search_tbl)) goto out; - } break; - case IWL_SISO_SWITCH_MIMO2: + case IWL_SISO_SWITCH_MIMO2_AB: + case IWL_SISO_SWITCH_MIMO2_AC: + case IWL_SISO_SWITCH_MIMO2_BC: IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); memcpy(search_tbl, tbl, sz); search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ + + if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) + search_tbl->ant_type = ANT_AB; + else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) + search_tbl->ant_type = ANT_AC; + else + search_tbl->ant_type = ANT_BC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; + if (!ret) goto out; - } break; case IWL_SISO_SWITCH_GI: if (!tbl->is_fat && @@ -1428,22 +1464,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, } search_tbl->current_rate = rate_n_flags_from_tbl( search_tbl, index, is_green); - lq_sta->search_better_tbl = 1; goto out; } tbl->action++; if (tbl->action > IWL_SISO_SWITCH_GI) - tbl->action = IWL_SISO_SWITCH_ANTENNA; + tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (tbl->action == start_action) break; } + search_tbl->lq_type = LQ_NONE; return 0; out: + lq_sta->search_better_tbl = 1; tbl->action++; if (tbl->action > IWL_SISO_SWITCH_GI) - tbl->action = IWL_SISO_SWITCH_ANTENNA; + tbl->action = IWL_SISO_SWITCH_ANTENNA1; return 0; } @@ -1459,37 +1496,58 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; - /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret; for (;;) { lq_sta->action_counter++; switch (tbl->action) { - case IWL_MIMO_SWITCH_ANTENNA_A: - case IWL_MIMO_SWITCH_ANTENNA_B: + case IWL_MIMO2_SWITCH_ANTENNA1: + case IWL_MIMO2_SWITCH_ANTENNA2: + IWL_DEBUG_RATE("LQ: MIMO toggle Antennas\n"); + + if (tx_chains_num <= 2) + break; + + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + + memcpy(search_tbl, tbl, sz); + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) + goto out; + break; + case IWL_MIMO2_SWITCH_SISO_A: + case IWL_MIMO2_SWITCH_SISO_B: + case IWL_MIMO2_SWITCH_SISO_C: IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); - /*FIXME:RS:need to check ant validity + C*/ - if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) + if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) search_tbl->ant_type = ANT_A; - else + else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) search_tbl->ant_type = ANT_B; + else + search_tbl->ant_type = ANT_C; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; ret = rs_switch_to_siso(priv, lq_sta, conf, sta, search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; + if (!ret) goto out; - } + break; - case IWL_MIMO_SWITCH_GI: + case IWL_MIMO2_SWITCH_GI: if (!tbl->is_fat && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) @@ -1518,23 +1576,23 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, } search_tbl->current_rate = rate_n_flags_from_tbl( search_tbl, index, is_green); - lq_sta->search_better_tbl = 1; goto out; } tbl->action++; - if (tbl->action > IWL_MIMO_SWITCH_GI) - tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + if (tbl->action > IWL_MIMO2_SWITCH_GI) + tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; if (tbl->action == start_action) break; } - + search_tbl->lq_type = LQ_NONE; return 0; out: + lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_MIMO_SWITCH_GI) - tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + if (tbl->action > IWL_MIMO2_SWITCH_GI) + tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; return 0; } @@ -1749,19 +1807,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, rs_stay_in_table(lq_sta); goto out; + } /* Else we have enough samples; calculate estimate of * actual average throughput */ - } else { - /*FIXME:RS remove this else if we don't get this error*/ - if (window->average_tpt != ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128)) { - IWL_ERROR("expected_tpt should have been calculated" - " by now\n"); - window->average_tpt = ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128); - } - } + + BUG_ON(window->average_tpt != ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128)); /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl) { @@ -1771,7 +1823,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, * continuing to use the setup that we've been trying. */ if (window->average_tpt > lq_sta->last_tpt) { - IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " + IWL_DEBUG_RATE("LQ: SWITCHING TO NEW TABLE " "suc=%d cur-tpt=%d old-tpt=%d\n", window->success_ratio, window->average_tpt, @@ -2184,7 +2236,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); - IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); + IWL_DEBUG_RATE("LQ: *** rate scale station global init ***\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 84d4d1e3375..d148d73635e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -206,21 +206,28 @@ enum { #define IWL_RATE_DECREASE_TH 1920 /* 15% */ /* possible actions when in legacy mode */ -#define IWL_LEGACY_SWITCH_ANTENNA 0 -#define IWL_LEGACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO2 2 +#define IWL_LEGACY_SWITCH_ANTENNA1 0 +#define IWL_LEGACY_SWITCH_ANTENNA2 1 +#define IWL_LEGACY_SWITCH_SISO 2 +#define IWL_LEGACY_SWITCH_MIMO2_AB 3 +#define IWL_LEGACY_SWITCH_MIMO2_AC 4 +#define IWL_LEGACY_SWITCH_MIMO2_BC 5 /* possible actions when in siso mode */ -#define IWL_SISO_SWITCH_ANTENNA 0 -#define IWL_SISO_SWITCH_MIMO2 1 -#define IWL_SISO_SWITCH_GI 2 +#define IWL_SISO_SWITCH_ANTENNA1 0 +#define IWL_SISO_SWITCH_ANTENNA2 1 +#define IWL_SISO_SWITCH_MIMO2_AB 2 +#define IWL_SISO_SWITCH_MIMO2_AC 3 +#define IWL_SISO_SWITCH_MIMO2_BC 4 +#define IWL_SISO_SWITCH_GI 5 /* possible actions when in mimo mode */ -#define IWL_MIMO_SWITCH_ANTENNA_A 0 -#define IWL_MIMO_SWITCH_ANTENNA_B 1 -#define IWL_MIMO_SWITCH_GI 2 - -/*FIXME:RS:separate MIMO2/3 transitions*/ +#define IWL_MIMO2_SWITCH_ANTENNA1 0 +#define IWL_MIMO2_SWITCH_ANTENNA2 1 +#define IWL_MIMO2_SWITCH_SISO_A 2 +#define IWL_MIMO2_SWITCH_SISO_B 3 +#define IWL_MIMO2_SWITCH_SISO_C 4 +#define IWL_MIMO2_SWITCH_GI 5 /*FIXME:RS:add posible acctions for MIMO3*/ -- cgit v1.2.3 From 0112c9e9e8d47f1d1e6ce1323675cb43ca6aae86 Mon Sep 17 00:00:00 2001 From: Anna Neal Date: Thu, 11 Sep 2008 11:17:25 -0700 Subject: libertas: Improvements on automatic tx power control via SIOCSIWTXPOW. iwconfig txpower can now be used to set tx power to fixed or auto. If set to auto the default firmware settings are used. The command CMD_802_11_PA_CFG is only sent to older firmware, as Dan Williams noted the command was no longer supported in firmware V9+. Signed-off-by: Anna Neal Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 64 +++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/cmd.h | 6 ++++ drivers/net/wireless/libertas/defs.h | 9 +++++ drivers/net/wireless/libertas/host.h | 1 + drivers/net/wireless/libertas/hostcmd.h | 24 ++++++++++--- drivers/net/wireless/libertas/wext.c | 31 ++++++++++++++-- 6 files changed, 128 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 802547e7967..5fef05f3cd0 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1971,6 +1971,70 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) } +/** + * @brief Configures the transmission power control functionality. + * + * @param priv A pointer to struct lbs_private structure + * @param enable Transmission power control enable + * @param p0 Power level when link quality is good (dBm). + * @param p1 Power level when link quality is fair (dBm). + * @param p2 Power level when link quality is poor (dBm). + * @param usesnr Use Signal to Noise Ratio in TPC + * + * @return 0 on success + */ +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr) +{ + struct cmd_ds_802_11_tpc_cfg cmd; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.enable = !!enable; + cmd.usesnr = !!enable; + cmd.P0 = p0; + cmd.P1 = p1; + cmd.P2 = p2; + + ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd); + + return ret; +} + +/** + * @brief Configures the power adaptation settings. + * + * @param priv A pointer to struct lbs_private structure + * @param enable Power adaptation enable + * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). + * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). + * @param p2 Power level for 48 and 54 Mbps (dBm). + * + * @return 0 on Success + */ + +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2) +{ + struct cmd_ds_802_11_pa_cfg cmd; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.enable = !!enable; + cmd.P0 = p0; + cmd.P1 = p1; + cmd.P2 = p2; + + ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd); + + return ret; +} + + static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 11ac996e895..336a181d857 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -26,6 +26,12 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), unsigned long callback_arg); +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2); + +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr); + int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 4b2428ac222..c89d7a1041a 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -189,6 +189,15 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MRVDRV_CMD_UPLD_RDY 0x0008 #define MRVDRV_CARDEVENT 0x0010 + +/* Automatic TX control default levels */ +#define POW_ADAPT_DEFAULT_P0 13 +#define POW_ADAPT_DEFAULT_P1 15 +#define POW_ADAPT_DEFAULT_P2 18 +#define TPC_DEFAULT_P0 5 +#define TPC_DEFAULT_P1 10 +#define TPC_DEFAULT_P2 13 + /** TxPD status */ /* Station firmware use TxPD status field to report final Tx transmit diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index da618fc997c..a916bb9bd5d 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -83,6 +83,7 @@ #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 #define CMD_802_11_SLEEP_PERIOD 0x0068 #define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PA_CFG 0x0073 #define CMD_802_11_FW_WAKE_METHOD 0x0074 #define CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define CMD_802_11_RATE_ADAPT_RATESET 0x0076 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d27c276b219..630b7996756 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -607,14 +607,28 @@ struct cmd_ds_802_11_eeprom_access { } __attribute__ ((packed)); struct cmd_ds_802_11_tpc_cfg { + struct cmd_header hdr; + __le16 action; - u8 enable; - s8 P0; - s8 P1; - s8 P2; - u8 usesnr; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; + uint8_t usesnr; } __attribute__ ((packed)); + +struct cmd_ds_802_11_pa_cfg { + struct cmd_header hdr; + + __le16 action; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; +} __attribute__ ((packed)); + + struct cmd_ds_802_11_led_ctrl { __le16 action; __le16 numled; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 426f1fe3bb4..e8cadad2c86 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1820,7 +1820,21 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, } if (vwrq->fixed == 0) { - /* Auto power control */ + /* User requests automatic tx power control, however there are + * many auto tx settings. For now use firmware defaults until + * we come up with a good way to expose these to the user. */ + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 1, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; dbm = priv->txpower_max; } else { /* Userspace check in iwrange if it should use dBm or mW, @@ -1830,7 +1844,8 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, goto out; } - /* Validate requested power level against firmware allowed levels */ + /* Validate requested power level against firmware allowed + * levels */ if (priv->txpower_min && (dbm < priv->txpower_min)) { ret = -EINVAL; goto out; @@ -1840,6 +1855,18 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, ret = -EINVAL; goto out; } + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 0, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; } /* If the radio was off, turn it on */ -- cgit v1.2.3 From e83a1070a1167eac1bf8844b9f08df5e9ea1b5bc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 9 Sep 2008 23:19:49 -0700 Subject: zd1211rw: make use of new regulatory_hint() This cleans up zd1211rw's own regulatory work, and makes use of the new cfg80211 regulatory_hint(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/Makefile | 2 +- drivers/net/wireless/zd1211rw/zd_chip.c | 1 - drivers/net/wireless/zd1211rw/zd_ieee80211.c | 100 --------------------------- drivers/net/wireless/zd1211rw/zd_ieee80211.h | 95 ------------------------- drivers/net/wireless/zd1211rw/zd_mac.c | 40 +++++++++-- drivers/net/wireless/zd1211rw/zd_mac.h | 65 ++++++++++++++++- drivers/net/wireless/zd1211rw/zd_rf.c | 2 +- 7 files changed, 102 insertions(+), 203 deletions(-) delete mode 100644 drivers/net/wireless/zd1211rw/zd_ieee80211.c delete mode 100644 drivers/net/wireless/zd1211rw/zd_ieee80211.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index cc36126cee8..1907eafb9b1 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o -zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \ +zd1211rw-objs := zd_chip.o zd_mac.o \ zd_rf_al2230.o zd_rf_rf2959.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ zd_rf.o zd_usb.o diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 0acb5c34573..e0ac58b8ff1 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -28,7 +28,6 @@ #include "zd_def.h" #include "zd_chip.h" -#include "zd_ieee80211.h" #include "zd_mac.h" #include "zd_rf.h" diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c deleted file mode 100644 index d8dc41ec0e5..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ /dev/null @@ -1,100 +0,0 @@ -/* ZD1211 USB-WLAN driver for Linux - * - * Copyright (C) 2005-2007 Ulrich Kunitz - * Copyright (C) 2006-2007 Daniel Drake - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * In the long term, we'll probably find a better way of handling regulatory - * requirements outside of the driver. - */ - -#include -#include - -#include "zd_ieee80211.h" -#include "zd_mac.h" - -struct channel_range { - u8 regdomain; - u8 start; - u8 end; /* exclusive (channel must be less than end) */ -}; - -static const struct channel_range channel_ranges[] = { - { ZD_REGDOMAIN_FCC, 1, 12 }, - { ZD_REGDOMAIN_IC, 1, 12 }, - { ZD_REGDOMAIN_ETSI, 1, 14 }, - { ZD_REGDOMAIN_JAPAN, 1, 14 }, - { ZD_REGDOMAIN_SPAIN, 1, 14 }, - { ZD_REGDOMAIN_FRANCE, 1, 14 }, - - /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in - * 802.11). However, in 2001 the range was extended to include channels - * 1-13. The ZyDAS devices still use the old region code but are - * designed to allow the extra channel access in Japan. */ - { ZD_REGDOMAIN_JAPAN_ADD, 1, 15 }, -}; - -static const struct channel_range *zd_channel_range(u8 regdomain) -{ - int i; - for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) { - const struct channel_range *range = &channel_ranges[i]; - if (range->regdomain == regdomain) - return range; - } - return NULL; -} - -#define CHAN_TO_IDX(chan) ((chan) - 1) - -static void unmask_bg_channels(struct ieee80211_hw *hw, - const struct channel_range *range, - struct ieee80211_supported_band *sband) -{ - u8 channel; - - for (channel = range->start; channel < range->end; channel++) { - struct ieee80211_channel *chan = - &sband->channels[CHAN_TO_IDX(channel)]; - chan->flags = 0; - } -} - -void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain) -{ - struct zd_mac *mac = zd_hw_mac(hw); - const struct channel_range *range; - - dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain); - - range = zd_channel_range(regdomain); - if (!range) { - /* The vendor driver overrides the regulatory domain and - * allowed channel registers and unconditionally restricts - * available channels to 1-11 everywhere. Match their - * questionable behaviour only for regdomains which we don't - * recognise. */ - dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: " - "%#02x. Defaulting to FCC.\n", regdomain); - range = zd_channel_range(ZD_REGDOMAIN_FCC); - } - - unmask_bg_channels(hw, range, &mac->band); -} - diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h deleted file mode 100644 index 26b79f19758..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ /dev/null @@ -1,95 +0,0 @@ -/* ZD1211 USB-WLAN driver for Linux - * - * Copyright (C) 2005-2007 Ulrich Kunitz - * Copyright (C) 2006-2007 Daniel Drake - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_IEEE80211_H -#define _ZD_IEEE80211_H - -#include - -/* Additional definitions from the standards. - */ - -#define ZD_REGDOMAIN_FCC 0x10 -#define ZD_REGDOMAIN_IC 0x20 -#define ZD_REGDOMAIN_ETSI 0x30 -#define ZD_REGDOMAIN_SPAIN 0x31 -#define ZD_REGDOMAIN_FRANCE 0x32 -#define ZD_REGDOMAIN_JAPAN_ADD 0x40 -#define ZD_REGDOMAIN_JAPAN 0x41 - -enum { - MIN_CHANNEL24 = 1, - MAX_CHANNEL24 = 14, -}; - -void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain); - -#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 - -struct ofdm_plcp_header { - u8 prefix[3]; - __le16 service; -} __attribute__((packed)); - -static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) -{ - return header->prefix[0] & 0xf; -} - -/* The following defines give the encoding of the 4-bit rate field in the - * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to - * define the zd-rate values for OFDM. - * - * See the struct zd_ctrlset definition in zd_mac.h. - */ -#define ZD_OFDM_PLCP_RATE_6M 0xb -#define ZD_OFDM_PLCP_RATE_9M 0xf -#define ZD_OFDM_PLCP_RATE_12M 0xa -#define ZD_OFDM_PLCP_RATE_18M 0xe -#define ZD_OFDM_PLCP_RATE_24M 0x9 -#define ZD_OFDM_PLCP_RATE_36M 0xd -#define ZD_OFDM_PLCP_RATE_48M 0x8 -#define ZD_OFDM_PLCP_RATE_54M 0xc - -struct cck_plcp_header { - u8 signal; - u8 service; - __le16 length; - __le16 crc16; -} __attribute__((packed)); - -static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) -{ - return header->signal; -} - -/* These defines give the encodings of the signal field in the 802.11b PLCP - * header. The signal field gives the bit rate of the following packet. Even - * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s - * rate to stay consistent with Zydas and our use of the term. - * - * Notify that these values are *not* used in the zd-rates. - */ -#define ZD_CCK_PLCP_SIGNAL_1M 0x0a -#define ZD_CCK_PLCP_SIGNAL_2M 0x14 -#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 -#define ZD_CCK_PLCP_SIGNAL_11M 0x6e - -#endif /* _ZD_IEEE80211_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index e019102b228..3005dd1fde4 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -3,7 +3,7 @@ * Copyright (C) 2005-2007 Ulrich Kunitz * Copyright (C) 2006-2007 Daniel Drake * Copyright (C) 2006-2007 Michael Wu - * Copyright (c) 2007 Luis R. Rodriguez + * Copyright (C) 2007-2008 Luis R. Rodriguez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,9 +29,23 @@ #include "zd_def.h" #include "zd_chip.h" #include "zd_mac.h" -#include "zd_ieee80211.h" #include "zd_rf.h" +struct zd_reg_alpha2_map { + u32 reg; + char alpha2[2]; +}; + +static struct zd_reg_alpha2_map reg_alpha2_map[] = { + { ZD_REGDOMAIN_FCC, "US" }, + { ZD_REGDOMAIN_IC, "CA" }, + { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ + { ZD_REGDOMAIN_JAPAN, "JP" }, + { ZD_REGDOMAIN_JAPAN_ADD, "JP" }, + { ZD_REGDOMAIN_SPAIN, "ES" }, + { ZD_REGDOMAIN_FRANCE, "FR" }, +}; + /* This table contains the hardware specific values for the modulation rates. */ static const struct ieee80211_rate zd_rates[] = { { .bitrate = 10, @@ -95,6 +109,21 @@ static void housekeeping_init(struct zd_mac *mac); static void housekeeping_enable(struct zd_mac *mac); static void housekeeping_disable(struct zd_mac *mac); +static int zd_reg2alpha2(u8 regdomain, char *alpha2) +{ + unsigned int i; + struct zd_reg_alpha2_map *reg_map; + for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { + reg_map = ®_alpha2_map[i]; + if (regdomain == reg_map->reg) { + alpha2[0] = reg_map->alpha2[0]; + alpha2[1] = reg_map->alpha2[1]; + return 0; + } + } + return 1; +} + int zd_mac_preinit_hw(struct ieee80211_hw *hw) { int r; @@ -115,6 +144,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) int r; struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; + char alpha2[2]; u8 default_regdomain; r = zd_chip_enable_int(chip); @@ -139,7 +169,9 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) if (r) goto disable_int; - zd_geo_init(hw, mac->regdomain); + r = zd_reg2alpha2(mac->regdomain, alpha2); + if (!r) + regulatory_hint(hw->wiphy, alpha2, NULL); r = 0; disable_int: @@ -753,7 +785,7 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, return 0; } -void zd_process_intr(struct work_struct *work) +static void zd_process_intr(struct work_struct *work) { u16 int_status; struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 18c1d56d3dd..4c05d3ee4c3 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -25,7 +25,6 @@ #include #include "zd_chip.h" -#include "zd_ieee80211.h" struct zd_ctrlset { u8 modulation; @@ -187,6 +186,70 @@ struct zd_mac { unsigned int pass_ctrl:1; }; +#define ZD_REGDOMAIN_FCC 0x10 +#define ZD_REGDOMAIN_IC 0x20 +#define ZD_REGDOMAIN_ETSI 0x30 +#define ZD_REGDOMAIN_SPAIN 0x31 +#define ZD_REGDOMAIN_FRANCE 0x32 +#define ZD_REGDOMAIN_JAPAN_ADD 0x40 +#define ZD_REGDOMAIN_JAPAN 0x41 + +enum { + MIN_CHANNEL24 = 1, + MAX_CHANNEL24 = 14, +}; + +#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 + +struct ofdm_plcp_header { + u8 prefix[3]; + __le16 service; +} __attribute__((packed)); + +static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) +{ + return header->prefix[0] & 0xf; +} + +/* The following defines give the encoding of the 4-bit rate field in the + * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to + * define the zd-rate values for OFDM. + * + * See the struct zd_ctrlset definition in zd_mac.h. + */ +#define ZD_OFDM_PLCP_RATE_6M 0xb +#define ZD_OFDM_PLCP_RATE_9M 0xf +#define ZD_OFDM_PLCP_RATE_12M 0xa +#define ZD_OFDM_PLCP_RATE_18M 0xe +#define ZD_OFDM_PLCP_RATE_24M 0x9 +#define ZD_OFDM_PLCP_RATE_36M 0xd +#define ZD_OFDM_PLCP_RATE_48M 0x8 +#define ZD_OFDM_PLCP_RATE_54M 0xc + +struct cck_plcp_header { + u8 signal; + u8 service; + __le16 length; + __le16 crc16; +} __attribute__((packed)); + +static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) +{ + return header->signal; +} + +/* These defines give the encodings of the signal field in the 802.11b PLCP + * header. The signal field gives the bit rate of the following packet. Even + * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s + * rate to stay consistent with Zydas and our use of the term. + * + * Notify that these values are *not* used in the zd-rates. + */ +#define ZD_CCK_PLCP_SIGNAL_1M 0x0a +#define ZD_CCK_PLCP_SIGNAL_2M 0x14 +#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 +#define ZD_CCK_PLCP_SIGNAL_11M 0x6e + static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw) { return hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index ec412931281..7207bfd2e6c 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -23,7 +23,7 @@ #include "zd_def.h" #include "zd_rf.h" -#include "zd_ieee80211.h" +#include "zd_mac.h" #include "zd_chip.h" static const char * const rfs[] = { -- cgit v1.2.3 From f8e77caefea8940ee1fb09c9ebb0107ca2eadb72 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Sep 2008 09:04:33 -0400 Subject: libertas: remove unused generic RESET command The generic reset command is unused. Each interface type needs to handle the reset command differently since after reset, the firmware is dead and interface-specific mechanisms must be used to reinitialize the card. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 18 ------------------ drivers/net/wireless/libertas/cmdresp.c | 1 - drivers/net/wireless/libertas/hostcmd.h | 5 ----- drivers/net/wireless/libertas/if_usb.c | 5 ++--- 4 files changed, 2 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 5fef05f3cd0..b57625a3802 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -480,20 +480,6 @@ int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, return ret; } -static int lbs_cmd_802_11_reset(struct cmd_ds_command *cmd, int cmd_action) -{ - struct cmd_ds_802_11_reset *reset = &cmd->params.reset; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd->command = cpu_to_le16(CMD_802_11_RESET); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); - reset->action = cpu_to_le16(cmd_action); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, struct cmd_ds_command *cmd, int cmd_action, @@ -1419,10 +1405,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_RESET: - ret = lbs_cmd_802_11_reset(cmdptr, cmd_action); - break; - case CMD_802_11_AUTHENTICATE: ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 0371c83f566..f305b049b58 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -271,7 +271,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): break; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 630b7996756..f2f92e237c4 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -151,10 +151,6 @@ struct cmd_ds_get_hw_spec { __le32 fwcapinfo; } __attribute__ ((packed)); -struct cmd_ds_802_11_reset { - __le16 action; -}; - struct cmd_ds_802_11_subscribe_event { struct cmd_header hdr; @@ -717,7 +713,6 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_reset reset; struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 7b02d612b07..cafbccb7414 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -439,11 +439,10 @@ static int if_usb_reset_device(struct if_usb_card *cardp) *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); cmd->command = cpu_to_le16(CMD_802_11_RESET); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(struct cmd_header)); cmd->result = cpu_to_le16(0); cmd->seqnum = cpu_to_le16(0x5a5a); - cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT); - usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset)); + usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header)); msleep(100); ret = usb_reset_device(cardp->udev); -- cgit v1.2.3 From 8feceb67929bd23bfca58d5f49df93d7fc315bb1 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Sep 2008 18:49:27 +0530 Subject: ath9k: Re-order functions in main.c Some of the functions in main.c are re-ordered in such a way that all local functions are defined before mac80211 and pci callbacks. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 1722 ++++++++++++++++++------------------- 1 file changed, 861 insertions(+), 861 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 57d7cc87cb0..07e5b5d877b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -325,1087 +325,1087 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } -static int ath9k_start(struct ieee80211_hw *hw) +static void ath9k_ht_conf(struct ath_softc *sc, + struct ieee80211_bss_conf *bss_conf) { - struct ath_softc *sc = hw->priv; - struct ieee80211_channel *curchan = hw->conf.channel; - int error = 0, pos; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " - "initial channel: %d MHz\n", __func__, curchan->center_freq); +#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) + struct ath_ht_info *ht_info = &sc->sc_ht_info; - /* setup initial channel */ + if (bss_conf->assoc_ht) { + ht_info->ext_chan_offset = + bss_conf->ht_bss_conf->bss_cap & + IEEE80211_HT_IE_CHA_SEC_OFFSET; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; - } + 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; - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; + 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); - /* open ath_dev */ - error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); - if (error) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to complete ath_open\n", __func__); - return error; } - ieee80211_wake_queues(hw); - return 0; +#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT } -static int ath9k_tx(struct ieee80211_hw *hw, - struct sk_buff *skb) +static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_bss_conf *bss_conf) { - struct ath_softc *sc = hw->priv; - int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - /* - * As a temporary workaround, assign seq# here; this will likely need - * to be cleaned up to work better with Beacon transmission and virtual - * BSSes. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); - } + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_channel *curchan = hw->conf.channel; + struct ath_vap *avp; + int pos; + DECLARE_MAC_BUF(mac); - /* Add the padding after the header if this is not already done */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - padsize = hdrlen % 4; - if (skb_headroom(skb) < padsize) - return -1; - skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, hdrlen); - } + if (bss_conf->assoc) { + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", + __func__, + bss_conf->aid); - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", - __func__, - skb); + avp = sc->sc_vaps[0]; + if (avp == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", + __func__); + return; + } - 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; - } + /* New association, store aid */ + if (avp->av_opmode == ATH9K_M_STA) { + sc->sc_curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, + sc->sc_curaid); + } - return 0; -} + /* Configure the beacon */ + ath_beacon_config(sc, 0); + sc->sc_flags |= SC_OP_BEACONS; -static void ath9k_stop(struct ieee80211_hw *hw) -{ - struct ath_softc *sc = hw->priv; - int error; + /* Reset rssi stats */ + sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); + /* Update chainmask */ + ath_update_chainmask(sc, bss_conf->assoc_ht); - error = ath_suspend(sc); - if (error) DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Device is no longer present\n", __func__); + "%s: bssid %s aid 0x%x\n", + __func__, + print_mac(mac, sc->sc_curbssid), sc->sc_curaid); - ieee80211_stop_queues(hw); -} + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", + __func__, + curchan->center_freq); -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; + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Invalid channel\n", __func__); + return; + } - /* Support only vap for now */ + 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; - if (sc->sc_nvaps) - return -ENOBUFS; + /* 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__); - switch (conf->type) { - case IEEE80211_IF_TYPE_STA: - ic_opmode = ATH9K_M_STA; - break; - case IEEE80211_IF_TYPE_IBSS: - ic_opmode = ATH9K_M_IBSS; - break; - case IEEE80211_IF_TYPE_AP: - ic_opmode = ATH9K_M_HOSTAP; - break; - default: - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Interface type %d not yet supported\n", - __func__, conf->type); - return -EOPNOTSUPP; + ath_rate_newstate(sc, avp); + /* Update ratectrl about the new state */ + ath_rc_node_update(hw, avp->rc_node); + } else { + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: Bss Info DISSOC\n", __func__); + sc->sc_curaid = 0; } +} - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n", - __func__, - ic_opmode); +void ath_get_beaconconfig(struct ath_softc *sc, + int if_id, + struct ath_beacon_config *conf) +{ + struct ieee80211_hw *hw = sc->hw; - 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; - } + /* fill in beacon config data */ - return 0; + 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; } -static void ath9k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + struct ath_xmit_status *tx_status, struct ath_node *an) { - struct ath_softc *sc = hw->priv; - struct ath_vap *avp; - int error; + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, + "%s: TX complete: skb: %p\n", __func__, skb); - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; + 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; } -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif - - /* Update ratectrl */ - ath_rate_newstate(sc, avp); + if (tx_status->flags & ATH_TX_BAR) { + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + tx_status->flags &= ~ATH_TX_BAR; + } - /* 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); - ath_beacon_return(sc, avp); + 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; } - /* 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; + tx_info->status.retry_count = tx_status->retries; - error = ath_vap_detach(sc, 0); - if (error) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to detach vap, error: %d\n", - __func__, error); + ieee80211_tx_status(hw, skb); + if (an) + ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); } -static int ath9k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +int _ath_rx_indicate(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_recv_status *status, + u16 keyix) { - struct ath_softc *sc = hw->priv; - struct ieee80211_channel *curchan = hw->conf.channel; - int pos; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + 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; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; + /* 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); } - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + /* Prepare rx status */ + ath9k_rx_prepare(sc, skb, status, &rx_status); - if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); + 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; - sc->sc_config.txpowlimit = 2 * conf->power_level; + if (test_bit(keyix, sc->sc_keymap)) + rx_status.flag |= RX_FLAG_DECRYPTED; + } - /* 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__); + 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; } -static int ath9k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +int ath_rx_subframe(struct ath_node *an, + struct sk_buff *skb, + struct ath_recv_status *status) { - struct ath_softc *sc = hw->priv; - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - 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 == IEEE80211_IF_TYPE_AP && - ah->ah_opmode != ATH9K_M_HOSTAP) { - ah->ah_opmode = ATH9K_M_HOSTAP; - ath9k_hw_setopmode(ah); - ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); - /* Request full reset to get hw opmode changed properly */ - sc->sc_flags |= SC_OP_FULL_RESET; - } - - if ((conf->changed & IEEE80211_IFCC_BSSID) && - !is_zero_ether_addr(conf->bssid)) { - switch (vif->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - /* 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; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); + struct ath_softc *sc = an->an_sc; + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_rx_status rx_status; - /* Set aggregation protection mode parameters */ - sc->sc_config.ath_aggr_prot = 0; + /* Prepare rx status */ + ath9k_rx_prepare(sc, skb, status, &rx_status); + if (!(status->flags & ATH_RX_DECRYPT_ERROR)) + rx_status.flag |= RX_FLAG_DECRYPTED; - /* - * 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); + __ieee80211_rx(hw, skb, &rx_status); - /* 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); + return 0; +} - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); +/********************************/ +/* LED functions */ +/********************************/ - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; +static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath_softc *sc = led->sc; - break; - default: - break; - } + switch (brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (led->led_type == ATH_LED_RADIO) ? 1 : + !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + break; + default: + break; } +} - if ((conf->changed & IEEE80211_IFCC_BEACON) && - ((vif->type == IEEE80211_IF_TYPE_IBSS) || - (vif->type == IEEE80211_IF_TYPE_AP))) { - /* - * Allocate and setup the beacon frame. - * - * Stop any previous beacon DMA. This may be - * necessary, for example, when an ibss merge - * causes reconfiguration; we may be called - * with beacon transmission active. - */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); +static int ath_register_led(struct ath_softc *sc, struct ath_led *led, + char *trigger) +{ + int ret; - error = ath_beacon_alloc(sc, 0); - if (error != 0) - return error; + led->sc = sc; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath_led_brightness; - ath_beacon_sync(sc, 0); - } + ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); + if (ret) + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + return ret; +} - /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { - for (i = 0; i < IEEE80211_WEP_NKID; i++) - if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) - ath9k_hw_keysetmac(sc->sc_ah, - (u16)i, - sc->sc_curbssid); +static void ath_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; } - - /* Only legacy IBSS for now */ - if (vif->type == IEEE80211_IF_TYPE_IBSS) - ath_update_chainmask(sc, 0); - - return 0; } -#define SUPPORTED_FILTERS \ - (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_CONTROL | \ - FIF_OTHER_BSS | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_FCSFAIL) - -/* FIXME: sc->sc_full_reset ? */ -static void ath9k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_mc_list *mclist) +static void ath_deinit_leds(struct ath_softc *sc) { - struct ath_softc *sc = hw->priv; - u32 rfilt; + ath_unregister_led(&sc->assoc_led); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath_unregister_led(&sc->tx_led); + ath_unregister_led(&sc->rx_led); + ath_unregister_led(&sc->radio_led); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); +} - changed_flags &= SUPPORTED_FILTERS; - *total_flags &= SUPPORTED_FILTERS; +static void ath_init_leds(struct ath_softc *sc) +{ + char *trigger; + int ret; - sc->rx_filter = *total_flags; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); - } + trigger = ieee80211_get_radio_led_name(sc->hw); + snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), + "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->radio_led, trigger); + sc->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", - __func__, sc->rx_filter); -} + trigger = ieee80211_get_assoc_led_name(sc->hw); + snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), + "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->assoc_led, trigger); + sc->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; -static void ath9k_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - const u8 *addr) -{ - struct ath_softc *sc = hw->priv; - struct ath_node *an; - unsigned long flags; - DECLARE_MAC_BUF(mac); + trigger = ieee80211_get_tx_led_name(sc->hw); + snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), + "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->tx_led, trigger); + sc->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; - spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_irqrestore(&sc->node_lock, flags); + trigger = ieee80211_get_rx_led_name(sc->hw); + snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), + "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->rx_led, trigger); + sc->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; - switch (cmd) { - case STA_NOTIFY_ADD: - spin_lock_irqsave(&sc->node_lock, flags); - if (!an) { - ath_node_attach(sc, (u8 *)addr, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, - print_mac(mac, addr)); - } else { - ath_node_get(sc, (u8 *)addr); - } - spin_unlock_irqrestore(&sc->node_lock, flags); - 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, addr)); - } - break; - default: - break; - } + return; + +fail: + ath_deinit_leds(sc); } -static int ath9k_conf_tx(struct ieee80211_hw *hw, - u16 queue, - const struct ieee80211_tx_queue_params *params) +static int ath_detach(struct ath_softc *sc) { - struct ath_softc *sc = hw->priv; - struct ath9k_tx_queue_info qi; - int ret = 0, qnum; + struct ieee80211_hw *hw = sc->hw; - if (queue >= WME_NUM_AC) - return 0; + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); - qi.tqi_aifs = params->aifs; - qi.tqi_cwmin = params->cw_min; - qi.tqi_cwmax = params->cw_max; - qi.tqi_burstTime = params->txop; - qnum = ath_get_hal_qnum(queue, sc); + /* Deinit LED control */ + ath_deinit_leds(sc); - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 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); + /* Unregister hw */ - ret = ath_txq_update(sc, qnum, &qi); - if (ret) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: TXQ Update failed\n", __func__); + ieee80211_unregister_hw(hw); - return ret; -} + /* unregister Rate control */ + ath_rate_control_unregister(); -static int ath9k_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - const u8 *local_addr, - const u8 *addr, - struct ieee80211_key_conf *key) -{ - struct ath_softc *sc = hw->priv; - int ret = 0; + /* tx/rx cleanup */ - DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__); + ath_rx_cleanup(sc); + ath_tx_cleanup(sc); - 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; - /* 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; - } - break; - case DISABLE_KEY: - ath_key_delete(sc, key); - clear_bit(key->keyidx, sc->sc_keymap); - sc->sc_keytype = ATH9K_CIPHER_CLR; - break; - default: - ret = -EINVAL; - } + /* Deinit */ - return ret; + ath_deinit(sc); + + return 0; } -static void ath9k_ht_conf(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) +static int ath_attach(u16 devid, + struct ath_softc *sc) { -#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; + struct ieee80211_hw *hw = sc->hw; + int error = 0; - 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; + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); - 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); + error = ath_init(devid, sc); + if (error != 0) + return error; - } + /* Init nodes */ -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT -} + INIT_LIST_HEAD(&sc->node_list); + spin_lock_init(&sc->node_lock); -static void ath9k_bss_assoc_info(struct ath_softc *sc, - 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); + /* get mac address from hardware and set in mac80211 */ - if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", - __func__, - bss_conf->aid); + SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } + /* setup channels and rates */ - /* New association, store aid */ - if (avp->av_opmode == ATH9K_M_STA) { - sc->sc_curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); - } + sc->sbands[IEEE80211_BAND_2GHZ].channels = + sc->channels[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = + sc->rates[IEEE80211_BAND_2GHZ]; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - /* Configure the beacon */ - ath_beacon_config(sc, 0); - sc->sc_flags |= SC_OP_BEACONS; + 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); - /* Reset rssi stats */ - sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; - /* Update chainmask */ - ath_update_chainmask(sc, bss_conf->assoc_ht); + 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; - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", - __func__, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + 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); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; + } - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid channel\n", __func__); - return; - } + /* FIXME: Have to figure out proper hw init values later */ - 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; + hw->queues = 4; + hw->ampdu_queues = 1; - /* 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__); + /* 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; + } - ath_rate_newstate(sc, avp); - /* Update ratectrl about the new state */ - ath_rc_node_update(hw, avp->rc_node); - } else { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Bss Info DISSOC\n", __func__); - sc->sc_curaid = 0; + error = ieee80211_register_hw(hw); + if (error != 0) { + ath_rate_control_unregister(); + goto bad; } + + /* Initialize LED control */ + ath_init_leds(sc); + + /* 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; + + return 0; +detach: + ath_detach(sc); +bad: + return error; } -static void ath9k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) +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; - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n", - __func__, - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - sc->sc_flags |= SC_OP_PREAMBLE_SHORT; - else - sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; - } + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " + "initial channel: %d MHz\n", __func__, curchan->center_freq); - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n", - __func__, - bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && - hw->conf.channel->band != IEEE80211_BAND_5GHZ) - sc->sc_flags |= SC_OP_PROTECT_ENABLE; - else - sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; - } + /* setup initial channel */ - 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); + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); + return -EINVAL; } - if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", - __func__, - bss_conf->assoc); - ath9k_bss_assoc_info(sc, bss_conf); + sc->sc_ah->ah_channels[pos].chanmode = + (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; + + /* open ath_dev */ + error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); + if (error) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to complete ath_open\n", __func__); + return error; } + + ieee80211_wake_queues(hw); + return 0; } -static u64 ath9k_get_tsf(struct ieee80211_hw *hw) +static int ath9k_tx(struct ieee80211_hw *hw, + struct sk_buff *skb) { - u64 tsf; struct ath_softc *sc = hw->priv; - struct ath_hal *ah = sc->sc_ah; + int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - tsf = ath9k_hw_gettsf64(ah); + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } - return tsf; + /* Add the padding after the header if this is not already done */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + padsize = hdrlen % 4; + if (skb_headroom(skb) < padsize) + return -1; + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } + + DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", + __func__, + skb); + + 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; + } + + return 0; } -static void ath9k_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - struct ath_hal *ah = sc->sc_ah; + int error; - ath9k_hw_reset_tsf(ah); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); + + error = ath_suspend(sc); + if (error) + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: Device is no longer present\n", __func__); + + ieee80211_stop_queues(hw); } -static int ath9k_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, - u16 tid, - u16 *ssn) +static int ath9k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - int ret = 0; + int error, ic_opmode = 0; - switch (action) { - case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, addr, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start RX aggregation\n", - __func__); - break; - case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, addr, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop RX aggregation\n", - __func__); + /* Support only vap for now */ + + if (sc->sc_nvaps) + return -ENOBUFS; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + ic_opmode = ATH9K_M_STA; break; - case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, addr, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start TX aggregation\n", - __func__); - else - ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + case IEEE80211_IF_TYPE_IBSS: + ic_opmode = ATH9K_M_IBSS; break; - case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, addr, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop TX aggregation\n", - __func__); - - ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + case IEEE80211_IF_TYPE_AP: + ic_opmode = ATH9K_M_HOSTAP; break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unknown AMPDU action\n", __func__); + "%s: Interface type %d not yet supported\n", + __func__, conf->type); + return -EOPNOTSUPP; } - return ret; + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n", + __func__, + ic_opmode); + + error = ath_vap_attach(sc, 0, conf->vif, ic_opmode); + if (error) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to attach vap, error: %d\n", + __func__, error); + return error; + } + + return 0; } -static struct ieee80211_ops ath9k_ops = { - .tx = ath9k_tx, - .start = ath9k_start, - .stop = ath9k_stop, - .add_interface = ath9k_add_interface, - .remove_interface = ath9k_remove_interface, - .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 -}; - -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) +static void ath9k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_softc *sc = hw->priv; + struct ath_vap *avp; + int error; - DPRINTF(sc, ATH_DBG_XMIT, - "%s: TX complete: skb: %p\n", __func__, skb); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); - 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; + avp = sc->sc_vaps[0]; + if (avp == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", + __func__); + return; } - if (tx_status->flags & ATH_TX_BAR) { - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - tx_status->flags &= ~ATH_TX_BAR; - } +#ifdef CONFIG_SLOW_ANT_DIV + ath_slow_ant_div_stop(&sc->sc_antdiv); +#endif - 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; + /* 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); + ath_beacon_return(sc, avp); } - tx_info->status.retry_count = tx_status->retries; + /* 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; - ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); + error = ath_vap_detach(sc, 0); + if (error) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to detach vap, error: %d\n", + __func__, error); } -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) +static int ath9k_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) { - 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; - } + struct ath_softc *sc = hw->priv; + struct ieee80211_channel *curchan = hw->conf.channel; + int pos; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr2); - spin_unlock_bh(&sc->node_lock); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", + __func__, + curchan->center_freq); - if (an) { - ath_rx_input(sc, an, - hw->conf.ht_conf.ht_supported, - skb, status, &st); + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); + return -EINVAL; } - if (!an || (st != ATH_RX_CONSUMED)) - __ieee80211_rx(hw, skb, &rx_status); - return 0; -} + sc->sc_ah->ah_channels[pos].chanmode = + (curchan->band == IEEE80211_BAND_2GHZ) ? + CHANNEL_G : CHANNEL_A; -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; + if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan); - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - if (!(status->flags & ATH_RX_DECRYPT_ERROR)) - rx_status.flag |= RX_FLAG_DECRYPTED; + sc->sc_config.txpowlimit = 2 * conf->power_level; - __ieee80211_rx(hw, skb, &rx_status); + /* set h/w channel */ + if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) + DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", + __func__); return 0; } -/********************************/ -/* LED functions */ -/********************************/ - -static void ath_led_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) +static int ath9k_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { - struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); - struct ath_softc *sc = led->sc; + struct ath_softc *sc = hw->priv; + struct ath_hal *ah = sc->sc_ah; + struct ath_vap *avp; + u32 rfilt = 0; + int error, i; + DECLARE_MAC_BUF(mac); - switch (brightness) { - case LED_OFF: - if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, - (led->led_type == ATH_LED_RADIO) ? 1 : - !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) - sc->sc_flags |= SC_OP_LED_ASSOCIATED; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); - break; - default: - break; + avp = sc->sc_vaps[0]; + if (avp == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", + __func__); + return -EINVAL; } -} -static int ath_register_led(struct ath_softc *sc, struct ath_led *led, - char *trigger) -{ - int ret; + /* TODO: Need to decide which hw opmode to use for multi-interface + * cases */ + if (vif->type == IEEE80211_IF_TYPE_AP && + ah->ah_opmode != ATH9K_M_HOSTAP) { + ah->ah_opmode = ATH9K_M_HOSTAP; + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); + /* Request full reset to get hw opmode changed properly */ + sc->sc_flags |= SC_OP_FULL_RESET; + } - led->sc = sc; - led->led_cdev.name = led->name; - led->led_cdev.default_trigger = trigger; - led->led_cdev.brightness_set = ath_led_brightness; + if ((conf->changed & IEEE80211_IFCC_BSSID) && + !is_zero_ether_addr(conf->bssid)) { + switch (vif->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + /* Update ratectrl about the new state */ + ath_rate_newstate(sc, avp); - ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); - if (ret) - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to register led:%s", led->name); - else - led->registered = 1; - return ret; -} + /* Set BSSID */ + memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); + sc->sc_curaid = 0; + ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, + sc->sc_curaid); -static void ath_unregister_led(struct ath_led *led) -{ - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } -} + /* Set aggregation protection mode parameters */ + sc->sc_config.ath_aggr_prot = 0; -static void ath_deinit_leds(struct ath_softc *sc) -{ - ath_unregister_led(&sc->assoc_led); - sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; - ath_unregister_led(&sc->tx_led); - ath_unregister_led(&sc->rx_led); - ath_unregister_led(&sc->radio_led); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -} + /* + * 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); -static void ath_init_leds(struct ath_softc *sc) -{ - char *trigger; - int ret; + /* 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); - /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + 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); - trigger = ieee80211_get_radio_led_name(sc->hw); - snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), - "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->radio_led, trigger); - sc->radio_led.led_type = ATH_LED_RADIO; - if (ret) - goto fail; + /* need to reconfigure the beacon */ + sc->sc_flags &= ~SC_OP_BEACONS ; - trigger = ieee80211_get_assoc_led_name(sc->hw); - snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), - "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->assoc_led, trigger); - sc->assoc_led.led_type = ATH_LED_ASSOC; - if (ret) - goto fail; + break; + default: + break; + } + } - trigger = ieee80211_get_tx_led_name(sc->hw); - snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), - "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->tx_led, trigger); - sc->tx_led.led_type = ATH_LED_TX; - if (ret) - goto fail; + if ((conf->changed & IEEE80211_IFCC_BEACON) && + ((vif->type == IEEE80211_IF_TYPE_IBSS) || + (vif->type == IEEE80211_IF_TYPE_AP))) { + /* + * Allocate and setup the beacon frame. + * + * Stop any previous beacon DMA. This may be + * necessary, for example, when an ibss merge + * causes reconfiguration; we may be called + * with beacon transmission active. + */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); - trigger = ieee80211_get_rx_led_name(sc->hw); - snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), - "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); - ret = ath_register_led(sc, &sc->rx_led, trigger); - sc->rx_led.led_type = ATH_LED_RX; - if (ret) - goto fail; + error = ath_beacon_alloc(sc, 0); + if (error != 0) + return error; - return; + ath_beacon_sync(sc, 0); + } -fail: - ath_deinit_leds(sc); -} + /* Check for WLAN_CAPABILITY_PRIVACY ? */ + if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { + for (i = 0; i < IEEE80211_WEP_NKID; i++) + if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) + ath9k_hw_keysetmac(sc->sc_ah, + (u16)i, + sc->sc_curbssid); + } -static int ath_detach(struct ath_softc *sc) -{ - struct ieee80211_hw *hw = sc->hw; + /* Only legacy IBSS for now */ + if (vif->type == IEEE80211_IF_TYPE_IBSS) + ath_update_chainmask(sc, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + return 0; +} - /* Deinit LED control */ - ath_deinit_leds(sc); +#define SUPPORTED_FILTERS \ + (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_CONTROL | \ + FIF_OTHER_BSS | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_FCSFAIL) - /* Unregister hw */ +/* FIXME: sc->sc_full_reset ? */ +static void ath9k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_mc_list *mclist) +{ + struct ath_softc *sc = hw->priv; + u32 rfilt; - ieee80211_unregister_hw(hw); + changed_flags &= SUPPORTED_FILTERS; + *total_flags &= SUPPORTED_FILTERS; - /* unregister Rate control */ - ath_rate_control_unregister(); + sc->rx_filter = *total_flags; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(sc->sc_ah, rfilt); - /* tx/rx cleanup */ + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); + } - ath_rx_cleanup(sc); - ath_tx_cleanup(sc); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", + __func__, sc->rx_filter); +} - /* Deinit */ +static void ath9k_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + const u8 *addr) +{ + struct ath_softc *sc = hw->priv; + struct ath_node *an; + unsigned long flags; + DECLARE_MAC_BUF(mac); - ath_deinit(sc); + spin_lock_irqsave(&sc->node_lock, flags); + an = ath_node_find(sc, (u8 *) addr); + spin_unlock_irqrestore(&sc->node_lock, flags); - return 0; + switch (cmd) { + case STA_NOTIFY_ADD: + spin_lock_irqsave(&sc->node_lock, flags); + if (!an) { + ath_node_attach(sc, (u8 *)addr, 0); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", + __func__, + print_mac(mac, addr)); + } else { + ath_node_get(sc, (u8 *)addr); + } + spin_unlock_irqrestore(&sc->node_lock, flags); + 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, addr)); + } + break; + default: + break; + } } -static int ath_attach(u16 devid, - struct ath_softc *sc) +static int ath9k_conf_tx(struct ieee80211_hw *hw, + u16 queue, + const struct ieee80211_tx_queue_params *params) { - struct ieee80211_hw *hw = sc->hw; - int error = 0; + struct ath_softc *sc = hw->priv; + struct ath9k_tx_queue_info qi; + int ret = 0, qnum; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); + if (queue >= WME_NUM_AC) + return 0; - error = ath_init(devid, sc); - if (error != 0) - return error; + qi.tqi_aifs = params->aifs; + qi.tqi_cwmin = params->cw_min; + qi.tqi_cwmax = params->cw_max; + qi.tqi_burstTime = params->txop; + qnum = ath_get_hal_qnum(queue, sc); - /* Init nodes */ + DPRINTF(sc, ATH_DBG_CONFIG, + "%s: 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); - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); + ret = ath_txq_update(sc, qnum, &qi); + if (ret) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: TXQ Update failed\n", __func__); - /* get mac address from hardware and set in mac80211 */ + return ret; +} - SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); +static int ath9k_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + const u8 *local_addr, + const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct ath_softc *sc = hw->priv; + int ret = 0; - /* setup channels and rates */ + DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__); - sc->sbands[IEEE80211_BAND_2GHZ].channels = - sc->channels[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = - sc->rates[IEEE80211_BAND_2GHZ]; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + 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; + /* 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; + } + break; + case DISABLE_KEY: + ath_key_delete(sc, key); + clear_bit(key->keyidx, sc->sc_keymap); + sc->sc_keytype = ATH9K_CIPHER_CLR; + break; + default: + ret = -EINVAL; + } - 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); + return ret; +} - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; +static void ath9k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct ath_softc *sc = hw->priv; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = - sc->channels[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = - IEEE80211_BAND_5GHZ; + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n", + __func__, + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + sc->sc_flags |= SC_OP_PREAMBLE_SHORT; + else + sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; + } - 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); + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n", + __func__, + bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && + hw->conf.channel->band != IEEE80211_BAND_5GHZ) + sc->sc_flags |= SC_OP_PROTECT_ENABLE; + else + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; + } - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + 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); } - /* FIXME: Have to figure out proper hw init values later */ + if (changed & BSS_CHANGED_ASSOC) { + DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", + __func__, + bss_conf->assoc); + ath9k_bss_assoc_info(sc, bss_conf); + } +} - hw->queues = 4; - hw->ampdu_queues = 1; +static u64 ath9k_get_tsf(struct ieee80211_hw *hw) +{ + u64 tsf; + struct ath_softc *sc = hw->priv; + struct ath_hal *ah = sc->sc_ah; - /* 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; - } + tsf = ath9k_hw_gettsf64(ah); - error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - goto bad; - } + return tsf; +} - /* Initialize LED control */ - ath_init_leds(sc); +static void ath9k_reset_tsf(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + struct ath_hal *ah = sc->sc_ah; - /* initialize tx/rx engine */ + ath9k_hw_reset_tsf(ah); +} - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto detach; +static int ath9k_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, + u16 tid, + u16 *ssn) +{ + struct ath_softc *sc = hw->priv; + int ret = 0; - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto detach; + switch (action) { + case IEEE80211_AMPDU_RX_START: + ret = ath_rx_aggr_start(sc, addr, tid, ssn); + if (ret < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to start RX aggregation\n", + __func__); + break; + case IEEE80211_AMPDU_RX_STOP: + ret = ath_rx_aggr_stop(sc, 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, addr, tid, ssn); + if (ret < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to start TX aggregation\n", + __func__); + else + ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP: + ret = ath_tx_aggr_stop(sc, addr, tid); + if (ret < 0) + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to stop TX aggregation\n", + __func__); - return 0; -detach: - ath_detach(sc); -bad: - return error; + ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + break; + default: + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unknown AMPDU action\n", __func__); + } + + return ret; } +static struct ieee80211_ops ath9k_ops = { + .tx = ath9k_tx, + .start = ath9k_start, + .stop = ath9k_stop, + .add_interface = ath9k_add_interface, + .remove_interface = ath9k_remove_interface, + .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 +}; + static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *mem; -- cgit v1.2.3 From 500c064d3a5f9c8aa604ef63a1346ab70eed443a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Sep 2008 18:50:17 +0530 Subject: ath9k: Add RF kill support RF kill support is enabled when CONFIG_RFKILL is set. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 7 +- drivers/net/wireless/ath9k/core.h | 16 +++ drivers/net/wireless/ath9k/hw.c | 70 +++++----- drivers/net/wireless/ath9k/main.c | 266 +++++++++++++++++++++++++++++++++++++ 4 files changed, 327 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 28b8d84f49b..0e897c27685 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -798,10 +798,11 @@ struct ath_hal { struct ath9k_channel *ah_curchan; u32 ah_nchan; - u16 ah_rfsilent; - bool ah_rfkillEnabled; bool ah_isPciExpress; u16 ah_txTrigLevel; + u16 ah_rfsilent; + u32 ah_rfkill_gpio; + u32 ah_rfkill_polarity; #ifndef ATH_NF_PER_CHAN struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; @@ -1003,4 +1004,6 @@ bool ath9k_get_channel_edges(struct ath_hal *ah, 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/core.h b/drivers/net/wireless/ath9k/core.h index 1faa1effa02..b66de29cf66 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "ath9k.h" #include "rc.h" @@ -823,6 +824,15 @@ struct ath_led { bool registered; }; +/* Rfkill */ +#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ + +struct ath_rfkill { + struct rfkill *rfkill; + struct delayed_work rfkill_poll; + char rfkill_name[32]; +}; + /********************/ /* Main driver core */ /********************/ @@ -906,6 +916,9 @@ struct ath_ht_info { #define SC_OP_PROTECT_ENABLE BIT(8) #define SC_OP_RXFLUSH BIT(9) #define SC_OP_LED_ASSOCIATED BIT(10) +#define SC_OP_RFKILL_REGISTERED BIT(11) +#define SC_OP_RFKILL_SW_BLOCKED BIT(12) +#define SC_OP_RFKILL_HW_BLOCKED BIT(13) struct ath_softc { struct ieee80211_hw *hw; @@ -1015,6 +1028,9 @@ struct ath_softc { struct ath_led assoc_led; struct ath_led tx_led; struct ath_led rx_led; + + /* Rfkill */ + struct ath_rfkill rf_kill; }; int ath_init(u16 devid, struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 4ccbbc07cf1..0251e59f2f8 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2821,7 +2821,38 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) AR_GPIO_BIT(gpio)); } -static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 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; @@ -3034,17 +3065,17 @@ static bool ath9k_hw_fill_cap_info(struct ath_hal *ah) 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) { - ahp->ah_gpioSelect = + ah->ah_rfkill_gpio = MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); - ahp->ah_polarity = + ah->ah_rfkill_polarity = MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true, - NULL); 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) || @@ -5961,6 +5992,10 @@ 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 (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + ath9k_enable_rfkill(ah); +#endif ath9k_hw_init_user_settings(ah); REG_WRITE(ah, AR_STA_ID1, @@ -6490,31 +6525,6 @@ ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) return true; } -#ifdef CONFIG_ATH9K_RFKILL -static void ath9k_enable_rfkill(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(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, ahp->ah_gpioSelect); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); - - if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) { - - ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect, - !ahp->ah_gpioBit); - } else { - ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect, - ahp->ah_gpioBit); - } -} -#endif - void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 07e5b5d877b..b493dff5643 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -672,6 +672,209 @@ fail: ath_deinit_leds(sc); } +#ifdef CONFIG_RFKILL +/*******************/ +/* Rfkill */ +/*******************/ + +static void ath_radio_enable(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, 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 channel %u (%uMhz) " + "flags 0x%x hal status %u\n", __func__, + ath9k_hw_mhz2ieee(ah, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags), + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, status); + } + spin_unlock_bh(&sc->sc_resetlock); + + ath_update_txpow(sc); + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to restart recv logic\n", __func__); + return; + } + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + + /* Re-Enable interrupts */ + ath9k_hw_set_interrupts(ah, sc->sc_imask); + + /* Enable LED */ + ath9k_hw_cfg_output(ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); + + ieee80211_wake_queues(sc->hw); +} + +static void ath_radio_disable(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + + + ieee80211_stop_queues(sc->hw); + + /* Disable LED */ + ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); + ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); + + /* Disable interrupts */ + ath9k_hw_set_interrupts(ah, 0); + + ath_draintxq(sc, false); /* clear pending tx frames */ + ath_stoprecv(sc); /* turn off frame recv */ + ath_flushrecv(sc); /* flush recv queue */ + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, 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 channel %u (%uMhz) " + "flags 0x%x hal status %u\n", __func__, + ath9k_hw_mhz2ieee(ah, + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags), + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, status); + } + spin_unlock_bh(&sc->sc_resetlock); + + ath9k_hw_phy_disable(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); +} + +static bool ath_is_rfkill_set(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + + return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) == + ah->ah_rfkill_polarity; +} + +/* h/w rfkill poll function */ +static void ath_rfkill_poll(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + rf_kill.rfkill_poll.work); + bool radio_on; + + if (sc->sc_flags & SC_OP_INVALID) + return; + + radio_on = !ath_is_rfkill_set(sc); + + /* + * enable/disable radio only when there is a + * state change in RF switch + */ + if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { + enum rfkill_state state; + + if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { + state = radio_on ? RFKILL_STATE_SOFT_BLOCKED + : RFKILL_STATE_HARD_BLOCKED; + } else if (radio_on) { + ath_radio_enable(sc); + state = RFKILL_STATE_UNBLOCKED; + } else { + ath_radio_disable(sc); + state = RFKILL_STATE_HARD_BLOCKED; + } + + if (state == RFKILL_STATE_HARD_BLOCKED) + sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; + else + sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; + + rfkill_force_state(sc->rf_kill.rfkill, state); + } + + queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, + msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); +} + +/* s/w rfkill handler */ +static int ath_sw_toggle_radio(void *data, enum rfkill_state state) +{ + struct ath_softc *sc = data; + + switch (state) { + case RFKILL_STATE_SOFT_BLOCKED: + if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | + SC_OP_RFKILL_SW_BLOCKED))) + ath_radio_disable(sc); + sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; + return 0; + case RFKILL_STATE_UNBLOCKED: + if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { + 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"); + return -EPERM; + } + ath_radio_enable(sc); + } + return 0; + default: + return -EINVAL; + } +} + +/* Init s/w rfkill */ +static int ath_init_sw_rfkill(struct ath_softc *sc) +{ + sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), + RFKILL_TYPE_WLAN); + if (!sc->rf_kill.rfkill) { + DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); + return -ENOMEM; + } + + snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), + "ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy)); + sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; + sc->rf_kill.rfkill->data = sc; + sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; + sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; + sc->rf_kill.rfkill->user_claim_unsupported = 1; + + return 0; +} + +/* Deinitialize rfkill */ +static void ath_deinit_rfkill(struct ath_softc *sc) +{ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); + + if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { + rfkill_unregister(sc->rf_kill.rfkill); + sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; + sc->rf_kill.rfkill = NULL; + } +} +#endif /* CONFIG_RFKILL */ + static int ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; @@ -681,6 +884,11 @@ static int ath_detach(struct ath_softc *sc) /* Deinit LED control */ ath_deinit_leds(sc); +#ifdef CONFIG_RFKILL + /* deinit rfkill */ + ath_deinit_rfkill(sc); +#endif + /* Unregister hw */ ieee80211_unregister_hw(hw); @@ -777,6 +985,16 @@ static int ath_attach(u16 devid, /* Initialize LED control */ ath_init_leds(sc); +#ifdef CONFIG_RFKILL + /* 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); + + /* Initialize s/w rfkill */ + if (ath_init_sw_rfkill(sc)) + goto detach; +#endif + /* initialize tx/rx engine */ error = ath_tx_init(sc, ATH_TXBUF); @@ -822,6 +1040,33 @@ static int ath9k_start(struct ieee80211_hw *hw) return error; } +#ifdef CONFIG_RFKILL + /* Start rfkill polling */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); + + if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { + if (rfkill_register(sc->rf_kill.rfkill)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to register rfkill\n"); + rfkill_free(sc->rf_kill.rfkill); + + /* Deinitialize the device */ + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + ath_detach(sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(hw); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } +#endif + ieee80211_wake_queues(hw); return 0; } @@ -883,6 +1128,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) "%s: Device is no longer present\n", __func__); ieee80211_stop_queues(hw); + +#ifdef CONFIG_RFKILL + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -1554,6 +1804,12 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) struct ath_softc *sc = hw->priv; ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + +#ifdef CONFIG_RFKILL + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); +#endif + pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, 3); @@ -1586,6 +1842,16 @@ 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 + /* + * check the h/w rfkill state on resume + * and start the rfkill poll timer + */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); +#endif + return 0; } -- cgit v1.2.3 From 39fcf7a315e098430e878a5c0c4d39561c93ebf6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Sep 2008 12:49:00 -0400 Subject: libertas: convert SNMP_MIB to a direct command And support setting both long and short retries independently. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 6 +- drivers/net/wireless/libertas/cmd.c | 180 ++++++++++++++------------------ drivers/net/wireless/libertas/cmd.h | 4 + drivers/net/wireless/libertas/cmdresp.c | 46 -------- drivers/net/wireless/libertas/defs.h | 27 ----- drivers/net/wireless/libertas/dev.h | 3 - drivers/net/wireless/libertas/host.h | 24 +++-- drivers/net/wireless/libertas/hostcmd.h | 5 +- drivers/net/wireless/libertas/wext.c | 141 +++++++++++++------------ 9 files changed, 172 insertions(+), 264 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 4ddf44b2758..92be60415d0 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -823,11 +823,7 @@ static int assoc_helper_mode(struct lbs_private *priv, } priv->mode = assoc_req->mode; - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_INFRASTRUCTURE_MODE, - /* Shoot me now */ (void *) (size_t) assoc_req->mode); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b57625a3802..aee19fa844e 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -480,124 +480,103 @@ int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, return ret; } -static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, - struct cmd_ds_command *cmd, - int cmd_action, - int cmd_oid, void *pdata_buf) +/** + * @brief Set an SNMP MIB value + * + * @param priv A pointer to struct lbs_private structure + * @param oid The OID to set in the firmware + * @param val Value to set the OID to + * + * @return 0 on success, error on failure + */ +int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) { - struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib; - u8 ucTemp; + struct cmd_ds_802_11_snmp_mib cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); - - cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB); - cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN); - - switch (cmd_oid) { - case OID_802_11_INFRASTRUCTURE_MODE: - { - u8 mode = (u8) (size_t) pdata_buf; - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8)); - if (mode == IW_MODE_ADHOC) { - ucTemp = SNMP_MIB_VALUE_ADHOC; - } else { - /* Infra and Auto modes */ - ucTemp = SNMP_MIB_VALUE_INFRA; - } - - memmove(pSNMPMIB->value, &ucTemp, sizeof(u8)); + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.oid = cpu_to_le16((u16) oid); + switch (oid) { + case SNMP_MIB_OID_BSS_TYPE: + cmd.bufsize = cpu_to_le16(sizeof(u8)); + cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1; + break; + case SNMP_MIB_OID_11D_ENABLE: + case SNMP_MIB_OID_FRAG_THRESHOLD: + case SNMP_MIB_OID_RTS_THRESHOLD: + case SNMP_MIB_OID_SHORT_RETRY_LIMIT: + case SNMP_MIB_OID_LONG_RETRY_LIMIT: + cmd.bufsize = cpu_to_le16(sizeof(u16)); + *((__le16 *)(&cmd.value)) = cpu_to_le16(val); break; + default: + lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid); + ret = -EINVAL; + goto out; } - case OID_802_11D_ENABLE: - { - u32 ulTemp; - - pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I); - - if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - ulTemp = *(u32 *)pdata_buf; - *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) ulTemp); - } - break; - } - - case OID_802_11_FRAGMENTATION_THRESHOLD: - { - u32 ulTemp; - - pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I); + lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n", + le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val); - if (cmd_action == CMD_ACT_GET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); - } else if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - ulTemp = *((u32 *) pdata_buf); - *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) ulTemp); + ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd); - } - - break; - } +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} - case OID_802_11_RTS_THRESHOLD: - { +/** + * @brief Get an SNMP MIB value + * + * @param priv A pointer to struct lbs_private structure + * @param oid The OID to retrieve from the firmware + * @param out_val Location for the returned value + * + * @return 0 on success, error on failure + */ +int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) +{ + struct cmd_ds_802_11_snmp_mib cmd; + int ret; - u32 ulTemp; - pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I); + lbs_deb_enter(LBS_DEB_CMD); - if (cmd_action == CMD_ACT_GET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); - } else if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - ulTemp = *((u32 *)pdata_buf); - *(__le16 *)(pSNMPMIB->value) = - cpu_to_le16((u16) ulTemp); + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET); + cmd.oid = cpu_to_le16(oid); - } - break; - } - case OID_802_11_TX_RETRYCOUNT: - pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I); - - if (cmd_action == CMD_ACT_GET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); - } else if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); - pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); - *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) priv->txretrycount); - } + ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd); + if (ret) + goto out; + switch (le16_to_cpu(cmd.bufsize)) { + case sizeof(u8): + if (oid == SNMP_MIB_OID_BSS_TYPE) { + if (cmd.value[0] == 2) + *out_val = IW_MODE_ADHOC; + else + *out_val = IW_MODE_INFRA; + } else + *out_val = cmd.value[0]; + break; + case sizeof(u16): + *out_val = le16_to_cpu(*((__le16 *)(&cmd.value))); break; default: + lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n", + oid, le16_to_cpu(cmd.bufsize)); break; } - lbs_deb_cmd( - "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n", - le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), - le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result)); - - lbs_deb_cmd( - "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n", - le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid), - le16_to_cpu(pSNMPMIB->bufsize), - le16_to_cpu(*(__le16 *) pSNMPMIB->value)); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; } /** @@ -1409,11 +1388,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_SNMP_MIB: - ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr, - cmd_action, cmd_oid, pdata_buf); - break; - case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 336a181d857..d002160f597 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -73,4 +73,8 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); +int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); + +int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); + #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index f305b049b58..bcf2a9756fb 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -146,48 +146,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv, return ret; } -static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; - u16 oid = le16_to_cpu(smib->oid); - u16 querytype = le16_to_cpu(smib->querytype); - - lbs_deb_enter(LBS_DEB_CMD); - - lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid, - querytype); - lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize)); - - if (querytype == CMD_ACT_GET) { - switch (oid) { - case FRAGTHRESH_I: - priv->fragthsd = - le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", - priv->fragthsd); - break; - case RTSTHRESH_I: - priv->rtsthsd = - le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", - priv->rtsthsd); - break; - case SHORT_RETRYLIM_I: - priv->txretrycount = - le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", - priv->rtsthsd); - break; - default: - break; - } - } - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -258,10 +216,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_SNMP_MIB): - ret = lbs_ret_802_11_snmp_mib(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index c89d7a1041a..58d11a35e61 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -352,27 +352,6 @@ enum mv_ms_type { MVMS_EVENT }; -/** SNMP_MIB_INDEX_e */ -enum SNMP_MIB_INDEX_e { - DESIRED_BSSTYPE_I = 0, - OP_RATESET_I, - BCNPERIOD_I, - DTIMPERIOD_I, - ASSOCRSP_TIMEOUT_I, - RTSTHRESH_I, - SHORT_RETRYLIM_I, - LONG_RETRYLIM_I, - FRAGTHRESH_I, - DOT11D_I, - DOT11H_I, - MANUFID_I, - PRODID_I, - MANUF_OUI_I, - MANUF_NAME_I, - MANUF_PRODNAME_I, - MANUF_PRODVER_I, -}; - /** KEY_TYPE_ID */ enum KEY_TYPE_ID { KEY_TYPE_ID_WEP = 0, @@ -387,12 +366,6 @@ enum KEY_INFO_WPA { KEY_INFO_WPA_ENABLED = 0x04 }; -/** SNMP_MIB_VALUE_e */ -enum SNMP_MIB_VALUE_e { - SNMP_MIB_VALUE_INFRA = 1, - SNMP_MIB_VALUE_ADHOC -}; - /* Default values for fwt commands. */ #define FWT_DEFAULT_METRIC 0 #define FWT_DEFAULT_DIR 1 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index fd59e181646..acb889e2590 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -240,9 +240,6 @@ struct lbs_private { uint16_t enablehwauto; uint16_t ratebitmap; - u32 fragthsd; - u32 rtsthsd; - u8 txretrycount; /** Tx-related variables (for single packet tx) */ diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index a916bb9bd5d..5004d7679c0 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -9,17 +9,6 @@ #define DEFAULT_AD_HOC_CHANNEL 6 #define DEFAULT_AD_HOC_CHANNEL_A 36 -/** IEEE 802.11 oids */ -#define OID_802_11_SSID 0x00008002 -#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 -#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 -#define OID_802_11_RTS_THRESHOLD 0x0000800A -#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D -#define OID_802_11_SUPPORTED_RATES 0x0000800E -#define OID_802_11_STATISTICS 0x00008012 -#define OID_802_11_TX_RETRYCOUNT 0x0000801D -#define OID_802_11D_ENABLE 0x00008020 - #define CMD_OPTION_WAITFORRSP 0x0002 /** Host command IDs */ @@ -191,6 +180,19 @@ #define CMD_WAKE_METHOD_COMMAND_INT 0x0001 #define CMD_WAKE_METHOD_GPIO 0x0002 +/* Object IDs for CMD_802_11_SNMP_MIB */ +#define SNMP_MIB_OID_BSS_TYPE 0x0000 +#define SNMP_MIB_OID_OP_RATE_SET 0x0001 +#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */ +#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */ +#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */ +#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005 +#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006 +#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007 +#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008 +#define SNMP_MIB_OID_11D_ENABLE 0x0009 +#define SNMP_MIB_OID_11H_ENABLE 0x000A + /* Define action or option for CMD_BT_ACCESS */ enum cmd_bt_access_opts { /* The bt commands start at 5 instead of 1 because the old dft commands diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index f2f92e237c4..d9f9a12a739 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -297,7 +297,9 @@ struct cmd_ds_802_11_get_stat { }; struct cmd_ds_802_11_snmp_mib { - __le16 querytype; + struct cmd_header hdr; + + __le16 action; __le16 oid; __le16 bufsize; u8 value[128]; @@ -716,7 +718,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; - struct cmd_ds_802_11_snmp_mib smib; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_rssi rssi; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index e8cadad2c86..d86fcf0a5ad 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -266,21 +266,17 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, { int ret = 0; struct lbs_private *priv = dev->priv; - u32 rthr = vwrq->value; + u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); - if (vwrq->disabled) { - priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; - } else { - if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) - return -EINVAL; - priv->rtsthsd = rthr; - } + if (vwrq->disabled) + val = MRVDRV_RTS_MAX_VALUE; + + if (val < MRVDRV_RTS_MIN_VALUE || val > MRVDRV_RTS_MAX_VALUE) + return -EINVAL; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_SET, CMD_OPTION_WAITFORRSP, - OID_802_11_RTS_THRESHOLD, &rthr); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -289,21 +285,19 @@ 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) { - int ret = 0; struct lbs_private *priv = dev->priv; + int ret = 0; + u16 val = 0; lbs_deb_enter(LBS_DEB_WEXT); - priv->rtsthsd = 0; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_GET, CMD_OPTION_WAITFORRSP, - OID_802_11_RTS_THRESHOLD, NULL); + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); if (ret) goto out; - vwrq->value = priv->rtsthsd; - vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) - || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); + vwrq->value = val; + vwrq->disabled = ((val < MRVDRV_RTS_MIN_VALUE) + || (val > MRVDRV_RTS_MAX_VALUE)); vwrq->fixed = 1; out: @@ -314,24 +308,19 @@ out: static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; - u32 fthr = vwrq->value; struct lbs_private *priv = dev->priv; + int ret = 0; + u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); - if (vwrq->disabled) { - priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; - } else { - if (fthr < MRVDRV_FRAG_MIN_VALUE - || fthr > MRVDRV_FRAG_MAX_VALUE) - return -EINVAL; - priv->fragthsd = fthr; - } + if (vwrq->disabled) + val = MRVDRV_FRAG_MAX_VALUE; + + if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE) + return -EINVAL; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_SET, CMD_OPTION_WAITFORRSP, - OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -340,22 +329,19 @@ 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) { - int ret = 0; struct lbs_private *priv = dev->priv; + int ret = 0; + u16 val = 0; lbs_deb_enter(LBS_DEB_WEXT); - priv->fragthsd = 0; - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - CMD_ACT_GET, CMD_OPTION_WAITFORRSP, - OID_802_11_FRAGMENTATION_THRESHOLD, NULL); + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); if (ret) goto out; - vwrq->value = priv->fragthsd; - vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) - || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); + vwrq->value = val; + vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE) + || (val > MRVDRV_FRAG_MAX_VALUE)); vwrq->fixed = 1; out: @@ -382,7 +368,7 @@ static int mesh_wlan_get_mode(struct net_device *dev, { lbs_deb_enter(LBS_DEB_WEXT); - *uwrq = IW_MODE_REPEAT ; + *uwrq = IW_MODE_REPEAT; lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -425,31 +411,44 @@ out: static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; + int ret = 0; + u16 slimit = 0, llimit = 0; lbs_deb_enter(LBS_DEB_WEXT); - if (vwrq->flags == IW_RETRY_LIMIT) { - /* The MAC has a 4-bit Total_Tx_Count register - Total_Tx_Count = 1 + Tx_Retry_Count */ + if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) + return -EOPNOTSUPP; + + /* The MAC has a 4-bit Total_Tx_Count register + Total_Tx_Count = 1 + Tx_Retry_Count */ #define TX_RETRY_MIN 0 #define TX_RETRY_MAX 14 - if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) - return -EINVAL; + if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) + return -EINVAL; - /* Adding 1 to convert retry count to try count */ - priv->txretrycount = vwrq->value + 1; + /* Add 1 to convert retry count to try count */ + if (vwrq->flags & IW_RETRY_SHORT) + slimit = (u16) (vwrq->value + 1); + else if (vwrq->flags & IW_RETRY_LONG) + llimit = (u16) (vwrq->value + 1); + else + slimit = llimit = (u16) (vwrq->value + 1); /* set both */ - ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - OID_802_11_TX_RETRYCOUNT, NULL); + if (llimit) { + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, + llimit); + if (ret) + goto out; + } + if (slimit) { + /* txretrycount follows the short retry limit */ + priv->txretrycount = slimit; + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, + slimit); if (ret) goto out; - } else { - return -EOPNOTSUPP; } out: @@ -462,22 +461,30 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, { struct lbs_private *priv = dev->priv; int ret = 0; + u16 val = 0; lbs_deb_enter(LBS_DEB_WEXT); - priv->txretrycount = 0; - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - CMD_ACT_GET, CMD_OPTION_WAITFORRSP, - OID_802_11_TX_RETRYCOUNT, NULL); - if (ret) - goto out; - vwrq->disabled = 0; - if (!vwrq->flags) { - vwrq->flags = IW_RETRY_LIMIT; + + if (vwrq->flags & IW_RETRY_LONG) { + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val); + if (ret) + goto out; + + /* Subtract 1 to convert try count to retry count */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + } else { + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val); + if (ret) + goto out; + + /* txretry count follows the short retry limit */ + priv->txretrycount = val; /* Subtract 1 to convert try count to retry count */ - vwrq->value = priv->txretrycount - 1; + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; } out: -- cgit v1.2.3 From 05c914fe330fa8e1cc67870dc0d3809dfd96c107 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 00:01:58 +0200 Subject: mac80211: use nl80211 interface types There's really no reason for mac80211 to be using its own interface type defines. Use the nl80211 types and simplify the configuration code a bit: there's no need to translate them any more now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 22 ++++---- drivers/net/wireless/ath5k/ath5k.h | 4 +- drivers/net/wireless/ath5k/attach.c | 2 +- drivers/net/wireless/ath5k/base.c | 50 ++++++++--------- drivers/net/wireless/ath5k/base.h | 2 +- drivers/net/wireless/ath5k/pcu.c | 12 ++--- drivers/net/wireless/ath5k/reset.c | 2 +- drivers/net/wireless/ath9k/main.c | 28 +++++----- drivers/net/wireless/b43/main.c | 38 ++++++------- drivers/net/wireless/b43/phy_common.c | 4 +- drivers/net/wireless/b43legacy/main.c | 30 +++++------ drivers/net/wireless/b43legacy/phy.c | 4 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 6 +-- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 8 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 64 +++++++++++----------- drivers/net/wireless/iwlwifi/iwl-core.c | 8 +-- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 8 +-- drivers/net/wireless/iwlwifi/iwl-scan.c | 4 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 20 +++---- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 84 ++++++++++++++--------------- drivers/net/wireless/libertas_tf/main.c | 18 +++---- drivers/net/wireless/mac80211_hwsim.c | 2 +- drivers/net/wireless/p54/p54common.c | 14 ++--- drivers/net/wireless/p54/p54pci.c | 4 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00config.c | 8 +-- drivers/net/wireless/rt2x00/rt2x00dev.c | 8 +-- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 18 +++---- drivers/net/wireless/rtl8180_dev.c | 10 ++-- drivers/net/wireless/rtl8187_dev.c | 8 +-- drivers/net/wireless/zd1211rw/zd_mac.c | 20 +++---- 38 files changed, 264 insertions(+), 264 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index c6a55cd12db..b2c050b6889 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -765,11 +765,11 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) priv->soft_rx_crc = 0; switch (priv->mode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA); priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; @@ -777,7 +777,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) if (priv->pdev->revision >= ADM8211_REV_BA) priv->soft_rx_crc = 1; break; - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST); priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR; break; @@ -1410,11 +1410,11 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -1437,7 +1437,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; } static int adm8211_init_rings(struct ieee80211_hw *dev) @@ -1556,7 +1556,7 @@ static int adm8211_start(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; adm8211_update_mode(dev); ADM8211_CSR_WRITE(RDR, 0); @@ -1571,7 +1571,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); @@ -1896,7 +1896,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { @@ -1986,7 +1986,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2004,7 +2004,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { adm8211_start(dev); ieee80211_wake_queues(dev); } diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 4c0211798a7..20018869051 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -1008,7 +1008,7 @@ struct ath5k_hw { enum ath5k_int ah_imr; - enum ieee80211_if_types ah_op_mode; + enum nl80211_iftype ah_op_mode; enum ath5k_power_mode ah_power_mode; struct ieee80211_channel ah_current_channel; bool ah_turbo; @@ -1117,7 +1117,7 @@ extern void ath5k_hw_detach(struct ath5k_hw *ah); /* Reset Functions */ extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); -extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel); +extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); /* Power management functions */ extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 0eb2511fe14..153c4111fab 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -124,7 +124,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* * HW information */ - ah->ah_op_mode = IEEE80211_IF_TYPE_STA; + ah->ah_op_mode = NL80211_IFTYPE_STATION; ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; ah->ah_turbo = false; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 85260c39aa2..e09ed2ce675 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -507,7 +507,7 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->iobase = mem; /* So we can unmap it on detach */ sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ - sc->opmode = IEEE80211_IF_TYPE_STA; + sc->opmode = NL80211_IFTYPE_STATION; mutex_init(&sc->lock); spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); @@ -1377,8 +1377,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc) ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); if (ret) return ret; - if (sc->opmode == IEEE80211_IF_TYPE_AP || - sc->opmode == IEEE80211_IF_TYPE_MESH_POINT) { + if (sc->opmode == NL80211_IFTYPE_AP || + sc->opmode == NL80211_IFTYPE_MESH_POINT) { /* * Always burst out beacon and CAB traffic * (aifs = cwmin = cwmax = 0) @@ -1386,7 +1386,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) qi.tqi_aifs = 0; qi.tqi_cw_min = 0; qi.tqi_cw_max = 0; - } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { /* * Adhoc mode; backoff between 0 and (2 * cw_min). */ @@ -1714,7 +1714,7 @@ ath5k_tasklet_rx(unsigned long data) /* let crypto-error packets fall through in MNTR */ if ((rs.rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || - sc->opmode != IEEE80211_IF_TYPE_MNTR) + sc->opmode != NL80211_IFTYPE_MONITOR) goto next; } accept: @@ -1777,7 +1777,7 @@ accept: ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ - if (sc->opmode == IEEE80211_IF_TYPE_IBSS) + if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_check_ibss_tsf(sc, skb, &rxs); __ieee80211_rx(sc->hw, skb, &rxs); @@ -1892,7 +1892,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ds = bf->desc; flags = AR5K_TXDESC_NOACK; - if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) { + if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { ds->ds_link = bf->daddr; /* self-linked */ flags |= AR5K_TXDESC_VEOL; /* @@ -1941,8 +1941,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); - if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA || - sc->opmode == IEEE80211_IF_TYPE_MNTR)) { + if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || + sc->opmode == NL80211_IFTYPE_MONITOR)) { ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); return; } @@ -2116,9 +2116,9 @@ ath5k_beacon_config(struct ath5k_softc *sc) sc->bmisscount = 0; sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - if (sc->opmode == IEEE80211_IF_TYPE_STA) { + if (sc->opmode == NL80211_IFTYPE_STATION) { sc->imask |= AR5K_INT_BMISS; - } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2323,7 +2323,7 @@ ath5k_intr(int irq, void *dev_id) * transmission time) in order to detect wether * automatic TSF updates happened. */ - if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + if (sc->opmode == NL80211_IFTYPE_ADHOC) { /* XXX: only if VEOL suppported */ u64 tsf = ath5k_hw_get_tsf64(ah); sc->nexttbtt += sc->bintval; @@ -2553,7 +2553,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ath5k_debug_dump_skb(sc, skb, "TX ", 1); - if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + if (sc->opmode == NL80211_IFTYPE_MONITOR) ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); /* @@ -2688,9 +2688,9 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->vif = conf->vif; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MONITOR: sc->opmode = conf->type; break; default: @@ -2761,7 +2761,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (conf->changed & IEEE80211_IFCC_BEACON && - vif->type == IEEE80211_IF_TYPE_IBSS) { + vif->type == NL80211_IFTYPE_ADHOC) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) { ret = -ENOMEM; @@ -2880,17 +2880,17 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ - if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + if (sc->opmode == NL80211_IFTYPE_MONITOR) rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; - if (sc->opmode != IEEE80211_IF_TYPE_STA) + if (sc->opmode != NL80211_IFTYPE_STATION) rfilt |= AR5K_RX_FILTER_PROBEREQ; - if (sc->opmode != IEEE80211_IF_TYPE_AP && - sc->opmode != IEEE80211_IF_TYPE_MESH_POINT && + if (sc->opmode != NL80211_IFTYPE_AP && + sc->opmode != NL80211_IFTYPE_MESH_POINT && test_bit(ATH_STAT_PROMISC, sc->status)) rfilt |= AR5K_RX_FILTER_PROM; - if (sc->opmode == IEEE80211_IF_TYPE_STA || - sc->opmode == IEEE80211_IF_TYPE_IBSS) { + if (sc->opmode == NL80211_IFTYPE_STATION || + sc->opmode == NL80211_IFTYPE_ADHOC) { rfilt |= AR5K_RX_FILTER_BEACON; } @@ -2995,7 +2995,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) * in IBSS mode we need to update the beacon timers too. * this will also reset the TSF if we call it with 0 */ - if (sc->opmode == IEEE80211_IF_TYPE_IBSS) + if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_beacon_update_timers(sc, 0); else ath5k_hw_reset_tsf(sc->ah); @@ -3010,7 +3010,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ath5k_debug_dump_skb(sc, skb, "BC ", 1); - if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { + if (sc->opmode != NL80211_IFTYPE_ADHOC) { ret = -EIO; goto end; } diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 1549b63d613..9d0b728928e 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -113,7 +113,7 @@ struct ath5k_softc { struct ieee80211_channel channels[ATH_CHAN_MAX]; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; u8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; - enum ieee80211_if_types opmode; + enum nl80211_iftype opmode; struct ath5k_hw *ah; /* Atheros HW */ struct ieee80211_supported_band *curband; diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index 5a896d1e2a2..c77cee2a558 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -52,26 +52,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) ATH5K_TRACE(ah->ah_sc); switch (ah->ah_op_mode) { - case IEEE80211_IF_TYPE_IBSS: + 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); beacon_reg |= AR5K_BCR_ADHOC; break; - case IEEE80211_IF_TYPE_AP: - case IEEE80211_IF_TYPE_MESH_POINT: + 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); beacon_reg |= AR5K_BCR_AP; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_NO_PSPOLL : 0); @@ -649,7 +649,7 @@ 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 IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: if (ah->ah_version == AR5K_AR5210) { timer1 = 0xffffffff; timer2 = 0xffffffff; diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index d260fba0180..f5c3de890cd 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -399,7 +399,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) /* * Main reset function */ -int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, +int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index b493dff5643..2a6e089062f 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -140,7 +140,7 @@ static int ath_key_config(struct ath_softc *sc, struct ath9k_keyval hk; const u8 *mac = NULL; int ret = 0; - enum ieee80211_if_types opmode; + enum nl80211_iftype opmode; memset(&hk, 0, sizeof(hk)); @@ -179,14 +179,14 @@ static int ath_key_config(struct ath_softc *sc, */ if (is_broadcast_ether_addr(addr)) { switch (opmode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: /* default key: could be group WPA key * or could be static WEP key */ mac = NULL; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: break; - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: break; default: ASSERT(0); @@ -1147,13 +1147,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, return -ENOBUFS; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: ic_opmode = ATH9K_M_STA; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: ic_opmode = ATH9K_M_IBSS; break; - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: ic_opmode = ATH9K_M_HOSTAP; break; default: @@ -1275,7 +1275,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ - if (vif->type == IEEE80211_IF_TYPE_AP && + if (vif->type == NL80211_IFTYPE_AP && ah->ah_opmode != ATH9K_M_HOSTAP) { ah->ah_opmode = ATH9K_M_HOSTAP; ath9k_hw_setopmode(ah); @@ -1287,8 +1287,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, if ((conf->changed & IEEE80211_IFCC_BSSID) && !is_zero_ether_addr(conf->bssid)) { switch (vif->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: /* Update ratectrl about the new state */ ath_rate_newstate(sc, avp); @@ -1333,8 +1333,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } if ((conf->changed & IEEE80211_IFCC_BEACON) && - ((vif->type == IEEE80211_IF_TYPE_IBSS) || - (vif->type == IEEE80211_IF_TYPE_AP))) { + ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP))) { /* * Allocate and setup the beacon frame. * @@ -1353,7 +1353,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { + if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, @@ -1362,7 +1362,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } /* Only legacy IBSS for now */ - if (vif->type == IEEE80211_IF_TYPE_IBSS) + if (vif->type == NL80211_IFTYPE_ADHOC) ath_update_chainmask(sc, 0); return 0; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d4a356b1163..df7a1e7f4a5 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1244,13 +1244,13 @@ generate_new: static void handle_irq_tbtt_indication(struct b43_wldev *dev) { - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) { ///TODO: PS TBTT } else { if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) b43_power_saving_ctl_bits(dev, 0); } - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) dev->dfq_valid = 1; } @@ -1599,8 +1599,8 @@ static void handle_irq_beacon(struct b43_wldev *dev) struct b43_wl *wl = dev->wl; u32 cmd, beacon0_valid, beacon1_valid; - if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) && - !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) + if (!b43_is_mode(wl, NL80211_IFTYPE_AP) && + !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -2568,10 +2568,10 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || - b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) + if (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) ctl |= B43_MACCTL_AP; - else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) ctl &= ~B43_MACCTL_INFRA; if (wl->filter_flags & FIF_CONTROL) @@ -3406,8 +3406,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) phy->ops->set_rx_antenna(dev, antenna); /* Update templates for AP/mesh mode. */ - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || - b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) + if (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) b43_set_beacon_int(dev, conf->beacon_int); if (!!conf->radio_enabled != phy->radio_on) { @@ -3595,14 +3595,14 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || - b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) { + 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, IEEE80211_IF_TYPE_IBSS)) { + } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { if (conf->changed & IEEE80211_IFCC_BEACON) b43_update_templates(wl); } @@ -3903,7 +3903,7 @@ static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) pu_delay = 3700; else pu_delay = 1050; - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle) + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle) pu_delay = 500; if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) pu_delay = max(pu_delay, (u16)2400); @@ -3917,7 +3917,7 @@ static void b43_set_pretbtt(struct b43_wldev *dev) u16 pretbtt; /* The time value is in microseconds. */ - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) { + if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) { pretbtt = 2; } else { if (dev->phy.type == B43_PHYTYPE_A) @@ -4084,11 +4084,11 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (conf->type != IEEE80211_IF_TYPE_AP && - conf->type != IEEE80211_IF_TYPE_MESH_POINT && - conf->type != IEEE80211_IF_TYPE_STA && - conf->type != IEEE80211_IF_TYPE_WDS && - conf->type != IEEE80211_IF_TYPE_IBSS) + if (conf->type != NL80211_IFTYPE_AP && + conf->type != NL80211_IFTYPE_MESH_POINT && + conf->type != NL80211_IFTYPE_STATION && + conf->type != NL80211_IFTYPE_WDS && + conf->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 4d4345d76ab..af37abccccb 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -162,7 +162,7 @@ void b43_phy_lock(struct b43_wldev *dev) #endif B43_WARN_ON(dev->dev->id.revision < 3); - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); } @@ -174,7 +174,7 @@ void b43_phy_unlock(struct b43_wldev *dev) #endif B43_WARN_ON(dev->dev->id.revision < 3); - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43_power_saving_ctl_bits(dev, 0); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 68f63f5093a..6e425410c99 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -888,13 +888,13 @@ generate_new: static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev) { - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) { /* TODO: PS TBTT */ } else { if (1/*FIXME: the last PSpoll frame was sent successfully */) b43legacy_power_saving_ctl_bits(dev, -1, -1); } - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) dev->dfq_valid = 1; } @@ -1201,7 +1201,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) struct b43legacy_wl *wl = dev->wl; u32 cmd; - if (!b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -1936,9 +1936,9 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) ctl &= ~B43legacy_MACCTL_BEACPROMISC; ctl |= B43legacy_MACCTL_INFRA; - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) ctl |= B43legacy_MACCTL_AP; - else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) ctl &= ~B43legacy_MACCTL_INFRA; if (wl->filter_flags & FIF_CONTROL) @@ -2646,7 +2646,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, b43legacy_mgmtframe_txantenna(dev, antenna_tx); /* Update templates for AP mode. */ - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) b43legacy_set_beacon_int(dev, conf->beacon_int); @@ -2733,12 +2733,12 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP); + 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, IEEE80211_IF_TYPE_IBSS)) { + } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { if (conf->changed & IEEE80211_IFCC_BEACON) b43legacy_update_templates(wl); } @@ -3020,7 +3020,7 @@ static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle) + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle) pu_delay = 500; if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) pu_delay = max(pu_delay, (u16)2400); @@ -3035,7 +3035,7 @@ static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev) u16 pretbtt; /* The time value is in microseconds. */ - if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + if (b43legacy_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) pretbtt = 2; else pretbtt = 250; @@ -3259,10 +3259,10 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ - if (conf->type != IEEE80211_IF_TYPE_AP && - conf->type != IEEE80211_IF_TYPE_STA && - conf->type != IEEE80211_IF_TYPE_WDS && - conf->type != IEEE80211_IF_TYPE_IBSS) + if (conf->type != NL80211_IFTYPE_AP && + conf->type != NL80211_IFTYPE_STATION && + conf->type != NL80211_IFTYPE_WDS && + conf->type != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; mutex_lock(&wl->mutex); diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index bed67a54250..4c9442b16f3 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -103,7 +103,7 @@ void b43legacy_phy_lock(struct b43legacy_wldev *dev) if (dev->dev->id.revision < 3) { b43legacy_mac_suspend(dev); } else { - if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, 1); } } @@ -118,7 +118,7 @@ void b43legacy_phy_unlock(struct b43legacy_wldev *dev) if (dev->dev->id.revision < 3) { b43legacy_mac_enable(dev); } else { - if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, -1); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 10c64bdb314..da23c927380 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -682,7 +682,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, rs_sta = (void *)sta->rate_ctrl_priv; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !rs_sta->ibss_sta_added) { u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 3d100e89824..7ca5627cc07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -520,10 +520,10 @@ static int iwl3945_is_network_packet(struct iwl3945_priv *priv, /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr3, priv->bssid); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr2, priv->bssid); default: @@ -807,7 +807,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, priv->stations[sta_id].current_rate.rate_n_flags = rate; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && (sta_id != priv->hw_setting.bcast_sta_id) && (sta_id != IWL_MULTICAST_ID)) priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 9bbbc9d7c0e..2a4933b5fb6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -851,7 +851,7 @@ struct iwl3945_priv { /* eeprom */ struct iwl3945_eeprom eeprom; - enum ieee80211_if_types iw_mode; + enum nl80211_iftype iw_mode; struct sk_buff *ibss_beacon; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index c293e5b6cbb..700da67ac28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -821,7 +821,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) goto out; @@ -2093,7 +2093,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, i = sta->last_txrate_idx; if ((lq_sta->lq.sta_id == 0xff) && - (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + (priv->iw_mode == NL80211_IFTYPE_ADHOC)) goto out; valid_tx_ant = priv->hw_params.valid_tx_ant; @@ -2163,7 +2163,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; i = sta->last_txrate_idx; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + 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); @@ -2243,7 +2243,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * after assoc.. */ lq_sta->ibss_sta_added = 0; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { u8 sta_id = iwl_find_station(priv, sta->addr); DECLARE_MAC_BUF(mac); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 31ea2885889..e8db33bf5e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -337,7 +337,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ if (new_assoc) { - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (priv->iw_mode == NL80211_IFTYPE_STATION) { ret = iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1); if (ret == IWL_INVALID_STATION) { @@ -448,8 +448,8 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, const u8 *dest, int left) { if (!iwl_is_associated(priv) || !priv->ibss_beacon || - ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && - (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && + (priv->iw_mode != NL80211_IFTYPE_AP))) return 0; if (priv->ibss_beacon->len > left) @@ -672,7 +672,7 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) beacon_int = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + 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); @@ -721,7 +721,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; @@ -740,23 +740,23 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; @@ -785,7 +785,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) * in some case A channels are all non IBSS * in this case force B/G channel */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; @@ -1182,7 +1182,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, le32_to_cpu(beacon->low_tsf), rate); #endif - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!test_bit(STATUS_EXIT_PENDING, &priv->status))) queue_work(priv->workqueue, &priv->beacon_update); } @@ -2388,7 +2388,7 @@ static void iwl4965_bg_set_monitor(struct work_struct *work) mutex_lock(&priv->mutex); - ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR); + ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR); if (ret) { if (ret == -EAGAIN) @@ -2469,7 +2469,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) DECLARE_MAC_BUF(mac); unsigned long flags; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); return; } @@ -2524,7 +2524,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -2532,10 +2532,10 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl4965_commit_rxon(priv); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: /* assume default assoc id */ priv->assoc_id = 1; @@ -2551,7 +2551,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) break; } - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->assoc_station_added = 1; spin_lock_irqsave(&priv->lock, flags); @@ -2828,7 +2828,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co goto out; } - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && !is_channel_ibss(ch_info)) { IWL_ERROR("channel %d in band %d not IBSS channel\n", conf->channel->hw_value, conf->channel->band); @@ -2943,7 +2943,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -2982,7 +2982,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return 0; } - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && conf->changed & IEEE80211_IFCC_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) @@ -2992,7 +2992,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, return rc; } - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!conf->ssid_len)) { IWL_DEBUG_MAC80211 ("Leaving in AP mode because HostAPD is not ready.\n"); @@ -3015,7 +3015,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); @@ -3050,11 +3050,11 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, * to verify) - jpk */ memcpy(priv->bssid, conf->bssid, ETH_ALEN); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl4965_config_ap(priv); else { rc = iwl4965_commit_rxon(priv); - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); } @@ -3090,7 +3090,7 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw, if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, + NL80211_IFTYPE_MONITOR, changed_flags, *total_flags); /* queue work 'cuz mac80211 is holding a lock which * prevents us from issuing (synchronous) f/w cmds */ @@ -3204,7 +3204,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) goto out_unlock; } - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ ret = -EIO; IWL_ERROR("ERROR: APs don't scan\n"); goto out_unlock; @@ -3329,7 +3329,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * in 1X mode. * In legacy wep mode, we use another host command to the uCode */ if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_AP) { + priv->iw_mode != NL80211_IFTYPE_AP) { if (cmd == SET_KEY) is_default_wep_key = !priv->key_mapping_key; else @@ -3400,7 +3400,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl_activate_qos(priv, 1); else if (priv->assoc_id && iwl_is_associated(priv)) iwl_activate_qos(priv, 0); @@ -3518,7 +3518,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) priv->beacon_int = priv->hw->conf.beacon_int; priv->timestamp = 0; - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + if ((priv->iw_mode == NL80211_IFTYPE_STATION)) priv->beacon_int = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -3532,7 +3532,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) /* we are restarting association process * clear RXON_FILTER_ASSOC_MSK bit */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + 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); @@ -3541,7 +3541,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) iwl_power_update_mode(priv, 0); /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { /* switch to CAM during association period. * the ucode will block any association/authentication @@ -3580,7 +3580,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk return -EIO; } - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); mutex_unlock(&priv->mutex); return -EIO; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 36d08b0eec4..d80184ee911 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -306,14 +306,14 @@ void iwl_reset_qos(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->qos_data.qos_active = 0; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + 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 == IEEE80211_IF_TYPE_AP) { + } 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)) { @@ -932,7 +932,7 @@ int iwl_init_drv(struct iwl_priv *priv) priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; - priv->iw_mode = IEEE80211_IF_TYPE_STA; + 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; @@ -1396,7 +1396,7 @@ void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) iwl_scan_cancel(priv); /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { spin_lock_irqsave(&priv->lock, flags); iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1823687e582..c018121085e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -954,7 +954,7 @@ struct iwl_priv { u8 *eeprom; struct iwl_eeprom_calib_info *calib_info; - enum ieee80211_if_types iw_mode; + enum nl80211_iftype iw_mode; struct sk_buff *ibss_beacon; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 55ec31ec9e1..60a03d2d2d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -290,7 +290,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) final_mode = setting->critical_power_setting; /* driver only support CAM for non STA network */ - if (priv->iw_mode != IEEE80211_IF_TYPE_STA) + if (priv->iw_mode != NL80211_IFTYPE_STATION) final_mode = IWL_POWER_MODE_CAM; if (!iwl_is_rfkill(priv) && !setting->power_disabled && diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index faad4d3f56e..38b2946b1d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1026,10 +1026,10 @@ static int iwl_is_network_packet(struct iwl_priv *priv, /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr3, priv->bssid); - case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ return !compare_ether_addr(header->addr2, priv->bssid); default: @@ -1169,7 +1169,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.flag |= RX_FLAG_SHORTPRE; /* Take shortcut when only in monitor mode */ - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { iwl_pass_packet_to_mac80211(priv, include_phy, rxb, &rx_status); return; @@ -1186,7 +1186,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: case IEEE80211_FTYPE_DATA: - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, header->addr2); /* fall through */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index d026aaf6233..09c264be049 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -463,7 +463,7 @@ void iwl_init_scan_params(struct iwl_priv *priv) int iwl_scan_initiate(struct iwl_priv *priv) { - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("APs don't scan.\n"); return 0; } @@ -868,7 +868,7 @@ static void iwl_bg_request_scan(struct work_struct *data) scan->tx_cmd.len = cpu_to_le16(cmd_len); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index a72569f1acb..61797f3f8d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -47,8 +47,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) unsigned long flags; DECLARE_MAC_BUF(mac); - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || - (priv->iw_mode == IEEE80211_IF_TYPE_AP)) + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || + (priv->iw_mode == NL80211_IFTYPE_AP)) start = IWL_STA_ID; if (is_broadcast_ether_addr(addr)) @@ -74,7 +74,7 @@ EXPORT_SYMBOL(iwl_find_station); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (priv->iw_mode == NL80211_IFTYPE_STATION) { return IWL_AP_ID; } else { u8 *da = ieee80211_get_DA(hdr); @@ -286,7 +286,7 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, /* BCAST station and IBSS stations do not work in HT mode */ if (sta_id != priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + priv->iw_mode != NL80211_IFTYPE_ADHOC) iwl_set_ht_add_station(priv, sta_id, ht_info); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); @@ -817,7 +817,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, }; if ((lq->sta_id == 0xFF) && - (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + (priv->iw_mode == NL80211_IFTYPE_ADHOC)) return -EINVAL; if (lq->sta_id == 0xFF) @@ -904,7 +904,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) if ((is_ap) && (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + (priv->iw_mode == NL80211_IFTYPE_STATION)) sta_id = iwl_add_station_flags(priv, addr, is_ap, 0, cur_ht_config); else @@ -938,11 +938,11 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are a client station in a BSS network, use the special * AP station entry (that's the only station we communicate with) */ - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: return IWL_AP_ID; /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -950,7 +950,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -970,7 +970,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are in monitor mode, use BCAST. This is required for * packet injection. */ - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: return priv->hw_params.bcast_sta_id; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9d5bcf46cbe..e9feca4033f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -814,10 +814,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (priv->iw_mode != IEEE80211_IF_TYPE_MNTR || + (priv->iw_mode != NL80211_IFTYPE_MONITOR || !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ (!iwl_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || + ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || !priv->assoc_station_added)) { IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); goto drop_unlock; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cbbe73a1288..e6c6ef6ad62 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1160,7 +1160,7 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ if (iwl3945_is_associated(priv) && - (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + (priv->iw_mode == NL80211_IFTYPE_STATION)) if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); @@ -1447,8 +1447,8 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, { if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || - ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && - (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && + (priv->iw_mode != NL80211_IFTYPE_AP))) return 0; if (priv->ibss_beacon->len > left) @@ -1746,14 +1746,14 @@ 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 == IEEE80211_IF_TYPE_IBSS) { + 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 == IEEE80211_IF_TYPE_AP) { + } 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)) { @@ -2120,7 +2120,7 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) beacon_int = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + 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); @@ -2156,7 +2156,7 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) static int iwl3945_scan_initiate(struct iwl3945_priv *priv) { - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("APs don't scan.\n"); return 0; } @@ -2218,7 +2218,7 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; @@ -2237,23 +2237,23 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; @@ -2282,7 +2282,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 == IEEE80211_IF_TYPE_IBSS) && + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; @@ -2302,7 +2302,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) { - if (mode == IEEE80211_IF_TYPE_IBSS) { + if (mode == NL80211_IFTYPE_ADHOC) { const struct iwl3945_channel_info *ch_info; ch_info = iwl3945_get_channel_info(priv, @@ -2469,11 +2469,11 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* If we are a client station in a BSS network, use the special * AP station entry (that's the only station we communicate with) */ - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: return IWL_AP_ID; /* If we are an AP, then find the station, or use BCAST */ - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2481,7 +2481,7 @@ 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 IEEE80211_IF_TYPE_IBSS: { + case NL80211_IFTYPE_ADHOC: { DECLARE_MAC_BUF(mac); /* Create new station table entry */ @@ -2502,7 +2502,7 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h } /* If we are in monitor mode, use BCAST. This is required for * packet injection. */ - case IEEE80211_IF_TYPE_MNTR: + case NL80211_IFTYPE_MONITOR: return priv->hw_setting.bcast_sta_id; default: @@ -2565,9 +2565,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (priv->iw_mode != IEEE80211_IF_TYPE_MNTR) && /* packet injection */ + (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */ (!iwl3945_is_associated(priv) || - ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id))) { + ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; } @@ -2806,7 +2806,7 @@ static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio) if (disable_radio) { iwl3945_scan_cancel(priv); /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { spin_lock_irqsave(&priv->lock, flags); iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); @@ -3161,7 +3161,7 @@ static void iwl3945_rx_beacon_notif(struct iwl3945_priv *priv, le32_to_cpu(beacon->low_tsf), rate); #endif - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!test_bit(STATUS_EXIT_PENDING, &priv->status))) queue_work(priv->workqueue, &priv->beacon_update); } @@ -6059,7 +6059,7 @@ static void iwl3945_bg_set_monitor(struct work_struct *work) if (!iwl3945_is_ready(priv)) IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); else - if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0) + if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0) IWL_ERROR("iwl3945_set_mode() failed\n"); mutex_unlock(&priv->mutex); @@ -6248,7 +6248,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) /* select Rx antennas */ scan->flags |= iwl3945_get_antenna_flags(priv); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->channel_count = @@ -6323,7 +6323,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) struct ieee80211_conf *conf = NULL; DECLARE_MAC_BUF(mac); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); return; } @@ -6372,7 +6372,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) else priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -6380,11 +6380,11 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) iwl3945_commit_rxon(priv); switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: iwl3945_rate_scale_init(priv->hw, IWL_AP_ID); break; - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_ADHOC: /* clear out the station table */ iwl3945_clear_stations_table(priv); @@ -6754,7 +6754,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; } @@ -6791,7 +6791,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, } /* handle this temporarily here */ - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && conf->changed & IEEE80211_IFCC_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) @@ -6803,7 +6803,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, /* XXX: this MUST use conf->mac_addr */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + if ((priv->iw_mode == NL80211_IFTYPE_AP) && (!conf->ssid_len)) { IWL_DEBUG_MAC80211 ("Leaving in AP mode because HostAPD is not ready.\n"); @@ -6826,7 +6826,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode == NL80211_IFTYPE_AP) { if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); @@ -6861,11 +6861,11 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, * to verify) - jpk */ memcpy(priv->bssid, conf->bssid, ETH_ALEN); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl3945_config_ap(priv); else { rc = iwl3945_commit_rxon(priv); - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0); } @@ -6901,7 +6901,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, + NL80211_IFTYPE_MONITOR, changed_flags, *total_flags); /* queue work 'cuz mac80211 is holding a lock which * prevents us from issuing (synchronous) f/w cmds */ @@ -7010,7 +7010,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) goto out_unlock; } - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ rc = -EIO; IWL_ERROR("ERROR: APs don't scan\n"); goto out_unlock; @@ -7152,7 +7152,7 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + if (priv->iw_mode == NL80211_IFTYPE_AP) iwl3945_activate_qos(priv, 1); else if (priv->assoc_id && iwl3945_is_associated(priv)) iwl3945_activate_qos(priv, 0); @@ -7239,7 +7239,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) priv->beacon_int = priv->hw->conf.beacon_int; priv->timestamp1 = 0; priv->timestamp0 = 0; - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + if ((priv->iw_mode == NL80211_IFTYPE_STATION)) priv->beacon_int = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -7253,14 +7253,14 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) /* we are restarting association process * clear RXON_FILTER_ASSOC_MSK bit */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl3945_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl3945_commit_rxon(priv); } /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not in IBSS\n"); mutex_unlock(&priv->mutex); @@ -7289,7 +7289,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk return -EIO; } - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); mutex_unlock(&priv->mutex); return -EIO; @@ -7996,7 +7996,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO("Radio disabled.\n"); } - priv->iw_mode = IEEE80211_IF_TYPE_STA; + priv->iw_mode = NL80211_IFTYPE_STATION; printk(KERN_INFO DRV_NAME ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index c948021bff6..feff945ad85 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -219,7 +219,7 @@ static void lbtf_tx_work(struct work_struct *work) struct sk_buff *skb = NULL; int err; - if ((priv->vif->type == IEEE80211_IF_TYPE_AP) && + if ((priv->vif->type == NL80211_IFTYPE_AP) && (!skb_queue_empty(&priv->bc_ps_buf))) skb = skb_dequeue(&priv->bc_ps_buf); else if (priv->skb_to_tx) { @@ -326,11 +326,11 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw, priv->vif = conf->vif; switch (conf->type) { - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: lbtf_set_mode(priv, LBTF_AP_MODE); break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: lbtf_set_mode(priv, LBTF_STA_MODE); break; default: @@ -346,8 +346,8 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw, { struct lbtf_private *priv = hw->priv; - if (priv->vif->type == IEEE80211_IF_TYPE_AP || - priv->vif->type == IEEE80211_IF_TYPE_MESH_POINT) + if (priv->vif->type == NL80211_IFTYPE_AP || + priv->vif->type == NL80211_IFTYPE_MESH_POINT) lbtf_beacon_ctrl(priv, 0, 0); lbtf_set_mode(priv, LBTF_PASSIVE_MODE); lbtf_set_bssid(priv, 0, NULL); @@ -372,8 +372,8 @@ static int lbtf_op_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon; switch (priv->vif->type) { - case IEEE80211_IF_TYPE_AP: - case IEEE80211_IF_TYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: beacon = ieee80211_beacon_get(hw, vif); if (beacon) { lbtf_beacon_set(priv, beacon); @@ -614,7 +614,7 @@ void lbtf_bcn_sent(struct lbtf_private *priv) { struct sk_buff *skb = NULL; - if (priv->vif->type != IEEE80211_IF_TYPE_AP) + if (priv->vif->type != NL80211_IFTYPE_AP) return; if (skb_queue_empty(&priv->bc_ps_buf)) { diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6ba50f087f7..e855211a90f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -267,7 +267,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct sk_buff *skb; struct ieee80211_tx_info *info; - if (vif->type != IEEE80211_IF_TYPE_AP) + if (vif->type != NL80211_IFTYPE_AP) return; skb = ieee80211_beacon_get(hw, vif); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index da51786254d..bac58ed03e5 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1139,7 +1139,7 @@ static int p54_start(struct ieee80211_hw *dev) err = priv->open(dev); if (!err) - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; p54_init_vdcf(dev); @@ -1157,7 +1157,7 @@ static void p54_stop(struct ieee80211_hw *dev) kfree_skb(skb); priv->stop(dev); priv->tsf_high32 = priv->tsf_low32 = 0; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; } static int p54_add_interface(struct ieee80211_hw *dev, @@ -1165,11 +1165,11 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -1181,7 +1181,7 @@ static int p54_add_interface(struct ieee80211_hw *dev, p54_set_filter(dev, 0, NULL); switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: p54_set_filter(dev, 1, NULL); break; default: @@ -1198,7 +1198,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); p54_set_filter(dev, 0, NULL); } @@ -1380,7 +1380,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; skb_queue_head_init(&priv->tx_queue); dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS | diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 1594786205f..1c2a02a741a 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -616,7 +616,7 @@ static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct p54p_priv *priv = dev->priv; - if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); p54p_stop(dev); } @@ -634,7 +634,7 @@ static int p54p_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { + if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { p54p_open(dev); ieee80211_wake_queues(dev); } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index cb5f2d01a9c..d3bf7bba611 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -384,7 +384,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, - 2 * (conf->type != IEEE80211_IF_TYPE_STA)); + 2 * (conf->type != NL80211_IFTYPE_STATION)); rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6f296cef76a..1359a376840 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -483,7 +483,7 @@ struct rt2x00intf_conf { /* * Interface type */ - enum ieee80211_if_types type; + enum nl80211_iftype type; /* * TSF sync value, this is dependant on the operation type. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index ca051f50ef1..4d5e87b015a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -31,7 +31,7 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, - enum ieee80211_if_types type, + enum nl80211_iftype type, u8 *mac, u8 *bssid) { struct rt2x00intf_conf conf; @@ -40,11 +40,11 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, conf.type = type; switch (type) { - case IEEE80211_IF_TYPE_IBSS: - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: conf.sync = TSF_SYNC_BEACON; break; - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: conf.sync = TSF_SYNC_INFRA; break; default: diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 2f3bfc60688..86840e3585e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -467,8 +467,8 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); - if (vif->type != IEEE80211_IF_TYPE_AP && - vif->type != IEEE80211_IF_TYPE_IBSS) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_ADHOC) return; /* @@ -1212,8 +1212,8 @@ static void rt2x00lib_resume_intf(void *data, u8 *mac, /* * Master or Ad-hoc mode require a new beacon update. */ - if (vif->type == IEEE80211_IF_TYPE_AP || - vif->type == IEEE80211_IF_TYPE_IBSS) + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) intf->delayed_flags |= DELAYED_UPDATE_BEACON; spin_unlock(&intf->lock); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 7bbc16b1b6c..797eb619aa0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -88,7 +88,7 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, - enum ieee80211_if_types type, + enum nl80211_iftype type, u8 *mac, u8 *bssid); void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 56829fad347..485c40de5cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -211,7 +211,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, return -ENODEV; switch (conf->type) { - case IEEE80211_IF_TYPE_AP: + case NL80211_IFTYPE_AP: /* * We don't support mixed combinations of * sta and ap interfaces. @@ -227,8 +227,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, return -ENOBUFS; break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: /* * We don't support mixed combinations of * sta and ap interfaces. @@ -268,7 +268,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * increase interface count and start initialization. */ - if (conf->type == IEEE80211_IF_TYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count++; else rt2x00dev->intf_sta_count++; @@ -277,7 +277,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, spin_lock_init(&intf->seqlock); intf->beacon = entry; - if (conf->type == IEEE80211_IF_TYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); @@ -311,11 +311,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * no interface is present. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || - (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || - (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) + (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || + (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) return; - if (conf->type == IEEE80211_IF_TYPE_AP) + if (conf->type == NL80211_IFTYPE_AP) rt2x00dev->intf_ap_count--; else rt2x00dev->intf_sta_count--; @@ -331,7 +331,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * are cleared to prevent false ACKing of frames. */ rt2x00lib_config_intf(rt2x00dev, intf, - IEEE80211_IF_TYPE_INVALID, NULL, NULL); + NL80211_IFTYPE_UNSPECIFIED, NULL, NULL); } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 861c76a65d6..abcd641c54b 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -615,7 +615,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_TX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; return 0; err_free_rings: @@ -633,7 +633,7 @@ static void rtl8180_stop(struct ieee80211_hw *dev) u8 reg; int i; - priv->mode = IEEE80211_IF_TYPE_INVALID; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); @@ -661,11 +661,11 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev, { struct rtl8180_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -688,7 +688,7 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8180_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; } diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 8a42bfa6d4f..e9902613e2e 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -836,11 +836,11 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, struct rtl8187_priv *priv = dev->priv; int i; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) + if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_STA: + case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: @@ -865,7 +865,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, { struct rtl8187_priv *priv = dev->priv; mutex_lock(&priv->conf_mutex); - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; priv->vif = NULL; mutex_unlock(&priv->conf_mutex); } @@ -1057,7 +1057,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 3005dd1fde4..a3da014f928 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -716,15 +716,15 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, { struct zd_mac *mac = zd_hw_mac(hw); - /* using IEEE80211_IF_TYPE_INVALID to indicate no mode selected */ - if (mac->type != IEEE80211_IF_TYPE_INVALID) + /* using NL80211_IFTYPE_UNSPECIFIED to indicate no mode selected */ + if (mac->type != NL80211_IFTYPE_UNSPECIFIED) return -EOPNOTSUPP; switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: mac->type = conf->type; break; default: @@ -738,7 +738,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); - mac->type = IEEE80211_IF_TYPE_INVALID; + mac->type = NL80211_IFTYPE_UNSPECIFIED; zd_set_beacon_interval(&mac->chip, 0); zd_write_mac_addr(&mac->chip, NULL); } @@ -757,8 +757,8 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, int associated; int r; - if (mac->type == IEEE80211_IF_TYPE_MESH_POINT || - mac->type == IEEE80211_IF_TYPE_IBSS) { + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC) { associated = true; if (conf->changed & IEEE80211_IFCC_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); @@ -955,7 +955,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) spin_lock_init(&mac->lock); mac->hw = hw; - mac->type = IEEE80211_IF_TYPE_INVALID; + mac->type = NL80211_IFTYPE_UNSPECIFIED; memcpy(mac->channels, zd_channels, sizeof(zd_channels)); memcpy(mac->rates, zd_rates, sizeof(zd_rates)); -- cgit v1.2.3 From 8aa21e6fd703cb3fed66ac07dcbcb861f00cf6d6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 02:16:36 +0200 Subject: mac80211 hwsim: verify vif pointers mac80211-hwsim is a debugging tool for mac80211, and as such it can very well verify that mac80211 isn't passing junk to drivers, especially the vif pointer is prone to this because for vlan interfaces the AP interface pointer needs to be passed. This makes mac80211-hwsim add a magic cookie to the private vif area and verify it whenever an operation is called that gets a vif pointer. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e855211a90f..bdedf10fc86 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -28,6 +28,29 @@ static int radios = 2; module_param(radios, int, 0444); MODULE_PARM_DESC(radios, "Number of simulated radios"); +struct hwsim_vif_priv { + u32 magic; +}; + +#define HWSIM_VIF_MAGIC 0x69537748 + +static inline void hwsim_check_magic(struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + WARN_ON(vp->magic != HWSIM_VIF_MAGIC); +} + +static inline void hwsim_set_magic(struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + vp->magic = HWSIM_VIF_MAGIC; +} + +static inline void hwsim_clear_magic(struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + vp->magic = 0; +} static struct class *hwsim_class; @@ -210,6 +233,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ack = mac80211_hwsim_tx_frame(hw, skb); txi = IEEE80211_SKB_CB(skb); + + hwsim_check_magic(txi->control.vif); + memset(&txi->status, 0, sizeof(txi->status)); if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { if (ack) @@ -246,6 +272,7 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", wiphy_name(hw->wiphy), __func__, conf->type, print_mac(mac, conf->mac_addr)); + hwsim_set_magic(conf->vif); return 0; } @@ -257,6 +284,8 @@ static void mac80211_hwsim_remove_interface( printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", wiphy_name(hw->wiphy), __func__, conf->type, print_mac(mac, conf->mac_addr)); + hwsim_check_magic(conf->vif); + hwsim_clear_magic(conf->vif); } @@ -267,6 +296,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct sk_buff *skb; struct ieee80211_tx_info *info; + hwsim_check_magic(vif); + if (vif->type != NL80211_IFTYPE_AP) return; @@ -341,7 +372,28 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, *total_flags = data->rx_filter; } +static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + hwsim_check_magic(vif); + return 0; +} +static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + hwsim_check_magic(vif); +} + +static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, const u8 *addr) +{ + hwsim_check_magic(vif); +} static const struct ieee80211_ops mac80211_hwsim_ops = { @@ -352,6 +404,9 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .remove_interface = mac80211_hwsim_remove_interface, .config = mac80211_hwsim_config, .configure_filter = mac80211_hwsim_configure_filter, + .config_interface = mac80211_hwsim_config_interface, + .bss_info_changed = mac80211_hwsim_bss_info_changed, + .sta_notify = mac80211_hwsim_sta_notify, }; @@ -452,6 +507,9 @@ static int __init init_mac80211_hwsim(void) BIT(NL80211_IFTYPE_AP); hw->ampdu_queues = 1; + /* ask mac80211 to reserve space for magic */ + hw->vif_data_size = sizeof(struct hwsim_vif_priv); + memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); data->band.channels = data->channels; -- cgit v1.2.3 From 17741cdc264e4d768167766a252210e201c1519a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 00:02:02 +0200 Subject: mac80211: share STA information with driver This patch changes mac80211 to share some more data about stations with drivers. Should help iwlwifi and ath9k when they get around to updating, and might also help with implementing rate control algorithms without internals. Signed-off-by: Johannes Berg Cc: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 30 ++++++++++++++---------------- drivers/net/wireless/b43/main.c | 5 +++-- drivers/net/wireless/b43legacy/main.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 12 ++++++------ drivers/net/wireless/iwlwifi/iwl-agn.c | 12 ++++++------ drivers/net/wireless/mac80211_hwsim.c | 3 ++- 6 files changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2a6e089062f..1ba18006f47 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1405,7 +1405,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, - const u8 *addr) + struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; struct ath_node *an; @@ -1413,19 +1413,18 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, DECLARE_MAC_BUF(mac); spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, (u8 *) addr); + 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, (u8 *)addr, 0); + ath_node_attach(sc, sta->addr, 0); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, - print_mac(mac, addr)); + __func__, print_mac(mac, sta->addr)); } else { - ath_node_get(sc, (u8 *)addr); + ath_node_get(sc, sta->addr); } spin_unlock_irqrestore(&sc->node_lock, flags); break; @@ -1438,7 +1437,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", __func__, - print_mac(mac, addr)); + print_mac(mac, sta->addr)); } break; default: @@ -1581,45 +1580,44 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) static int ath9k_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, - u16 tid, - u16 *ssn) + struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_softc *sc = hw->priv; int ret = 0; switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, addr, tid, ssn); + 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__); break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, addr, tid); + 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, addr, tid, ssn); + ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to start TX aggregation\n", __func__); else - ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, addr, tid); + ret = ath_tx_aggr_stop(sc, sta->addr, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to stop TX aggregation\n", __func__); - ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; default: DPRINTF(sc, ATH_DBG_FATAL, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index df7a1e7f4a5..0f628a29d83 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4234,7 +4234,8 @@ out_unlock: return err; } -static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) +static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) { struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; @@ -4249,7 +4250,7 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) static void b43_op_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd notify_cmd, - const u8 *addr) + struct ieee80211_sta *sta) { struct b43_wl *wl = hw_to_b43_wl(hw); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 6e425410c99..9fb1421cbec 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3403,7 +3403,7 @@ out_unlock: } static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, - int aid, int set) + struct ieee80211_sta *sta, bool set) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 700da67ac28..af4e0b994e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -366,8 +366,8 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, if (state == HT_AGG_STATE_IDLE && 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); - ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); + print_mac(mac, sta->sta.addr), tid); + ieee80211_start_tx_ba_session(priv->hw, sta->sta.addr, tid); } } @@ -2244,17 +2244,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { - u8 sta_id = iwl_find_station(priv, sta->addr); + u8 sta_id = iwl_find_station(priv, sta->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)); + print_mac(mac, sta->sta.addr)); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); - sta_id = iwl_add_station_flags(priv, sta->addr, + print_mac(mac, sta->sta.addr)); + sta_id = iwl_add_station_flags(priv, sta->sta.addr, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e8db33bf5e5..5eeffb41d8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3413,13 +3413,13 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn) + 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, addr), tid); + print_mac(mac, sta->addr), tid); if (!(priv->cfg->sku & IWL_SKU_N)) return -EACCES; @@ -3427,16 +3427,16 @@ 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, addr, tid, *ssn); + return iwl_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, addr, tid); + return iwl_rx_agg_stop(priv, sta->addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); - return iwl_tx_agg_start(priv, addr, tid, ssn); + return iwl_tx_agg_start(priv, sta->addr, tid, ssn); case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT("stop Tx\n"); - return iwl_tx_agg_stop(priv, addr, tid); + return iwl_tx_agg_stop(priv, sta->addr, tid); default: IWL_DEBUG_HT("unknown\n"); return -EINVAL; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bdedf10fc86..173dd5d2c62 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -390,7 +390,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, const u8 *addr) + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) { hwsim_check_magic(vif); } -- cgit v1.2.3 From 81c065238644ade3869391f977438ff7ed3158db Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 02:17:01 +0200 Subject: mac80211 hwsim: verify sta pointers In analogy with the previous patch to make mac80211-hwsim verify that the virtual interface pointers are correct, this makes it very that it knows about all station structs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 173dd5d2c62..da8aa83481f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -52,6 +52,30 @@ static inline void hwsim_clear_magic(struct ieee80211_vif *vif) vp->magic = 0; } +struct hwsim_sta_priv { + u32 magic; +}; + +#define HWSIM_STA_MAGIC 0x6d537748 + +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); +} + +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; +} + +static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) +{ + struct hwsim_sta_priv *sp = (void *)sta->drv_priv; + sp->magic = 0; +} + static struct class *hwsim_class; static struct ieee80211_hw **hwsim_radios; @@ -235,6 +259,8 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) txi = IEEE80211_SKB_CB(skb); hwsim_check_magic(txi->control.vif); + 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)) { @@ -394,6 +420,22 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { hwsim_check_magic(vif); + switch (cmd) { + case STA_NOTIFY_ADD: + hwsim_set_sta_magic(sta); + break; + case STA_NOTIFY_REMOVE: + hwsim_clear_sta_magic(sta); + break; + } +} + +static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + bool set) +{ + hwsim_check_sta_magic(sta); + return 0; } static const struct ieee80211_ops mac80211_hwsim_ops = @@ -408,6 +450,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .config_interface = mac80211_hwsim_config_interface, .bss_info_changed = mac80211_hwsim_bss_info_changed, .sta_notify = mac80211_hwsim_sta_notify, + .set_tim = mac80211_hwsim_set_tim, }; @@ -510,6 +553,7 @@ static int __init init_mac80211_hwsim(void) /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); + hw->sta_data_size = sizeof(struct hwsim_sta_priv); memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); -- cgit v1.2.3 From b7e35008815a1c39123f4dd53b430788e2e18da4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 02:22:58 +0200 Subject: mac80211: move last_txrate_idx into RC algorithms This variable in sta_info is only used in a meaningful way by the Intel RC algorithms, so move it into those. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 20 ++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 15 +++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index da23c927380..46b672c3458 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -65,6 +65,9 @@ struct iwl3945_rs_sta { u8 ibss_sta_added; struct timer_list rate_scale_flush; struct iwl3945_rate_scale_data win[IWL_RATE_COUNT]; + + /* used to be in sta_info */ + int last_txrate_idx; }; static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = { @@ -319,6 +322,7 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, static void rs_rate_init(void *priv_rate, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta) { + struct iwl3945_rs_sta *rs_sta = (void *)sta->rate_ctrl_priv; int i; IWL_DEBUG_RATE("enter\n"); @@ -335,11 +339,11 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, } } - sta->last_txrate_idx = sta->txrate_idx; + rs_sta->last_txrate_idx = sta->txrate_idx; /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) - sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; IWL_DEBUG_RATE("leave\n"); } @@ -674,14 +678,14 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, return; } + rs_sta = (void *)sta->rate_ctrl_priv; + rate_mask = sta->supp_rates[sband->band]; - index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); + index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); if (sband->band == IEEE80211_BAND_5GHZ) rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; - rs_sta = (void *)sta->rate_ctrl_priv; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !rs_sta->ibss_sta_added) { u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); @@ -803,11 +807,11 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, out: - sta->last_txrate_idx = index; + rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + sta->txrate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; else - sta->txrate_idx = sta->last_txrate_idx; + sta->txrate_idx = rs_sta->last_txrate_idx; rcu_read_unlock(); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index af4e0b994e4..54f076bb202 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -163,6 +163,9 @@ struct iwl_lq_sta { u32 dbg_fixed_rate; #endif struct iwl_priv *drv; + + /* used to be in sta_info */ + int last_txrate_idx; }; static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -1746,7 +1749,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, is_green = lq_sta->is_green; /* current tx rate */ - index = sta->last_txrate_idx; + index = lq_sta->last_txrate_idx; IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, tbl->lq_type); @@ -2059,7 +2062,7 @@ lq_update: out: tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green); i = index; - sta->last_txrate_idx = i; + lq_sta->last_txrate_idx = i; /* sta->txrate_idx is an index to A mode rates which start * at IWL_FIRST_OFDM_RATE @@ -2090,7 +2093,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, goto out; lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate_idx; + i = lq_sta->last_txrate_idx; if ((lq_sta->lq.sta_id == 0xff) && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) @@ -2161,7 +2164,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, } lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate_idx; + i = lq_sta->last_txrate_idx; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { @@ -2270,10 +2273,10 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, if (sta->supp_rates[sband->band] & BIT(i)) sta->txrate_idx = i; - sta->last_txrate_idx = sta->txrate_idx; + lq_sta->last_txrate_idx = sta->txrate_idx; /* For MODE_IEEE80211A, skip over cck rates in global rate table */ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) - sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; lq_sta->is_green = rs_use_green(priv, conf); -- cgit v1.2.3 From 323ce79a9cdbf838ea577677b1ddace8e0b4d4c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 02:45:11 +0200 Subject: mac80211: share sta->supp_rates As more preparation for a saner rate control algorithm API, share the supported rates bitmap in the public API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 390019ed398..226d70c73fe 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1825,7 +1825,7 @@ static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta) sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) { + if (sta->sta.supp_rates[local->hw.conf.channel->band] & BIT(i)) { rc_priv->neg_rates.rs_rates[j] = (sband->bitrates[i].bitrate * 2) / 10; j++; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 46b672c3458..f751b909759 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -333,7 +333,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * after assoc.. */ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { - if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) { + if (sta->sta.supp_rates[local->hw.conf.channel->band] & (1 << i)) { sta->txrate_idx = i; break; } @@ -680,7 +680,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, rs_sta = (void *)sta->rate_ctrl_priv; - rate_mask = sta->supp_rates[sband->band]; + rate_mask = sta->sta.supp_rates[sband->band]; index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); if (sband->band == IEEE80211_BAND_5GHZ) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 54f076bb202..f7191a9a7fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1731,7 +1731,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, return; lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; + lq_sta->supp_rates = sta->sta.supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); @@ -2233,7 +2233,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; lq_sta->flush_timer = 0; - lq_sta->supp_rates = sta->supp_rates[sband->band]; + lq_sta->supp_rates = sta->sta.supp_rates[sband->band]; sta->txrate_idx = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) @@ -2270,7 +2270,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, /* Find highest tx rate supported by hardware and destination station */ for (i = 0; i < sband->n_bitrates; i++) - if (sta->supp_rates[sband->band] & BIT(i)) + if (sta->sta.supp_rates[sband->band] & BIT(i)) sta->txrate_idx = i; lq_sta->last_txrate_idx = sta->txrate_idx; -- cgit v1.2.3 From ae17e986091637e7ef5a8224c7b689029b105131 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 03:04:36 +0200 Subject: mac80211: move txrate_idx into RC algorithms The sta_info->txrate_idx member isn't used by all RC algorithms in the way it was intended to be used, move it into those that require it (only PID) and keep track in the core code of which rate was last used for reporting to userspace and the mesh MLME. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 1 - drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 10 +++------- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 13 ++----------- 3 files changed, 5 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 226d70c73fe..1cc9daf4455 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -2039,7 +2039,6 @@ static void ath_rate_init(void *priv, void *priv_sta, DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - sta->txrate_idx = rate_lowest_index(local, sband, sta); ath_setup_rates(local, sta); if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index f751b909759..a279bf1dc9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -334,13 +334,11 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { if (sta->sta.supp_rates[local->hw.conf.channel->band] & (1 << i)) { - sta->txrate_idx = i; + rs_sta->last_txrate_idx = i; break; } } - rs_sta->last_txrate_idx = sta->txrate_idx; - /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; @@ -809,15 +807,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sta->txrate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; else - sta->txrate_idx = rs_sta->last_txrate_idx; + sel->rate_idx = rs_sta->last_txrate_idx; rcu_read_unlock(); IWL_DEBUG_RATE("leave: %d\n", index); - - sel->rate_idx = sta->txrate_idx; } static struct rate_control_ops rs_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index f7191a9a7fb..a8711c314e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2064,14 +2064,6 @@ out: i = index; lq_sta->last_txrate_idx = i; - /* sta->txrate_idx is an index to A mode rates which start - * at IWL_FIRST_OFDM_RATE - */ - if (lq_sta->band == IEEE80211_BAND_5GHZ) - sta->txrate_idx = i - IWL_FIRST_OFDM_RATE; - else - sta->txrate_idx = i; - return; } @@ -2234,7 +2226,6 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->sta.supp_rates[sband->band]; - sta->txrate_idx = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); @@ -2269,11 +2260,11 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, } /* 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->sta.supp_rates[sband->band] & BIT(i)) - sta->txrate_idx = i; + lq_sta->last_txrate_idx = i; - lq_sta->last_txrate_idx = sta->txrate_idx; /* For MODE_IEEE80211A, skip over cck rates in global rate table */ if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; -- cgit v1.2.3 From 687c7c0807371aeaa94ff2fff511eeb326b5c5de Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 03:14:11 +0200 Subject: mac80211: share sta_info->ht_info Rate control algorithms may need access to a station's HT capabilities, so share the ht_info struct in the public station API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a8711c314e6..f45a752e93c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1154,10 +1154,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s8 is_green = lq_sta->is_green; if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + !sta->sta.ht_info.ht_supported) return -1; - if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + if (((sta->sta.ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == WLAN_HT_CAP_SM_PS_STATIC) return -1; @@ -1222,7 +1222,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, s32 rate; if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + !sta->sta.ht_info.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); -- cgit v1.2.3 From ff550cb4f8ef03f7cb0b4948e503388bcfb96034 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2008 03:17:05 +0200 Subject: iwlwifi: don't access mac80211's AMPDU state machine There really is no need, at worst ieee80211_start_tx_ba_session will log a message when debugging is enabled, and poking such internals of mac80211 definitely doesn't belong into an RC algorithm. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index f45a752e93c..8b57b390c8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -359,15 +359,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, struct sta_info *sta) { - unsigned long state; DECLARE_MAC_BUF(mac); - spin_lock_bh(&sta->lock); - state = sta->ampdu_mlme.tid_state_tx[tid]; - spin_unlock_bh(&sta->lock); - - if (state == HT_AGG_STATE_IDLE && - rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { + 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->sta.addr), tid); ieee80211_start_tx_ba_session(priv->hw, sta->sta.addr, tid); -- cgit v1.2.3 From e96a8495dcac965ef41a654fb456a72e56c87340 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Sep 2008 11:45:20 +0800 Subject: iwlwifi: update 5350 Wifi PCI IDs This patch updates PCI IDs for 5350 Wifi/WiMax. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 5eeffb41d8c..27376276976 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4506,7 +4506,10 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, - {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)}, +/* 5350 WiFi/WiMax */ + {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, + {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, + {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, #endif /* CONFIG_IWL5000 */ {0} }; -- cgit v1.2.3 From c9f79ed2d063c3b0e0f2dbb2befd793ab40f6054 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Sep 2008 11:45:21 +0800 Subject: iwlwifi: add MODULE_FIRMWARE for 5000 HW This patch adds MODULE_FIRMWARE statement for 5000 HW. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cccd84c2f8e..f6003e7996a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1569,6 +1569,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .mod_params = &iwl50_mod_params, }; +MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode"); + module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, "manually disable the 50XX radio (default 0 [radio on])"); -- cgit v1.2.3 From 25cb6cada8fa0a2f375af29eca6ab5520199ffd6 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 11 Sep 2008 11:45:22 +0800 Subject: iwl3945: add MODULE_FIRMWARE for 3945 HW This patch adds MODULE_FIRMWARE statement for 3945 HW. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e6c6ef6ad62..62b26befddc 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -8376,6 +8376,8 @@ static void __exit iwl3945_exit(void) iwl3945_rate_control_unregister(); } +MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode"); + module_param_named(antenna, iwl3945_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(disable, iwl3945_param_disable, int, 0444); -- cgit v1.2.3 From e35cc4ddcc4c3b11006bcabe8ce28aa7e18da318 Mon Sep 17 00:00:00 2001 From: Lorenzo Nava Date: Thu, 11 Sep 2008 15:06:24 +0200 Subject: b43: fix QoS parameters initialization This fixes the initialization of QoS parameters. Reported-by: Lorenzo Nava, Francesco Gringoli Signed-off-by: Francesco Gringoli Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 07d2825458a..427b8203e3f 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -569,7 +569,7 @@ struct b43_key { #define B43_QOS_VOICE B43_QOS_PARAMS(3) /* QOS parameter hardware data structure offsets. */ -#define B43_NR_QOSPARAMS 22 +#define B43_NR_QOSPARAMS 16 enum { B43_QOSPARAM_TXOP = 0, B43_QOSPARAM_CWMIN, -- cgit v1.2.3 From 9c31fd635ddfae6eb61712491770befa2ce1fdde Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 11 Sep 2008 15:32:50 -0700 Subject: libertas: Reduce the WPA key installation time. WPA requires that the PTK is installed immediately after the 4-way handshake in order to properly decrypt the subsequent incoming EAPOL-GTK frame. If the PTK is not enabled by the time the EAPOL-GTK frame arrives, the frame is dropped and the supplicant does not receive the group key. This will happen with fast Access Points that send the EAPOL-GTK frame before the suplicant has successfully installed and enabled the PTK. To mitigate this situation, this patch simplifies and accelerates the SIOCSIWENCODEEXT execution. This patch resolves OLPC ticket 7825 (http://dev.laptop.org/ticket/7825) Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index d86fcf0a5ad..1156be53df3 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -30,6 +30,14 @@ static inline void lbs_postpone_association_work(struct lbs_private *priv) queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); } +static inline void lbs_do_association_work(struct lbs_private *priv) +{ + if (priv->surpriseremoved) + return; + cancel_delayed_work(&priv->assoc_work); + queue_delayed_work(priv->work_thread, &priv->assoc_work, 0); +} + static inline void lbs_cancel_association_work(struct lbs_private *priv) { cancel_delayed_work(&priv->assoc_work); @@ -1585,12 +1593,14 @@ static int lbs_set_encodeext(struct net_device *dev, set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); } - disable_wep (assoc_req); + /* Only disable wep if necessary: can't waste time here. */ + if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) + disable_wep(assoc_req); } out: - if (ret == 0) { - lbs_postpone_association_work(priv); + if (ret == 0) { /* key installation is time critical: postpone not! */ + lbs_do_association_work(priv); } else { lbs_cancel_association_work(priv); } -- cgit v1.2.3 From 25d834e16294c8dfd923dae6bdb8a055391a99a5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Sep 2008 22:52:47 +0200 Subject: mac80211: fix virtual interfaces vs. injection Currently, virtual interface pointers passed to drivers might be from monitor interfaces and as such completely uninitialised because we do not tell the driver about monitor interfaces when those are created. Instead of passing them, we should therefore indicate to the driver that there is no information; do that by passing a NULL value and adjust drivers to cope with it. As a result, some mac80211 API functions also need to cope with a NULL vif pointer so drivers can still call them unconditionally. Also, when injecting frames we really don't want to pass NULL all the time, if we know we are the source address of a frame and have a local interface for that address, we can to use that interface. This also helps with processing the frame correctly for that interface which will help the 802.11w implementation. It's not entirely correct for VLANs or WDS interfaces because there the MAC address isn't unique, but it's already a lot better than what we do now. Finally, when injecting without a matching local interface, don't assign sequence numbers at all. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00queue.c | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index da8aa83481f..631d65b73ed 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -258,7 +258,8 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) txi = IEEE80211_SKB_CB(skb); - hwsim_check_magic(txi->control.vif); + if (txi->control.vif) + hwsim_check_magic(txi->control.vif); if (txi->control.sta) hwsim_check_sta_magic(txi->control.sta); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index a5e965068c8..b7f4fe8fba6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -155,7 +155,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; struct ieee80211_rate *rate = ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); @@ -278,16 +277,22 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * sequence counter given by mac80211. */ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - spin_lock_irqsave(&intf->seqlock, irqflags); + if (likely(tx_info->control.vif)) { + struct rt2x00_intf *intf; - if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) - intf->seqno += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(intf->seqno); + intf = vif_to_intf(tx_info->control.vif); - spin_unlock_irqrestore(&intf->seqlock, irqflags); + spin_lock_irqsave(&intf->seqlock, irqflags); - __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) + intf->seqno += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(intf->seqno); + + spin_unlock_irqrestore(&intf->seqlock, irqflags); + + __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + } } /* -- cgit v1.2.3 From 0e057d73eacd952d321d46c7eb972969ec245026 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Sep 2008 00:39:22 +0200 Subject: mac80211 hwsim: make radio list dynamic This paves the way for dynamic radio additions while the module is loaded. Also restrict the number of radios to 100 because creating that many already takes forever. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 86 ++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 631d65b73ed..c9e4a435b2f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -14,6 +14,8 @@ * - RX filtering based on filter configuration (data->rx_filter) */ +#include +#include #include #include #include @@ -78,8 +80,6 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) static struct class *hwsim_class; -static struct ieee80211_hw **hwsim_radios; -static int hwsim_radio_count; static struct net_device *hwsim_mon; /* global monitor netdev */ @@ -115,7 +115,12 @@ static const struct ieee80211_rate hwsim_rates[] = { { .bitrate = 540 } }; +static spinlock_t hwsim_radio_lock; +static struct list_head hwsim_radios; + struct mac80211_hwsim_data { + struct list_head list; + struct ieee80211_hw *hw; struct device *dev; struct ieee80211_supported_band band; struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)]; @@ -191,11 +196,11 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } -static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, - struct sk_buff *skb) +static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, + struct sk_buff *skb) { - struct mac80211_hwsim_data *data = hw->priv; - int i, ack = 0; + struct mac80211_hwsim_data *data = hw->priv, *data2; + bool ack = false; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rx_status rx_status; @@ -208,13 +213,13 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* TODO: simulate signal strength (and optional packet drop) */ /* Copy skb to all enabled radios that are on the current frequency */ - for (i = 0; i < hwsim_radio_count; i++) { - struct mac80211_hwsim_data *data2; + spin_lock(&hwsim_radio_lock); + list_for_each_entry(data2, &hwsim_radios, list) { struct sk_buff *nskb; - if (hwsim_radios[i] == NULL || hwsim_radios[i] == hw) + if (data == data2) continue; - data2 = hwsim_radios[i]->priv; + if (!data2->started || !data2->radio_enabled || data->channel->center_freq != data2->channel->center_freq) continue; @@ -223,11 +228,12 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (nskb == NULL) continue; - if (memcmp(hdr->addr1, hwsim_radios[i]->wiphy->perm_addr, + if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, ETH_ALEN) == 0) - ack = 1; - ieee80211_rx_irqsafe(hwsim_radios[i], nskb, &rx_status); + ack = true; + ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); } + spin_unlock(&hwsim_radio_lock); return ack; } @@ -236,7 +242,7 @@ static int mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct mac80211_hwsim_data *data = hw->priv; - int ack; + bool ack; struct ieee80211_tx_info *txi; mac80211_hwsim_monitor_rx(hw, skb); @@ -457,18 +463,21 @@ static const struct ieee80211_ops mac80211_hwsim_ops = static void mac80211_hwsim_free(void) { - int i; - - for (i = 0; i < hwsim_radio_count; i++) { - if (hwsim_radios[i]) { - struct mac80211_hwsim_data *data; - data = hwsim_radios[i]->priv; - ieee80211_unregister_hw(hwsim_radios[i]); - device_unregister(data->dev); - ieee80211_free_hw(hwsim_radios[i]); - } + struct list_head tmplist, *i, *tmp; + struct mac80211_hwsim_data *data; + + INIT_LIST_HEAD(&tmplist); + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_safe(i, tmp, &hwsim_radios) + list_move(i, &tmplist); + spin_unlock_bh(&hwsim_radio_lock); + + list_for_each_entry(data, &tmplist, list) { + ieee80211_unregister_hw(data->hw); + device_unregister(data->dev); + ieee80211_free_hw(data->hw); } - kfree(hwsim_radios); class_destroy(hwsim_class); } @@ -498,37 +507,32 @@ static int __init init_mac80211_hwsim(void) struct ieee80211_hw *hw; DECLARE_MAC_BUF(mac); - if (radios < 1 || radios > 65535) + if (radios < 1 || radios > 100) return -EINVAL; - hwsim_radio_count = radios; - hwsim_radios = kcalloc(hwsim_radio_count, - sizeof(struct ieee80211_hw *), GFP_KERNEL); - if (hwsim_radios == NULL) - return -ENOMEM; + spin_lock_init(&hwsim_radio_lock); + INIT_LIST_HEAD(&hwsim_radios); hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); - if (IS_ERR(hwsim_class)) { - kfree(hwsim_radios); + if (IS_ERR(hwsim_class)) return PTR_ERR(hwsim_class); - } memset(addr, 0, ETH_ALEN); addr[0] = 0x02; - for (i = 0; i < hwsim_radio_count; i++) { + for (i = 0; i < radios; i++) { printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", i); hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); - if (hw == NULL) { + if (!hw) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " "failed\n"); err = -ENOMEM; goto failed; } - hwsim_radios[i] = hw; - data = hw->priv; + data->hw = hw; + data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw, "hwsim%d", i); if (IS_ERR(data->dev)) { @@ -590,6 +594,8 @@ static int __init init_mac80211_hwsim(void) setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); + + list_add_tail(&data->list, &hwsim_radios); } hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); @@ -621,7 +627,6 @@ failed_hw: device_unregister(data->dev); failed_drvdata: ieee80211_free_hw(hw); - hwsim_radios[i] = NULL; failed: mac80211_hwsim_free(); return err; @@ -630,8 +635,7 @@ failed: static void __exit exit_mac80211_hwsim(void) { - printk(KERN_DEBUG "mac80211_hwsim: unregister %d radios\n", - hwsim_radio_count); + printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); unregister_netdev(hwsim_mon); mac80211_hwsim_free(); -- cgit v1.2.3 From 75d31cf19fe8f86b4612561c94dfbb6d8a472ba3 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Fri, 12 Sep 2008 22:28:18 +0100 Subject: orinoco: Fix compile warnings Use min_t to avoid warnings when the typesafe version is used. Explicitly cast u64s to unsigned long long when being passed to printk. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index ec0451cbb8e..9a2fcc0163d 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -4777,14 +4777,14 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, encoding->flags |= IW_ENCODE_DISABLED; break; case IW_ENCODE_ALG_WEP: - ext->key_len = min(le16_to_cpu(priv->keys[idx].len), - (u16) max_key_len); + ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), + max_key_len); memcpy(ext->key, priv->keys[idx].data, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; case IW_ENCODE_ALG_TKIP: - ext->key_len = min((u16) sizeof(struct orinoco_tkip_key), - (u16) max_key_len); + ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), + max_key_len); memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; @@ -5686,9 +5686,9 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, /* Timestamp */ iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "tsf=%016llx", - le64_to_cpu(bss->timestamp)); + iwe.u.data.length = + snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", + (unsigned long long) le64_to_cpu(bss->timestamp)); if (iwe.u.data.length) current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); -- cgit v1.2.3 From 375da53b8e5e3ff2330b66b377e07a6151a93fe5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 15 Sep 2008 17:25:54 -0400 Subject: libertas: correct "limited range of data type" warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/libertas/wext.o drivers/net/wireless/libertas/wext.c: In function ‘lbs_get_rts’: drivers/net/wireless/libertas/wext.c:307: warning: comparison is always false due to limited range of data type Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 1156be53df3..11297dcf9fc 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -281,7 +281,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, if (vwrq->disabled) val = MRVDRV_RTS_MAX_VALUE; - if (val < MRVDRV_RTS_MIN_VALUE || val > MRVDRV_RTS_MAX_VALUE) + if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */ return -EINVAL; ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val); @@ -304,8 +304,7 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, goto out; vwrq->value = val; - vwrq->disabled = ((val < MRVDRV_RTS_MIN_VALUE) - || (val > MRVDRV_RTS_MAX_VALUE)); + vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */ vwrq->fixed = 1; out: -- cgit v1.2.3 From 47a227db746edbcfc8b78ac8a7787733faf6f171 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 23 Sep 2008 00:23:30 -0700 Subject: zd1211: Use skb_queue_walk() instead of by-hand implementation. Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a3da014f928..fe1867b25ff 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -611,7 +611,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, q = &zd_hw_mac(hw)->ack_wait_queue; spin_lock_irqsave(&q->lock, flags); - for (skb = q->next; skb != (struct sk_buff *)q; skb = skb->next) { + skb_queue_walk(q, skb) { struct ieee80211_hdr *tx_hdr; tx_hdr = (struct ieee80211_hdr *)skb->data; -- cgit v1.2.3 From 9930ccee16addda9fa7d9af00cd03cd5a10c8965 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 13 Sep 2008 12:22:05 +0100 Subject: wireless: Read scan flags correctly on x86-64 The SIOCSIWSCAN handler is passed data in an iw_point structure. Some drivers erronously use an iw_param instead. On 32 bit architectures the difference isn't noticed as the flags parameter tends to be the only one used by scan handlers and is at the same offset. On 64 bit architectures the pointer in the iw_point structure means the flag parameter is at different offsets in these structures. Thanks to Jean Tourrilhes for tracking this down for orinoco, and Pavel Roskin for confirming the fix and identifying other suspect handlers. Signed-off-by: David Kilroy Acked-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/atmel.c | 2 +- drivers/net/wireless/orinoco.c | 2 +- drivers/net/wireless/rndis_wlan.c | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ae58a12befd..370133e492d 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7107,7 +7107,7 @@ static int airo_get_aplist(struct net_device *dev, */ static int airo_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + struct iw_point *dwrq, char *extra) { struct airo_info *ai = dev->priv; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index bd65c485098..ecb02bdaab5 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -2258,7 +2258,7 @@ static int atmel_get_freq(struct net_device *dev, static int atmel_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, + struct iw_point *dwrq, char *extra) { struct atmel_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 9a2fcc0163d..50904771f29 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -5291,7 +5291,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev, /* Trigger a scan (look for other cells in the vicinity) */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *srq, + struct iw_point *srq, char *extra) { struct orinoco_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 00e965b9da7..2b414899dfa 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1627,7 +1627,6 @@ 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 iw_param *param = &wrqu->param; struct usbnet *usbdev = dev->priv; union iwreq_data evt; int ret = -EINVAL; @@ -1635,7 +1634,7 @@ static int rndis_iw_set_scan(struct net_device *dev, devdbg(usbdev, "SIOCSIWSCAN"); - if (param->flags == 0) { + if (wrqu->data.flags == 0) { tmp = ccpu2(1); ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, sizeof(tmp)); -- cgit v1.2.3 From fdd1097488e3c1278996bd7c73d8429d410e725a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 16 Sep 2008 14:56:49 -0500 Subject: b43: Issue warning when RFKILL_INPUT is not enabled If the system is misconfigured with CONFIG_RFKILL set but CONFIG_RFKILL_INPUT not set, the built-in radio LEDs will not work. In the current code, no warning is issued. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/rfkill.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 7b9e99adb8c..96902da7d66 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -188,6 +188,11 @@ void b43_rfkill_init(struct b43_wldev *dev) "The built-in radio LED will not work.\n"); #endif /* CONFIG_RFKILL_INPUT */ +#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE) + b43warn(wl, "The rfkill-input subsystem is not available. " + "The built-in radio LED will not work.\n"); +#endif + err = input_register_polled_device(rfk->poll_dev); if (err) goto err_unreg_rfk; -- cgit v1.2.3 From 9ccacb86b5c613b25f41ca4227c3fb17bcd77de0 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 16 Sep 2008 14:01:03 +0800 Subject: iwlwifi: don't delay scan in IBSS mode Scan need to be delayed only after association to allow EAPOL exchange. We don't need the delay for IBSS mode. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 27376276976..970d0b32265 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2568,8 +2568,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) iwl_chain_noise_reset(priv); priv->start_calib = 1; - /* we have just associated, don't start scan too early */ - priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); @@ -3171,6 +3169,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, priv->power_data.dtim_period = bss_conf->dtim_period; priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; + + /* we have just associated, don't start scan too early + * leave time for EAPOL exchange to complete + */ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; mutex_lock(&priv->mutex); -- cgit v1.2.3 From 9e5e6c327defcef19dabad64335ee68bb55b2355 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 16 Sep 2008 14:01:04 +0800 Subject: iwlwifi: make PS use named constants This patch adds named constants for configuring MIMO power save chain settings. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d80184ee911..8203887ca00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -697,8 +697,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) } EXPORT_SYMBOL(iwl_set_rxon_ht); -/* - * Determine how many receiver/antenna chains to use. +#define IWL_NUM_RX_CHAINS_MULTIPLE 3 +#define IWL_NUM_RX_CHAINS_SINGLE 2 +#define IWL_NUM_IDLE_CHAINS_DUAL 2 +#define IWL_NUM_IDLE_CHAINS_SINGLE 1 + +/* Determine how many receiver/antenna chains to use. * More provides better reception via diversity. Fewer saves power. * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. @@ -711,9 +715,9 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) /* # of Rx chains to use when expecting MIMO. */ if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == WLAN_HT_CAP_SM_PS_STATIC))) - return 2; + return IWL_NUM_RX_CHAINS_SINGLE; else - return 3; + return IWL_NUM_RX_CHAINS_MULTIPLE; } static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) @@ -724,10 +728,11 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) switch (priv->current_ht_config.sm_ps) { case WLAN_HT_CAP_SM_PS_STATIC: case WLAN_HT_CAP_SM_PS_DYNAMIC: - idle_cnt = (is_cam) ? 2 : 1; + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; break; case WLAN_HT_CAP_SM_PS_DISABLED: - idle_cnt = (is_cam) ? active_cnt : 1; + idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; break; case WLAN_HT_CAP_SM_PS_INVALID: default: @@ -796,7 +801,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); - if (!is_single && (active_rx_cnt >= 2) && is_cam) + if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam) priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; else priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; -- cgit v1.2.3 From 84e463fa0786a105c39281b90f8e3b6fe1444a05 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Wed, 17 Sep 2008 03:33:19 +0300 Subject: ath5k: Fix bad udelay calls on AR5210 code * Fix bad udelay calls (using > 2000us) in AR5210 code and clean up some bits on nic_reset (AR5210 support is still in bad shape) Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/phy.c | 2 +- drivers/net/wireless/ath5k/reg.h | 2 -- drivers/net/wireless/ath5k/reset.c | 20 +++++++++++++------- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 1ea8ed962d2..e43f6563e61 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -2124,7 +2124,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - udelay(2300); + mdelay(2); /* * Set the channel (with AGC turned off) diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index a9883236444..410f99a6d61 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -820,8 +820,6 @@ #define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ #define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ #define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ -#define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \ - AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY) /* * Sleep control register diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index f5c3de890cd..953ba3b19ff 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -173,8 +173,10 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) udelay(15); if (ah->ah_version == AR5K_AR5210) { - val &= AR5K_RESET_CTL_CHIP; - mask &= AR5K_RESET_CTL_CHIP; + val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA + | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY; + mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA + | AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY; } else { val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; @@ -361,16 +363,20 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; /* Reset chipset */ - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_BASEBAND | bus_flags); + if (ah->ah_version == AR5K_AR5210) { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | + AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); + mdelay(2); + } else { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + } if (ret) { ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); return -EIO; } - if (ah->ah_version == AR5K_AR5210) - udelay(2300); - /* ...wakeup again!*/ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { -- cgit v1.2.3 From 9c40fc510a3df3a74731f5f251b9481feffc0ed5 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 16 Sep 2008 18:08:39 -0700 Subject: libertas: Reduce the WPA key installation time (fixups) This patch addresses comments from Dan Williams about the patch committed as "libertas: Reduce the WPA key installation time." Signed-off-by: Javier Cardona Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/wext.c | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index acb889e2590..f6f3753da30 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -58,6 +58,7 @@ struct lbs_802_11_security { u8 WPA2enabled; u8 wep_enabled; u8 auth_mode; + u32 key_mgmt; }; /** Current Basic Service Set State Structure */ diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 11297dcf9fc..6ebdd7f161f 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1598,8 +1598,20 @@ static int lbs_set_encodeext(struct net_device *dev, } out: - if (ret == 0) { /* key installation is time critical: postpone not! */ - lbs_do_association_work(priv); + if (ret == 0) { + /* 802.1x and WPA rekeying must happen as quickly as possible, + * especially during the 4-way handshake; thus if in + * infrastructure mode, and either (a) 802.1x is enabled or + * (b) WPA is being used, set the key right away. + */ + if (assoc_req->mode == IW_MODE_INFRA && + ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) || + (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) || + assoc_req->secinfo.WPAenabled || + assoc_req->secinfo.WPA2enabled)) { + lbs_do_association_work(priv); + } else + lbs_postpone_association_work(priv); } else { lbs_cancel_association_work(priv); } @@ -1707,13 +1719,17 @@ static int lbs_set_auth(struct net_device *dev, case IW_AUTH_TKIP_COUNTERMEASURES: case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: case IW_AUTH_DROP_UNENCRYPTED: /* * libertas does not use these parameters */ break; + case IW_AUTH_KEY_MGMT: + assoc_req->secinfo.key_mgmt = dwrq->value; + updated = 1; + break; + case IW_AUTH_WPA_VERSION: if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { assoc_req->secinfo.WPAenabled = 0; @@ -1793,6 +1809,10 @@ static int lbs_get_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + dwrq->value = priv->secinfo.key_mgmt; + break; + case IW_AUTH_WPA_VERSION: dwrq->value = 0; if (priv->secinfo.WPAenabled) -- cgit v1.2.3 From 42eb7c644afcdbcd7eac4d862046230856fbf531 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 17 Sep 2008 10:10:05 +0800 Subject: iwlwifi: remove HT flags from RXON when not in HT anymore This patch removes the HT flags from RXON when moving from HT to legacy. This avoids keeping those flags set and possibly miss configuring firmware. If we are configured in HT, fat channel: channel 1 above, and move later to legacy channel 11, we need to clear the FAT channel control flags in RXON. If we don't, the firmware will understand this as channel 11 above which is not possible due to regulatory constraints, leading to firmware crash. Signed-off-by: Emmanuel Grumbach Reviewed-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-core.c | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 970d0b32265..d069549a01c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2504,8 +2504,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - if (priv->current_ht_config.is_ht) - iwl_set_rxon_ht(priv, &priv->current_ht_config); + iwl_set_rxon_ht(priv, &priv->current_ht_config); iwl_set_rxon_chain(priv); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8203887ca00..4c312c55f90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -646,8 +646,14 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; u32 val; - if (!ht_info->is_ht) + if (!ht_info->is_ht) { + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | + RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT_PROT_MSK); return; + } /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ if (iwl_is_fat_tx_allowed(priv, NULL)) -- cgit v1.2.3 From 980b24da6f1725c2d0b32c9484d06cd7d09d3c4b Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 17 Sep 2008 10:15:09 +0530 Subject: ath9k: Whitespace cleanup Also, remove comments that are not relevant anymore. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 136 ++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 76 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index c43fd586116..f8d952ca3f8 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -26,7 +26,6 @@ * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max */ - static int ath_beaconq_config(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; @@ -63,19 +62,18 @@ static int ath_beaconq_config(struct ath_softc *sc) * up all required antenna switch parameters, rate codes, and channel flags. * Beacons are always sent out at the lowest rate, and are not retried. */ - static void ath_beacon_setup(struct ath_softc *sc, - struct ath_vap *avp, struct ath_buf *bf) + struct ath_vap *avp, struct ath_buf *bf) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; - int flags, antenna; + struct ath9k_11n_rate_series series[4]; const struct ath9k_rate_table *rt; + int flags, antenna; u8 rix, rate; int ctsrate = 0; int ctsduration = 0; - struct ath9k_11n_rate_series series[4]; DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n", __func__, skb, skb->len); @@ -115,20 +113,21 @@ static void ath_beacon_setup(struct ath_softc *sc, rate |= rt->info[rix].shortPreamble; ath9k_hw_set11n_txdesc(ah, ds, - skb->len + FCS_LEN, /* frame length */ - ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ + skb->len + FCS_LEN, /* frame length */ + ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ avp->av_btxctl.txpower, /* txpower XXX */ - ATH9K_TXKEYIX_INVALID, /* no encryption */ - ATH9K_KEY_TYPE_CLEAR, /* no encryption */ - flags /* no ack, veol for beacons */ + ATH9K_TXKEYIX_INVALID, /* no encryption */ + ATH9K_KEY_TYPE_CLEAR, /* no encryption */ + flags /* no ack, + veol for beacons */ ); /* NB: beacon's BufLen must be a multiple of 4 bytes */ ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), /* buffer length */ - true, /* first segment */ - true, /* last segment */ - ds /* first descriptor */ + true, /* first segment */ + true, /* last segment */ + ds /* first descriptor */ ); memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); @@ -153,22 +152,23 @@ 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; - int cabq_depth; struct ath_txq *cabq; struct ieee80211_tx_info *info; + int cabq_depth; + avp = sc->sc_vaps[if_id]; + ASSERT(avp); cabq = sc->sc_cabq; - ASSERT(avp); - if (avp->av_bcbuf == NULL) { DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", __func__, avp, avp->av_bcbuf); return NULL; } + bf = avp->av_bcbuf; - skb = (struct sk_buff *) bf->bf_mpdu; + skb = (struct sk_buff *)bf->bf_mpdu; if (skb) { pci_unmap_single(sc->pdev, bf->bf_dmacontext, skb_end_pointer(skb) - skb->head, @@ -179,17 +179,19 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) bf->bf_mpdu = skb; if (skb == NULL) return NULL; + info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { /* * TODO: make sure the seq# gets assigned properly (vs. other * TX frames) */ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; sc->seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); } + bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb_end_pointer(skb) - skb->head, @@ -241,7 +243,6 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * Startup beacon transmission for adhoc mode when they are sent entirely * by the hardware using the self-linked descriptor + veol trick. */ - static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) { struct ath_hal *ah = sc->sc_ah; @@ -278,7 +279,6 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) * 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; @@ -299,11 +299,10 @@ int ath_beaconq_setup(struct ath_hal *ah) * 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 ath_vap *avp; - struct ieee80211_hdr *wh; + struct ieee80211_hdr *hdr; struct ath_buf *bf; struct sk_buff *skb; @@ -312,13 +311,11 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) /* 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. - */ + /* Allocate beacon state for hostap/ibss. We know + * a buffer is available. */ avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, - struct ath_buf, list); + struct ath_buf, list); list_del(&avp->av_bcbuf->list); if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || @@ -362,9 +359,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) } /* - * NB: the beacon data buffer must be 32-bit aligned; - * we assume the wbuf routines will return us something - * with this alignment (perhaps should assert). + * NB: the beacon data buffer must be 32-bit aligned. * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ @@ -408,8 +403,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) __func__, "stagger", avp->av_bslot, intval, (unsigned long long)tsfadjust); - wh = (struct ieee80211_hdr *)skb->data; - memcpy(&wh[1], &val, sizeof(val)); + hdr = (struct ieee80211_hdr *)skb->data; + memcpy(&hdr[1], &val, sizeof(val)); } bf->bf_buf_addr = bf->bf_dmacontext = @@ -425,9 +420,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * 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 wbuf frames that were sent as CAB traffic. + * 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) { @@ -459,10 +453,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) * 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. - * - * This tasklet is not scheduled, it's called in ISR context. */ - void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -490,6 +481,8 @@ void ath9k_beacon_tasklet(unsigned long data) * and wait for the next. Missed beacons indicate * a problem and should not occur. If we miss too * many consecutive beacons reset the device. + * + * FIXME: Clean up this mess !! */ if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) { sc->sc_bmisscount++; @@ -505,19 +498,16 @@ void ath9k_beacon_tasklet(unsigned long data) __func__, sc->sc_bmisscount); if (show_cycles) { /* - * Display cycle counter stats - * from HW to aide in debug of - * stickiness. + * Display cycle counter stats from HW + * to aide in debug of stickiness. */ - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: busy times: rx_clear=%d, " "rx_frame=%d, tx_frame=%d\n", __func__, rx_clear, rx_frame, tx_frame); } else { - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: unable to obtain " "busy times\n", __func__); } @@ -529,8 +519,7 @@ void ath9k_beacon_tasklet(unsigned long data) } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_bmisscount == BSTUCK_THRESH) { - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: beacon is officially " "stuck\n", __func__); ath9k_hw_dmaRegDump(ah); @@ -542,13 +531,12 @@ void ath9k_beacon_tasklet(unsigned long data) ath_bstuck_process(sc); } } - return; } + if (sc->sc_bmisscount != 0) { if (sc->sc_flags & SC_OP_NO_RESET) { - DPRINTF(sc, - ATH_DBG_BEACON, + DPRINTF(sc, ATH_DBG_BEACON, "%s: resume beacon xmit after %u misses\n", __func__, sc->sc_bmisscount); } else { @@ -572,10 +560,12 @@ void ath9k_beacon_tasklet(unsigned long data) tsftu = TSF_TO_TU(tsf>>32, tsf); slot = ((tsftu % intval) * ATH_BCBUF) / intval; if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; + DPRINTF(sc, ATH_DBG_BEACON, - "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", - __func__, slot, (unsigned long long) tsf, tsftu, - intval, if_id); + "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", + __func__, slot, (unsigned long long)tsf, tsftu, + intval, if_id); + bfaddr = 0; if (if_id != ATH_IF_ID_ANY) { bf = ath_beacon_generate(sc, if_id); @@ -632,9 +622,8 @@ void ath9k_beacon_tasklet(unsigned long data) * Tasklet for Beacon Stuck processing * * Processing for Beacon Stuck. - * Basically calls the ath_internal_reset function to reset the chip. + * Basically resets the chip. */ - void ath_bstuck_process(struct ath_softc *sc) { DPRINTF(sc, ATH_DBG_BEACON, @@ -658,13 +647,12 @@ void ath_bstuck_process(struct ath_softc *sc) * interrupt when we stop seeing beacons from the AP * we've associated with. */ - void ath_beacon_config(struct ath_softc *sc, int if_id) { struct ath_hal *ah = sc->sc_ah; - u32 nexttbtt, intval; struct ath_beacon_config conf; enum ath9k_opmode av_opmode; + u32 nexttbtt, intval; if (if_id != ATH_IF_ID_ANY) av_opmode = sc->sc_vaps[if_id]->av_opmode; @@ -673,12 +661,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) memzero(&conf, sizeof(struct ath_beacon_config)); - /* FIXME: Use default values for now - Sujith */ - /* Query beacon configuration first */ - /* - * Protocol stack doesn't support dynamic beacon configuration, - * use default configurations. - */ conf.beacon_interval = sc->hw->conf.beacon_int ? sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; conf.listen_interval = 1; @@ -704,12 +686,14 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; } - if (nexttbtt == 0) /* e.g. for ap mode */ + if (nexttbtt == 0) /* e.g. for ap mode */ nexttbtt = intval; - else if (intval) /* NB: can be 0 for monitor mode */ + 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); + /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { struct ath9k_beacon_state bs; @@ -723,19 +707,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * last beacon we received (which may be none). */ dtimperiod = conf.dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ + if (dtimperiod <= 0) /* NB: 0 if not known */ dtimperiod = 1; dtimcount = conf.dtim_count; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; /* XXX? */ - cfpperiod = 1; /* NB: no PCF support yet */ + if (dtimcount >= dtimperiod) /* NB: sanity check */ + dtimcount = 0; + cfpperiod = 1; /* NB: no PCF support yet */ cfpcount = 0; sleepduration = conf.listen_interval * intval; if (sleepduration <= 0) sleepduration = intval; -#define FUDGE 2 +#define FUDGE 2 /* * Pull nexttbtt forward to reflect the current * TSF and calculate dtim+cfp state for the result. @@ -759,6 +743,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; bs.bs_cfpmaxduration = 0; + /* * Calculate the number of consecutive beacons to miss * before taking a BMISS interrupt. The configuration @@ -767,9 +752,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * result to at most 15 beacons. */ if (sleepduration > intval) { - bs.bs_bmissthreshold = - conf.listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; + bs.bs_bmissthreshold = conf.listen_interval * + ATH_DEFAULT_BMISS_LIMIT / 2; } else { bs.bs_bmissthreshold = DIV_ROUND_UP(conf.bmiss_timeout, intval); @@ -789,8 +773,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * XXX fixed at 100ms */ - bs.bs_sleepduration = - roundup(IEEE80211_MS_TO_TU(100), sleepduration); + bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), + sleepduration); if (bs.bs_sleepduration > bs.bs_dtimperiod) bs.bs_sleepduration = bs.bs_dtimperiod; @@ -834,9 +818,9 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { /* * Pull nexttbtt forward to reflect the current - * TSF . + * TSF */ -#define FUDGE 2 +#define FUDGE 2 if (!(intval & ATH9K_BEACON_RESET_TSF)) { tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU((u32)(tsf>>32), -- cgit v1.2.3 From 459f5f90f1bd959ced04761406415b178b315177 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 17 Sep 2008 10:15:36 +0530 Subject: ath9k: Fix nexttbtt calculation nexttbtt has to be obtained from the timestamp of the beacon obtained from mac80211. Fix this. And is not needed anymore. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 9 ++++++--- drivers/net/wireless/ath9k/core.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index f8d952ca3f8..eedb465d25d 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -16,7 +16,6 @@ /* Implementation of beacon processing. */ -#include #include "core.h" /* @@ -305,6 +304,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) struct ieee80211_hdr *hdr; struct ath_buf *bf; struct sk_buff *skb; + __le64 tstamp; avp = sc->sc_vaps[if_id]; ASSERT(avp); @@ -370,6 +370,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) return -ENOMEM; } + tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + sc->bc_tstamp = le64_to_cpu(tstamp); + /* * Calculate a TSF adjustment factor required for * staggered beacons. Note that we assume the format @@ -669,8 +672,8 @@ 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(get_unaligned_le32(conf.u.last_tstamp + 4), - get_unaligned_le32(conf.u.last_tstamp)); + nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); + /* XXX conditionalize multi-bss support? */ if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index b66de29cf66..6ff3befe39f 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1001,6 +1001,7 @@ struct ath_softc { u32 sc_bhalq; u32 sc_bmisscount; u32 ast_be_xmit; /* beacons transmitted */ + u64 bc_tstamp; /* Rate */ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; -- cgit v1.2.3 From 31e9ab2b180bccb3977b9a82ff357ac4c6ee3c83 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 17 Sep 2008 10:16:07 +0530 Subject: ath9k: Fix TSF Adjust usage TSF adjust is needed only for AP mode when staggered beacons are used. Since we support only a single interface in IBSS mode, disable setting the TSF adjust register. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index c262ef279ff..690f7c56af3 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -534,7 +534,8 @@ int ath_vap_attach(struct ath_softc *sc, avp->av_opmode = opmode; avp->av_bslot = -1; - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + if (opmode == ATH9K_M_HOSTAP) + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); sc->sc_vaps[if_id] = avp; sc->sc_nvaps++; -- cgit v1.2.3 From 4b7679a561e552eeda1e3567119bef2bca99b66e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Sep 2008 18:14:18 +0200 Subject: mac80211: clean up rate control API Long awaited, hard work. This patch totally cleans up the rate control API to remove the requirement to include internal headers outside of net/mac80211/. There's one internal use in the PID algorithm left for mesh networking, we'll have to figure out a way to clean that one up and decide how to do the peer link evaluation, possibly independent of the rate control algorithm or via new API. Additionally, ath9k is left using the cross-inclusion hack for now, we will add new API where necessary to make this work properly, but right now I'm not expert enough to do it. It's still off better than before. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/rc.c | 98 +++++++-------- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 182 ++++++---------------------- drivers/net/wireless/iwlwifi/iwl-3945-rs.h | 9 -- drivers/net/wireless/iwlwifi/iwl-3945.h | 4 + drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 146 +++++++++------------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 11 +- 6 files changed, 146 insertions(+), 304 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1cc9daf4455..cca2fc5b076 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -20,6 +20,7 @@ */ #include "core.h" +/* FIXME: remove this include! */ #include "../net/mac80211/rate.h" static u32 tx_triglevel_max; @@ -1812,20 +1813,18 @@ static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv) } -static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta) +static void ath_setup_rates(struct ath_softc *sc, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, + struct ath_rate_node *rc_priv) { - struct ieee80211_supported_band *sband; - struct ieee80211_hw *hw = local_to_hw(local); - struct ath_softc *sc = hw->priv; - struct ath_rate_node *rc_priv = sta->rate_ctrl_priv; int i, j = 0; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < sband->n_bitrates; i++) { - if (sta->sta.supp_rates[local->hw.conf.channel->band] & BIT(i)) { + if (sta->supp_rates[sband->band] & BIT(i)) { rc_priv->neg_rates.rs_rates[j] = (sband->bitrates[i].bitrate * 2) / 10; j++; @@ -1852,19 +1851,17 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) } /* Rate Control callbacks */ -static void ath_tx_status(void *priv, struct net_device *dev, +static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { struct ath_softc *sc = priv; struct ath_tx_info_priv *tx_info_priv; struct ath_node *an; - struct sta_info *sta; - struct ieee80211_local *local; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; __le16 fc; - local = hw_to_local(sc->hw); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; @@ -1873,8 +1870,7 @@ static void ath_tx_status(void *priv, struct net_device *dev, an = ath_node_find(sc, hdr->addr1); spin_unlock_bh(&sc->node_lock); - sta = sta_info_get(local, hdr->addr1); - if (!an || !sta || !ieee80211_is_data(fc)) { + 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; @@ -1882,24 +1878,22 @@ static void ath_tx_status(void *priv, struct net_device *dev, return; } if (tx_info->driver_data[0] != NULL) { - ath_rate_tx_complete(sc, an, sta->rate_ctrl_priv, tx_info_priv); + 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 sta_info *sta, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, struct ath_node *an, u8 tidno) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_local *local; struct ath_atx_tid *txtid; - struct ieee80211_supported_band *sband; u16 buffersize = 0; int state; - DECLARE_MAC_BUF(mac); + struct sta_info *si; if (!(sc->sc_flags & SC_OP_TXAGGR)) return; @@ -1908,11 +1902,16 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, if (!txtid->paused) return; - local = hw_to_local(sc->hw); - sband = hw->wiphy->bands[hw->conf.channel->band]; + /* + * XXX: This is entirely busted, we aren't supposed to + * access the sta from here because it's internal + * to mac80211, and looking at the state without + * locking is wrong too. + */ + si = container_of(sta, struct sta_info, sta); buffersize = IEEE80211_MIN_AMPDU_BUF << sband->ht_info.ampdu_factor; /* FIXME */ - state = sta->ampdu_mlme.tid_state_tx[tidno]; + state = si->ampdu_mlme.tid_state_tx[tidno]; if (state & HT_ADDBA_RECEIVED_MSK) { txtid->addba_exchangecomplete = 1; @@ -1928,18 +1927,15 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, } } -static void ath_get_rate(void *priv, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) +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) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ath_softc *sc = (struct ath_softc *)priv; + 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; + struct ath_rate_node *ath_rc_priv = priv_sta; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); int is_probe = FALSE, chk, ret; @@ -1955,8 +1951,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, ASSERT(tx_info->driver_data[0] != NULL); tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - sta = sta_info_get(local, hdr->addr1); - lowest_idx = rate_lowest_index(local, sband, sta); + 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) || @@ -1965,8 +1960,6 @@ static void ath_get_rate(void *priv, struct net_device *dev, return; } - ath_rc_priv = sta->rate_ctrl_priv; - /* Find tx rate for unicast frames */ ath_rate_findrate(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, @@ -1975,8 +1968,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, &is_probe, false); if (is_probe) - sel->probe_idx = ((struct ath_tx_ratectrl *) - sta->rate_ctrl_priv)->probe_rate; + sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; /* Ratecontrol sometimes returns invalid rate index */ if (tx_info_priv->rcs[0].rix != 0xff) @@ -2020,37 +2012,31 @@ static void ath_get_rate(void *priv, struct net_device *dev, __func__, print_mac(mac, hdr->addr1)); } else if (chk == AGGR_EXCHANGE_PROGRESS) - ath_tx_aggr_resp(sc, sta, an, tid); + ath_tx_aggr_resp(sc, sband, sta, an, tid); } } } -static void ath_rate_init(void *priv, void *priv_sta, - struct ieee80211_local *local, - struct sta_info *sta) +static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) { - struct ieee80211_supported_band *sband; - struct ieee80211_hw *hw = local_to_hw(local); - struct ieee80211_conf *conf = &local->hw.conf; - struct ath_softc *sc = hw->priv; + struct ath_softc *sc = priv; struct ath_rate_node *ath_rc_priv = priv_sta; int i, j = 0; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - ath_setup_rates(local, sta); - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + 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 (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) + if (sc->hw->conf.ht_conf.supp_mcs_set[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(hw, priv_sta); + ath_rc_node_update(sc->hw, priv_sta); } static void ath_rate_clear(void *priv) @@ -2058,13 +2044,12 @@ static void ath_rate_clear(void *priv) return; } -static void *ath_rate_alloc(struct ieee80211_local *local) +static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ieee80211_hw *hw = local_to_hw(local); struct ath_softc *sc = hw->priv; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - return local->hw.priv; + return hw->priv; } static void ath_rate_free(void *priv) @@ -2072,7 +2057,7 @@ static void ath_rate_free(void *priv) return; } -static void *ath_rate_alloc_sta(void *priv, gfp_t gfp) +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]; @@ -2092,7 +2077,8 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp) return rate_priv; } -static void ath_rate_free_sta(void *priv, void *priv_sta) +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; @@ -2111,7 +2097,7 @@ static struct rate_control_ops ath_rate_ops = { .alloc = ath_rate_alloc, .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, - .free_sta = ath_rate_free_sta + .free_sta = ath_rate_free_sta, }; int ath_rate_control_register(void) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index a279bf1dc9b..6fc5e7361f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -36,8 +36,6 @@ #include -#include "../net/mac80211/rate.h" - #include "iwl-3945.h" #define RS_NAME "iwl-3945-rs" @@ -319,10 +317,10 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, } } -static void rs_rate_init(void *priv_rate, void *priv_sta, - struct ieee80211_local *local, struct sta_info *sta) +static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) { - struct iwl3945_rs_sta *rs_sta = (void *)sta->rate_ctrl_priv; + struct iwl3945_rs_sta *rs_sta = priv_sta; int i; IWL_DEBUG_RATE("enter\n"); @@ -333,22 +331,22 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * after assoc.. */ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { - if (sta->sta.supp_rates[local->hw.conf.channel->band] & (1 << i)) { + if (sta->supp_rates[sband->band] & (1 << i)) { rs_sta->last_txrate_idx = i; break; } } /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ - if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + if (sband->band == IEEE80211_BAND_5GHZ) rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; IWL_DEBUG_RATE("leave\n"); } -static void *rs_alloc(struct ieee80211_local *local) +static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - return local->hw.priv; + return hw->priv; } /* rate scale requires free function to be implemented */ @@ -356,17 +354,24 @@ static void rs_free(void *priv) { return; } + static void rs_clear(void *priv) { return; } -static void *rs_alloc_sta(void *priv, gfp_t gfp) +static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; + struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; int i; + /* + * XXX: If it's using sta->drv_priv anyway, it might + * as well just put all the information there. + */ + IWL_DEBUG_RATE("enter\n"); rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp); @@ -375,6 +380,8 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp) return NULL; } + psta->rs_sta = rs_sta; + spin_lock_init(&rs_sta->lock); rs_sta->start_rate = IWL_RATE_INVALID; @@ -400,10 +407,14 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp) return rs_sta; } -static void rs_free_sta(void *priv, void *priv_sta) +static void rs_free_sta(void *priv, struct ieee80211_sta *sta, + void *priv_sta) { + struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; struct iwl3945_rs_sta *rs_sta = priv_sta; + psta->rs_sta = NULL; + IWL_DEBUG_RATE("enter\n"); del_timer_sync(&rs_sta->rate_scale_flush); kfree(rs_sta); @@ -445,26 +456,19 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by * the hardware for each rate. */ -static void rs_tx_status(void *priv_rate, - struct net_device *dev, +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; int scale_rate_index, first_index, last_index; unsigned long flags; - struct sta_info *sta; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iwl3945_rs_sta *rs_sta; - struct ieee80211_supported_band *sband; + struct iwl3945_rs_sta *rs_sta = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - retries = info->status.retry_count; first_index = sband->bitrates[info->tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { @@ -472,17 +476,11 @@ static void rs_tx_status(void *priv_rate, return; } - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - if (!sta || !sta->rate_ctrl_priv) { - rcu_read_unlock(); + if (!priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); return; } - rs_sta = (void *)sta->rate_ctrl_priv; - rs_sta->tx_packets++; scale_rate_index = first_index; @@ -549,8 +547,6 @@ static void rs_tx_status(void *priv_rate, spin_unlock_irqrestore(&rs_sta->lock, flags); - rcu_read_unlock(); - IWL_DEBUG_RATE("leave\n"); return; @@ -634,16 +630,15 @@ 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_rate, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) +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) { u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; int index; - struct iwl3945_rs_sta *rs_sta; + struct iwl3945_rs_sta *rs_sta = priv_sta; struct iwl3945_rate_scale_data *window = NULL; int current_tpt = IWL_INV_TPT; int low_tpt = IWL_INV_TPT; @@ -651,34 +646,25 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, u32 fail_count; s8 scale_action = 0; unsigned long flags; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct sta_info *sta; u16 fc, rate_mask; - struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; DECLARE_MAC_BUF(mac); IWL_DEBUG_RATE("enter\n"); - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - /* Send management frames and broadcast/multicast data using lowest * rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || - !sta || !sta->rate_ctrl_priv) { + !sta || !priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate_idx = rate_lowest_index(local, sband, sta); - rcu_read_unlock(); + sel->rate_idx = rate_lowest_index(sband, sta); return; } - rs_sta = (void *)sta->rate_ctrl_priv; - - rate_mask = sta->sta.supp_rates[sband->band]; + rate_mask = sta->supp_rates[sband->band]; index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); if (sband->band == IEEE80211_BAND_5GHZ) @@ -811,8 +797,6 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, else sel->rate_idx = rs_sta->last_txrate_idx; - rcu_read_unlock(); - IWL_DEBUG_RATE("leave: %d\n", index); } @@ -829,114 +813,28 @@ static struct rate_control_ops rs_ops = { .free_sta = rs_free_sta, }; -int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct iwl3945_priv *priv = hw->priv; - struct iwl3945_rs_sta *rs_sta; - struct sta_info *sta; - unsigned long flags; - int count = 0, i; - u32 samples = 0, success = 0, good = 0; - unsigned long now = jiffies; - u32 max_time = 0; - - rcu_read_lock(); - - sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); - if (!sta || !sta->rate_ctrl_priv) { - if (sta) - IWL_DEBUG_RATE("leave - no private rate data!\n"); - else - IWL_DEBUG_RATE("leave - no station!\n"); - rcu_read_unlock(); - return sprintf(buf, "station %d not found\n", sta_id); - } - - rs_sta = (void *)sta->rate_ctrl_priv; - spin_lock_irqsave(&rs_sta->lock, flags); - i = IWL_RATE_54M_INDEX; - while (1) { - u64 mask; - int j; - - count += - sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2); - - mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); - for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) - buf[count++] = - (rs_sta->win[i].data & mask) ? '1' : '0'; - - samples += rs_sta->win[i].counter; - good += rs_sta->win[i].success_counter; - success += rs_sta->win[i].success_counter * - iwl3945_rates[i].ieee; - - if (rs_sta->win[i].stamp) { - int delta = - jiffies_to_msecs(now - rs_sta->win[i].stamp); - - if (delta > max_time) - max_time = delta; - - count += sprintf(&buf[count], "%5dms\n", delta); - } else - buf[count++] = '\n'; - - j = iwl3945_get_prev_ieee_rate(i); - if (j == i) - break; - i = j; - } - spin_unlock_irqrestore(&rs_sta->lock, flags); - rcu_read_unlock(); - - /* Display the average rate of all samples taken. - * - * NOTE: We multiple # of samples by 2 since the IEEE measurement - * added from iwl3945_rates is actually 2X the rate */ - if (samples) - count += sprintf( - &buf[count], - "\nAverage rate is %3d.%02dMbs over last %4dms\n" - "%3d%% success (%d good packets over %d tries)\n", - success / (2 * samples), (success * 5 / samples) % 10, - max_time, good * 100 / samples, good, samples); - else - count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); - - return count; -} - void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) { struct iwl3945_priv *priv = hw->priv; s32 rssi = 0; unsigned long flags; - struct ieee80211_local *local = hw_to_local(hw); struct iwl3945_rs_sta *rs_sta; - struct sta_info *sta; + struct ieee80211_sta *sta; + struct iwl3945_sta_priv *psta; IWL_DEBUG_RATE("enter\n"); - if (!local->rate_ctrl->ops->name || - strcmp(local->rate_ctrl->ops->name, RS_NAME)) { - IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n"); - IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n"); - return; - } - rcu_read_lock(); - sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); - if (!sta || !sta->rate_ctrl_priv) { + 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"); rcu_read_unlock(); return; } - rs_sta = (void *)sta->rate_ctrl_priv; + rs_sta = psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index f085d330bdc..98b17ae6ef2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -175,15 +175,6 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) return rate; } -/** - * iwl3945_fill_rs_info - Fill an output text buffer with the rate representation - * - * NOTE: This is provided as a quick mechanism for a user to visualize - * the performance of the rate control algorithm and is not meant to be - * parsed software. - */ -extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); - /** * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info * diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 2a4933b5fb6..bdd32475b99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -73,6 +73,10 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; extern int iwl3945_param_hwcrypto; extern int iwl3945_param_queues_num; +struct iwl3945_sta_priv { + struct iwl3945_rs_sta *rs_sta; +}; + enum iwl3945_antenna { IWL_ANTENNA_DIVERSITY, IWL_ANTENNA_MAIN, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8b57b390c8b..93944de923c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -35,8 +35,6 @@ #include -#include "../net/mac80211/rate.h" - #include "iwl-dev.h" #include "iwl-sta.h" #include "iwl-core.h" @@ -169,9 +167,9 @@ struct iwl_lq_sta { }; static void rs_rate_scale_perform(struct iwl_priv *priv, - struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta); + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta); static void rs_fill_link_cmd(const struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); @@ -357,20 +355,20 @@ static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, - struct sta_info *sta) + 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->sta.addr), tid); - ieee80211_start_tx_ba_session(priv->hw, sta->sta.addr, tid); + print_mac(mac, sta->addr), tid); + ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); } } static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, struct iwl_lq_sta *lq_data, - struct sta_info *sta) + struct ieee80211_sta *sta) { if ((tid < TID_MAX_LOAD_COUNT)) rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); @@ -770,7 +768,8 @@ out: /* * mac80211 sends us Tx status */ -static void rs_tx_status(void *priv_rate, struct net_device *dev, +static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { int status; @@ -778,11 +777,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, int rs_index, index = 0; struct iwl_lq_sta *lq_sta; struct iwl_link_quality_cmd *table; - struct sta_info *sta; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = local_to_hw(local); + struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct ieee80211_hw *hw = priv->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_rate_scale_data *window = NULL; struct iwl_rate_scale_data *search_win = NULL; @@ -808,15 +805,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (retries > 15) retries = 15; - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - - if (!sta || !sta->rate_ctrl_priv) - goto out; - - - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + lq_sta = (struct iwl_lq_sta *)priv_sta; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) @@ -962,9 +951,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, } /* See if there's a better rate or modulation mode to try. */ - rs_rate_scale_perform(priv, dev, hdr, sta); + rs_rate_scale_perform(priv, hdr, sta, lq_sta); out: - rcu_read_unlock(); return; } @@ -1140,7 +1128,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, static int rs_switch_to_mimo2(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, + struct ieee80211_sta *sta, struct iwl_scale_tbl_info *tbl, int index) { u16 rate_mask; @@ -1148,10 +1136,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s8 is_green = lq_sta->is_green; if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->sta.ht_info.ht_supported) + !sta->ht_info.ht_supported) return -1; - if (((sta->sta.ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == WLAN_HT_CAP_SM_PS_STATIC) return -1; @@ -1208,7 +1196,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, static int rs_switch_to_siso(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, + struct ieee80211_sta *sta, struct iwl_scale_tbl_info *tbl, int index) { u16 rate_mask; @@ -1216,7 +1204,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, s32 rate; if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->sta.ht_info.ht_supported) + !sta->ht_info.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); @@ -1268,7 +1256,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, static int rs_move_legacy_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, + struct ieee80211_sta *sta, int index) { struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1376,7 +1364,7 @@ out: static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, int index) + struct ieee80211_sta *sta, int index) { u8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1487,7 +1475,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, static int rs_move_mimo_to_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, - struct sta_info *sta, int index) + struct ieee80211_sta *sta, int index) { s8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1680,12 +1668,11 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) * Do rate scaling and search for new modulation mode. */ static void rs_rate_scale_perform(struct iwl_priv *priv, - struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta) + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_hw *hw = priv->hw; struct ieee80211_conf *conf = &hw->conf; int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; @@ -1700,7 +1687,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, __le16 fc; u16 rate_mask; u8 update_lq = 0; - struct iwl_lq_sta *lq_sta; struct iwl_scale_tbl_info *tbl, *tbl1; u16 rate_scale_index_msk = 0; u32 rate; @@ -1721,11 +1707,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, return; } - if (!sta || !sta->rate_ctrl_priv) + if (!sta || !lq_sta) return; - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; - lq_sta->supp_rates = sta->sta.supp_rates[lq_sta->band]; + lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); @@ -2064,9 +2049,9 @@ out: static void rs_initialize_lq(struct iwl_priv *priv, struct ieee80211_conf *conf, - struct sta_info *sta) + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) { - struct iwl_lq_sta *lq_sta; struct iwl_scale_tbl_info *tbl; int rate_idx; int i; @@ -2075,10 +2060,9 @@ static void rs_initialize_lq(struct iwl_priv *priv, u8 active_tbl = 0; u8 valid_tx_ant; - if (!sta || !sta->rate_ctrl_priv) + if (!sta || !lq_sta) goto out; - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; i = lq_sta->last_txrate_idx; if ((lq_sta->lq.sta_id == 0xff) && @@ -2119,37 +2103,30 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; } -static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) +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) { int i; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; + struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct sta_info *sta; __le16 fc; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_lq_sta *lq_sta; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - /* 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 || !sta->rate_ctrl_priv) { - sel->rate_idx = rate_lowest_index(local, sband, sta); - goto out; + !sta || !priv_sta) { + sel->rate_idx = rate_lowest_index(sband, sta); + return; } - lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + lq_sta = (struct iwl_lq_sta *)priv_sta; i = lq_sta->last_txrate_idx; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && @@ -2167,23 +2144,22 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, lq_sta->lq.sta_id = sta_id; lq_sta->lq.rs_table[0].rate_n_flags = 0; lq_sta->ibss_sta_added = 1; - rs_initialize_lq(priv, conf, sta); + rs_initialize_lq(priv, conf, sta, lq_sta); } } if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(local, sband, sta); - goto out; + sel->rate_idx = rate_lowest_index(sband, sta); + return; } if (sband->band == IEEE80211_BAND_5GHZ) i -= IWL_FIRST_OFDM_RATE; sel->rate_idx = i; -out: - rcu_read_unlock(); } -static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) +static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, + gfp_t gfp) { struct iwl_lq_sta *lq_sta; struct iwl_priv *priv; @@ -2206,20 +2182,16 @@ static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) return lq_sta; } -static void rs_rate_init(void *priv_rate, void *priv_sta, - struct ieee80211_local *local, - struct sta_info *sta) +static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta, void *priv_sta) { int i, j; - struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_supported_band *sband; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_priv *priv = (struct iwl_priv *)priv_r; + struct ieee80211_conf *conf = &priv->hw->conf; struct iwl_lq_sta *lq_sta = priv_sta; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - lq_sta->flush_timer = 0; - lq_sta->supp_rates = sta->sta.supp_rates[sband->band]; + lq_sta->supp_rates = sta->supp_rates[sband->band]; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); @@ -2232,17 +2204,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { - u8 sta_id = iwl_find_station(priv, sta->sta.addr); + 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->sta.addr)); + print_mac(mac, sta->addr)); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->sta.addr)); - sta_id = iwl_add_station_flags(priv, sta->sta.addr, + print_mac(mac, sta->addr)); + sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { @@ -2256,11 +2228,11 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, /* 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->sta.supp_rates[sband->band] & BIT(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 (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + if (sband->band == IEEE80211_BAND_5GHZ) lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; @@ -2301,7 +2273,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; - rs_initialize_lq(priv, conf, sta); + rs_initialize_lq(priv, conf, sta, lq_sta); } static void rs_fill_link_cmd(const struct iwl_priv *priv, @@ -2423,9 +2395,9 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); } -static void *rs_alloc(struct ieee80211_local *local) +static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - return local->hw.priv; + return hw->priv; } /* rate scale requires free function to be implemented */ static void rs_free(void *priv_rate) @@ -2446,12 +2418,12 @@ static void rs_clear(void *priv_rate) #endif /* CONFIG_IWLWIFI_DEBUG */ } -static void rs_free_sta(void *priv_rate, void *priv_sta) +static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, + void *priv_sta) { struct iwl_lq_sta *lq_sta = priv_sta; - struct iwl_priv *priv; + struct iwl_priv *priv = priv_r; - priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE("enter\n"); kfree(lq_sta); IWL_DEBUG_RATE("leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 62b26befddc..d15a2c99795 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7370,15 +7370,6 @@ static ssize_t show_temperature(struct device *d, static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); -static ssize_t show_rs_window(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct iwl3945_priv *priv = d->driver_data; - return iwl3945_fill_rs_info(priv->hw, buf, IWL_AP_ID); -} -static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); - static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { @@ -7840,7 +7831,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, @@ -7908,6 +7898,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e SET_IEEE80211_DEV(hw, &pdev->dev); hw->rate_control_algorithm = "iwl-3945-rs"; + hw->sta_data_size = sizeof(struct iwl3945_sta_priv); IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); priv = hw->priv; -- cgit v1.2.3 From e6c948e8b8e565c7666ea482994e422c4f19ea44 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 22 Sep 2008 01:14:02 -0700 Subject: ath9k: Add a few comments about mibevents Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 0251e59f2f8..272c7581660 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2526,6 +2526,11 @@ static void ath9k_ani_reset(struct ath_hal *ah) } } +/* + * 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) { @@ -2533,18 +2538,20 @@ void ath9k_hw_procmibevent(struct ath_hal *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) || @@ -2552,6 +2559,7 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, 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; @@ -2562,11 +2570,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah, 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); } } -- cgit v1.2.3 From acaf908d408ccd49f13aeb46cbd4428a4db174d1 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 22 Sep 2008 19:40:04 +0200 Subject: rt2x00: Fix HW crypto key handling When a crypto key is being removed, rt2x00mac should not reset the key->hw_key_idx value because that will prevent the driver from removing the correct key from the hardware. Furthermore ffz() starts counting at 0 instead of 1, so we don't need to substract 1 from the resulting value. Signed-off-by: Stephen Blackheath Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 ++- drivers/net/wireless/rt2x00/rt61pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt73usb.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 485c40de5cc..2c6cc5c374f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -543,7 +543,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * provided but key 0 is not, then the key is not found * by the hardware during RX). */ - key->hw_key_idx = 0; + if (cmd == SET_KEY) + key->hw_key_idx = 0; if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) set_key = rt2x00dev->ops->lib->config_pairwise_key; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2c36b91ff4c..a461620b489 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -381,7 +381,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, if (reg && reg == mask) return -ENOSPC; - key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + key->hw_key_idx += reg ? ffz(reg) : 0; /* * Upload key to hardware @@ -477,7 +477,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, return -ENOSPC; } - key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + key->hw_key_idx += reg ? ffz(reg) : 0; /* * Upload key to hardware diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 27dde3e3460..934f8e03c5a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -393,7 +393,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, if (reg && reg == mask) return -ENOSPC; - key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + key->hw_key_idx += reg ? ffz(reg) : 0; /* * Upload key to hardware @@ -494,7 +494,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, return -ENOSPC; } - key->hw_key_idx += reg ? (ffz(reg) - 1) : 0; + key->hw_key_idx += reg ? ffz(reg) : 0; /* * Upload key to hardware -- cgit v1.2.3 From 47cbb1107e4172f3632713d74dc8651a32ceb294 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 23 Sep 2008 13:53:09 +0100 Subject: pcmcia: Fix up legacy driver IRQs The PCMCIA layer obsoleted asking for per device private IRQS some years ago and all the drivers by inspection correctly use dev_id and handle shared interrupts [they get em anyway in most PCI bridged PCMCIA/Cardbus] so can be adjusted. This gets rid of the various bugs reported where there is spewage about conflicting irq types and sometimes the driver won't load. (Note I don't have all of these devices to test each one beyond by inspection) Signed-off-by: Alan Cox Signed-off-by: John W. Linville --- drivers/net/wireless/airo_cs.c | 2 +- drivers/net/wireless/atmel_cs.c | 2 +- drivers/net/wireless/netwave_cs.c | 2 +- drivers/net/wireless/orinoco_cs.c | 2 +- drivers/net/wireless/ray_cs.c | 2 +- drivers/net/wireless/spectrum_cs.c | 2 +- drivers/net/wireless/wavelan_cs.c | 2 +- drivers/net/wireless/wl3501_cs.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index f12355398fe..fd72e427cb2 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -147,7 +147,7 @@ static int airo_probe(struct pcmcia_device *p_dev) DEBUG(0, "airo_attach()\n"); /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = NULL; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 12617cd0b78..d2388e8d179 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -158,7 +158,7 @@ static int atmel_probe(struct pcmcia_device *p_dev) DEBUG(0, "atmel_attach()\n"); /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = NULL; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index f479c1af678..25bae7933aa 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -398,7 +398,7 @@ static int netwave_probe(struct pcmcia_device *link) link->io.IOAddrLines = 5; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = &netwave_interrupt; diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1ccf5a40cf0..9eaa252c243 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -121,7 +121,7 @@ orinoco_cs_probe(struct pcmcia_device *link) link->priv = dev; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; link->irq.Instance = dev; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 963960dc30f..44da0d19b5c 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -325,7 +325,7 @@ static int ray_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 5; /* Interrupt setup. For PCMCIA, driver takes what's given */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = &ray_interrupt; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index e368759d1d8..67b26d3c3cd 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -195,7 +195,7 @@ spectrum_cs_probe(struct pcmcia_device *link) link->priv = dev; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; link->irq.Instance = dev; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 00a3559e5aa..b5de38a9b79 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4496,7 +4496,7 @@ wavelan_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 3; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = wavelan_interrupt; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index b6d4e04b8ab..74a5ad2f122 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1917,7 +1917,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 5; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = wl3501_interrupt; -- cgit v1.2.3 From 55d6a3cd0cc85ed90c39cf32e16f622bd003117b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Sep 2008 19:18:43 +0200 Subject: iwlagn: downgrade BUG_ON in interrupt This BUG_ON really shouldn't trigger, but if it does, as on my machine, it leaves you wondering what happened because you won't see it. Let's instead leak a bit of state and memory and at least make it possible to report it to the kerneloops project to track it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index e9feca4033f..907a53ebc6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1200,10 +1200,9 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced * in the queue management code. */ - if (txq_id != IWL_CMD_QUEUE_NUM) - IWL_ERROR("Error wrong command queue %d command id 0x%X\n", - txq_id, pkt->hdr.cmd); - BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + if (WARN(txq_id != IWL_CMD_QUEUE_NUM, + "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd)) + return; cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; -- cgit v1.2.3 From 8d09a5e1c36d0dec5728e6c8b0bb5412de09b27b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 24 Sep 2008 13:57:46 +0800 Subject: iwlwifi: don't fail if scan is issued too early This patch returns success and empty scan on scans requests that were rejected because issued too early. The cached bss list from previous scanning will be returned by mac80211. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 15 +++++++++++---- drivers/net/wireless/iwlwifi/iwl-scan.c | 8 +------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d069549a01c..7330890fd05 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3190,9 +3190,9 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) { - int ret; unsigned long flags; struct iwl_priv *priv = hw->priv; + int ret; IWL_DEBUG_MAC80211("enter\n"); @@ -3211,20 +3211,27 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) goto out_unlock; } - /* we don't schedule scan within next_scan_jiffies period */ + /* We don't schedule scan within next_scan_jiffies period. + * Avoid scanning during possible EAPOL exchange, return + * success immediately. + */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { IWL_DEBUG_SCAN("scan rejected: within next scan period\n"); - ret = -EAGAIN; + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; goto out_unlock; } + /* if we just finished scan ask for delay */ if (iwl_is_associated(priv) && priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { IWL_DEBUG_SCAN("scan rejected: within previous scan period\n"); - ret = -EAGAIN; + queue_work(priv->workqueue, &priv->scan_completed); + ret = 0; goto out_unlock; } + if (ssid_len) { priv->one_direct_scan = 1; priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 09c264be049..bf855c35b0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -463,11 +463,6 @@ void iwl_init_scan_params(struct iwl_priv *priv) int iwl_scan_initiate(struct iwl_priv *priv) { - if (priv->iw_mode == NL80211_IFTYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; @@ -479,8 +474,7 @@ int iwl_scan_initiate(struct iwl_priv *priv) } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN("Scan request while abort pending. " - "Queuing.\n"); + IWL_DEBUG_SCAN("Scan request while abort pending\n"); return -EAGAIN; } -- cgit v1.2.3 From 3bb91bff8165223aa14f015a6c9150a536b40d9b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 19 Sep 2008 14:47:38 -0500 Subject: b43: Fix Bluetooth coexistence SPROM coding error for Motorola 7010 variant of BCM4306 An additional BCM4306 has been found with the Bluetooth coexistence SPROM coding error. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0f628a29d83..2968919a827 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4545,7 +4545,8 @@ static void b43_sprom_fixup(struct ssb_bus *bus) IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) || - IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013)) + IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) || + IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010)) bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST; } } -- cgit v1.2.3 From 1f1c0e33a0ab1379272da68fe58abf586c8e96e5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 25 Sep 2008 14:54:28 -0500 Subject: p54: Fix sparse warnings The command make C=2 CF="-D__CHECK_ENDIAN__" drivers/net/wireless/p54/ generates the following warnings: .../p54common.c:152:38: warning: incorrect type in argument 1 (different base types) .../p54common.c:152:38: expected restricted __be32 const [usertype] *p .../p54common.c:152:38: got unsigned int * .../p54common.c:184:15: warning: restricted __le32 degrades to integer .../p54common.c:185:29: warning: cast to restricted __le16 .../p54common.c:309:11: warning: symbol 'p54_rf_chips' was not declared. Should it be static? .../p54common.c:313:5: warning: symbol 'p54_parse_eeprom' was not declared. Should it be static? .../p54common.c:620:43: warning: incorrect type in argument 3 (different base types) .../p54common.c:620:43: expected unsigned long [unsigned] [usertype] len .../p54common.c:620:43: got restricted __le16 [usertype] len .../p54common.c:780:41: warning: restricted __le16 degrades to integer .../p54common.c:781:32: warning: restricted __le16 degrades to integer .../p54common.c:1250:28: warning: incorrect type in argument 2 (different base types) .../p54common.c:1250:28: expected unsigned short [unsigned] [usertype] filter_type .../p54common.c:1250:28: got restricted __le16 [usertype] filter_type .../p54common.c:1252:28: warning: incorrect type in argument 2 (different base types) .../p54common.c:1252:28: expected unsigned short [unsigned] [usertype] filter_type .../p54common.c:1252:28: got restricted __le16 [usertype] filter_type .../p54common.c:1257:42: warning: incorrect type in argument 2 (different base types) .../p54common.c:1257:42: expected unsigned short [unsigned] [usertype] filter_type .../p54common.c:1257:42: got restricted __le16 .../p54common.c:1260:42: warning: incorrect type in argument 2 (different base types) .../p54common.c:1260:42: expected unsigned short [unsigned] [usertype] filter_type .../p54common.c:1260:42: got restricted __le16 .../p54usb.c:228:10: warning: restricted __le32 degrades to integer .../p54usb.c:228:23: warning: restricted __le32 degrades to integer .../p54usb.c:228:7: warning: incorrect type in assignment (different base types) .../p54usb.c:228:7: expected restricted __le32 [assigned] [usertype] chk .../p54usb.c:228:7: got unsigned int .../p54usb.c:221:8: warning: symbol 'p54u_lm87_chksum' was not declared. Should it be static? All of the above have been fixed. One question, however, remains: In struct bootrec, the array "data" is treated in many places as native CPU order, but it may be little-endian everywhere. As far as I can tell, this driver has only been used with little-endian hardware. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 33 ++++++++++++++++++--------------- drivers/net/wireless/p54/p54common.h | 3 ++- drivers/net/wireless/p54/p54usb.c | 8 ++++---- 3 files changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index bac58ed03e5..de5e8f44b20 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -149,7 +149,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) u32 code = le32_to_cpu(bootrec->code); switch (code) { case BR_CODE_COMPONENT_ID: - priv->fw_interface = be32_to_cpup(bootrec->data); + priv->fw_interface = be32_to_cpup((__be32 *) + bootrec->data); switch (priv->fw_interface) { case FW_FMAC: printk(KERN_INFO "p54: FreeMAC firmware\n"); @@ -181,9 +182,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; - if (bootrec->len == 11) - priv->rx_mtu = (size_t) le16_to_cpu( - (__le16)bootrec->data[10]); + if (le32_to_cpu(bootrec->len) == 11) + priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu); else priv->rx_mtu = (size_t) 0x620 - priv->tx_hdr_len; @@ -306,11 +306,11 @@ static int p54_convert_rev1(struct ieee80211_hw *dev, return 0; } -const char* p54_rf_chips[] = { "NULL", "Indigo?", "Duette", +static const char *p54_rf_chips[] = { "NULL", "Indigo?", "Duette", "Frisbee", "Xbow", "Longbow" }; static int p54_init_xbow_synth(struct ieee80211_hw *dev); -int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) +static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; struct eeprom_pda_wrap *wrap = NULL; @@ -617,7 +617,7 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, if (!priv->eeprom) return ; - memcpy(priv->eeprom, eeprom->data, eeprom->len); + memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len)); complete(&priv->eeprom_comp); } @@ -777,8 +777,9 @@ int p54_read_eeprom(struct ieee80211_hw *dev) 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, hdr->len + sizeof(*hdr)); - priv->tx(dev, hdr, hdr->len + sizeof(*hdr), 0); + 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); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -1247,18 +1248,20 @@ static void p54_configure_filter(struct ieee80211_hw *dev, if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, priv->filter_type, NULL); + p54_set_filter(dev, le16_to_cpu(priv->filter_type), + NULL); else - p54_set_filter(dev, priv->filter_type, priv->bssid); + 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, priv->filter_type | - cpu_to_le16(0x8), NULL); + p54_set_filter(dev, le16_to_cpu(priv->filter_type) | + 0x8, NULL); else - p54_set_filter(dev, priv->filter_type & - ~cpu_to_le16(0x8), priv->bssid); + p54_set_filter(dev, le16_to_cpu(priv->filter_type) & + ~0x8, priv->bssid); } } diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 4da736c789a..2fa994cfcfe 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -18,7 +18,8 @@ struct bootrec { __le32 code; __le32 len; - u32 data[0]; + u32 data[10]; + __le16 rx_mtu; } __attribute__((packed)); struct bootrec_exp_if { diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 7444f372977..1912f5e9a0a 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -218,17 +218,17 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, usb_submit_urb(data_urb, GFP_ATOMIC); } -__le32 p54u_lm87_chksum(const u32 *data, size_t length) +static __le32 p54u_lm87_chksum(const u32 *data, size_t length) { - __le32 chk = 0; + u32 chk = 0; length >>= 2; while (length--) { - chk ^= cpu_to_le32(*data++); + chk ^= *data++; chk = (chk >> 5) ^ (chk << 3); } - return chk; + return cpu_to_le32(chk); } static void p54u_tx_lm87(struct ieee80211_hw *dev, -- cgit v1.2.3 From 8cd519e89616057c8a433a54a3e60883e4893017 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 26 Sep 2008 15:09:32 +0800 Subject: iwlwifi: refactor rx register initialization The patch adds HW bug W/A FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY so that we can enable again interrupt coalescing. It also uses named constants for open code. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 2 +- drivers/net/wireless/iwlwifi/iwl-fh.h | 9 +++++---- drivers/net/wireless/iwlwifi/iwl-rx.c | 30 +++++++++++++++++++----------- 3 files changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 52629fbd835..662edf4f8d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -64,7 +64,7 @@ #define CSR_BASE (0x000) #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index cd11c0ca299..a72efdf6d1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -247,8 +247,8 @@ #define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */ #define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/ -#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) -#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS (20) +#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS (4) #define RX_RB_TIMEOUT (0x10) #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) @@ -260,8 +260,9 @@ #define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) #define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) +#define FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY (0x00000004) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) /** diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 38b2946b1d8..7cde9d76ff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -376,7 +376,9 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { int ret; unsigned long flags; - unsigned int rb_size; + u32 rb_size; + const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ + const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */ spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); @@ -398,26 +400,32 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Tell device where to find RBD circular buffer in DRAM */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - rxq->dma_addr >> 8); + (u32)(rxq->dma_addr >> 8)); /* 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); - /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ + /* Enable Rx DMA + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in + * the credit mechanism in 5000 HW RX FIFO + * Direct rx interrupts to hosts + * Rx buffer size 4 or 8k + * RB timeout 0x10 + * 256 RBDs + */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 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 | - rb_size | - /* 0x10 << 4 | */ - (RX_QUEUE_SIZE_LOG << - FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); - - /* - * iwl_write32(priv,CSR_INT_COAL_REG,0); - */ + rb_size| + (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| + (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); iwl_release_nic_access(priv); + + iwl_write32(priv, CSR_INT_COALESCING, 0x40); + spin_unlock_irqrestore(&priv->lock, flags); return 0; -- cgit v1.2.3 From e602cb180e97c46dfb01a4644781ec68ee0cda22 Mon Sep 17 00:00:00 2001 From: Ester Kummer Date: Fri, 26 Sep 2008 15:09:33 +0800 Subject: iwlwifi: enable power save setting upon config This patch enables power save setting from config (iwconfig power) The sysfs power_level interface is still preserved as it has mac80211 power implementation is not yet rich enough. Signed-off-by: Ester Kummer Reviewed-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7330890fd05..a589f7ea57f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2875,6 +2875,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co goto out; } + if (conf->flags & IEEE80211_CONF_PS) + ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); + else + ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); + if (ret) + IWL_DEBUG_MAC80211("Error setting power level\n"); + IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", priv->tx_power_user_lmt, conf->power_level); -- cgit v1.2.3 From 093d874c02e8d3091aa38596faf0ff2bfd4f0ceb Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Fri, 26 Sep 2008 15:09:34 +0800 Subject: iwlwifi: use correct DMA_MASK Use correct DMA_MASK: 4964 and 5000 support 36 bit addresses for pci express memory access. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a589f7ea57f..204abab7644 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4243,13 +4243,13 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36)); if (err) { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); /* both attempts failed: */ if (err) { printk(KERN_WARNING "%s: No suitable DMA available.\n", -- cgit v1.2.3 From 570bdfb17dfc92061f7e26f6320b309c1df00997 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 26 Sep 2008 08:23:00 -0500 Subject: b43: Fix Bluetooth Coexistence SPROM programming error for HP 12f8 version of BCM4306 Yet another BCM4306 card with the Bluetooth Coexistence SPROM programming error has been found. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2968919a827..e5e71220e7d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4543,6 +4543,7 @@ static void b43_sprom_fixup(struct ssb_bus *bus) pdev = bus->host_pci; if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) || IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) || + IS_PDEV(pdev, BROADCOM, 0x4320, HP, 0x12f8) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) || IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) || -- cgit v1.2.3 From 3ed6e0803b4fe95107f6cb5a432587d03cd4d17a Mon Sep 17 00:00:00 2001 From: Anna Neal Date: Fri, 26 Sep 2008 11:34:35 -0400 Subject: libertas: Improvements on automatic tx power control via SIOCSIWTXPOW (fixups) This patch addresses comments from Dan Williams about the patch committed as "libertas: Improvements on automatic tx power control via SIOCSIWTXPOW." Signed-off-by: Anna Neal Signed-off-by: Javier Cardona Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/cmd.h | 6 ++++++ drivers/net/wireless/libertas/defs.h | 1 - drivers/net/wireless/libertas/wext.c | 12 ++++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index aee19fa844e..a912fb68c09 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1949,7 +1949,7 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); cmd.enable = !!enable; - cmd.usesnr = !!enable; + cmd.usesnr = !!usesnr; cmd.P0 = p0; cmd.P1 = p1; cmd.P2 = p2; diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index d002160f597..36be4c9703e 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -32,6 +32,12 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, int8_t p2, int usesnr); +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2); + +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr); + int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 58d11a35e61..076a636e8f6 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -189,7 +189,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MRVDRV_CMD_UPLD_RDY 0x0008 #define MRVDRV_CARDEVENT 0x0010 - /* Automatic TX control default levels */ #define POW_ADAPT_DEFAULT_P0 13 #define POW_ADAPT_DEFAULT_P1 15 diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 6ebdd7f161f..82c3e5a50ea 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1025,6 +1025,18 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, new_rate); goto out; } + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 0, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; } /* Try the newer command first (Firmware Spec 5.1 and above) */ -- cgit v1.2.3 From 4c99f3e4cfc3190e01c55e72d15a837d9dc41426 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 28 Sep 2008 15:11:38 +0200 Subject: rt2x00: Fix build errors due to modularized rfkill or leds and built-in rt2x00. Fix by disabling rt2x00 rfkill support when rt2x00 is built-in and rfkill has been modularized, and a similar scheme for the relationship between leds_class and rt2x00.. Also, give a warning to the end-user when rfkill-/leds-support is disabled this way, so that the end-user has at least some clues on what is going on. Proper fixing required some general updates of the Kconfig-structure for the rt2x00 driver, whereby internal configuration symbols had to be moved to after the user-visible configuration symbols. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 69 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index b686dc45483..f839ce044af 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,5 +1,5 @@ -config RT2X00 - tristate "Ralink driver support" +menuconfig RT2X00 + bool "Ralink driver support" depends on MAC80211 && WLAN_80211 && EXPERIMENTAL ---help--- This will enable the experimental support for the Ralink drivers, @@ -17,39 +17,6 @@ config RT2X00 if RT2X00 -config RT2X00_LIB - tristate - -config RT2X00_LIB_PCI - tristate - select RT2X00_LIB - -config RT2X00_LIB_USB - tristate - select RT2X00_LIB - -config RT2X00_LIB_FIRMWARE - boolean - depends on RT2X00_LIB - select FW_LOADER - -config RT2X00_LIB_CRYPTO - boolean - depends on RT2X00_LIB - -config RT2X00_LIB_RFKILL - boolean - depends on RT2X00_LIB - depends on RFKILL - default y - -config RT2X00_LIB_LEDS - boolean - depends on RT2X00_LIB - depends on NEW_LEDS - depends on LEDS_CLASS - default y - config RT2400PCI tristate "Ralink rt2400 (PCI/PCMCIA) support" depends on PCI @@ -109,6 +76,38 @@ config RT73USB When compiled as a module, this driver will be called "rt73usb.ko". +config RT2X00_LIB_PCI + tristate + select RT2X00_LIB + +config RT2X00_LIB_USB + tristate + select RT2X00_LIB + +config RT2X00_LIB + tristate + +config RT2X00_LIB_FIRMWARE + boolean + select FW_LOADER + +config RT2X00_LIB_CRYPTO + boolean + +config RT2X00_LIB_RFKILL + boolean + default y if (RT2X00_LIB=y && RFKILL=y) || (RT2X00_LIB=m && RFKILL!=n) + +comment "rt2x00 rfkill support disabled due to modularized RFKILL and built-in rt2x00" + depends on RT2X00_LIB=y && RFKILL=m + +config RT2X00_LIB_LEDS + boolean + default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) + +comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00" + depends on RT2X00_LIB=y && LEDS_CLASS=m + config RT2X00_LIB_DEBUGFS bool "Ralink debugfs support" depends on RT2X00_LIB && MAC80211_DEBUGFS -- cgit v1.2.3 From 14be9947ef9843102b67d315c7483de112b5b2d7 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sun, 28 Sep 2008 12:09:43 -0400 Subject: ath5k: write beacon control register twice when resetting tsf According to the newly-released Atheros HAL code, asserting the TSF reset bit will toggle a hardware internal state, resulting in a spurious reset on the next chip reset. Whenever we force a TSF bit, write the bit twice to clear the internal signal. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/pcu.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index c77cee2a558..a47df9a24aa 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -633,8 +633,20 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) */ void ath5k_hw_reset_tsf(struct ath5k_hw *ah) { + u32 val; + ATH5K_TRACE(ah->ah_sc); - AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF); + + val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF; + + /* + * Each write to the RESET_TSF bit toggles a hardware internal + * signal to reset TSF, but if left high it will cause a TSF reset + * on the next chip reset as well. Thus we always write the value + * twice to clear the signal. + */ + ath5k_hw_reg_write(ah, val, AR5K_BEACON); + ath5k_hw_reg_write(ah, val, AR5K_BEACON); } /* -- cgit v1.2.3 From 1bef016a5a2c52de45b332c8fa797958becde9bf Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 29 Sep 2008 02:09:09 +0300 Subject: ath5k: Update registers and SREV ids v2 * Update registers * Update SREV values and add some PHY srevs * Prepare ath5k.h for newer radios etc Thanks to Atheros 's HAL source we now know for sure how many parts we have and what their SREV values are. We also have some updates on registers. Prepare ath5k for some major updates ;-) My previous mail had 2 more patches following (git log misusage), sorry for double posting ;-( Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 59 ++-- drivers/net/wireless/ath5k/attach.c | 26 +- drivers/net/wireless/ath5k/base.c | 50 ++-- drivers/net/wireless/ath5k/qcu.c | 8 +- drivers/net/wireless/ath5k/reg.h | 577 +++++++++++++++++++++++++----------- drivers/net/wireless/ath5k/reset.c | 8 +- 6 files changed, 490 insertions(+), 238 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 20018869051..7134c40d6a6 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -281,7 +281,9 @@ enum ath5k_radio { AR5K_RF5112 = 2, AR5K_RF2413 = 3, AR5K_RF5413 = 4, - AR5K_RF2425 = 5, + AR5K_RF2316 = 5, + AR5K_RF2317 = 6, + AR5K_RF2425 = 7, }; /* @@ -289,7 +291,7 @@ enum ath5k_radio { */ enum ath5k_srev_type { - AR5K_VERSION_VER, + AR5K_VERSION_MAC, AR5K_VERSION_RAD, }; @@ -301,23 +303,24 @@ struct ath5k_srev_name { #define AR5K_SREV_UNKNOWN 0xffff -#define AR5K_SREV_VER_AR5210 0x00 -#define AR5K_SREV_VER_AR5311 0x10 -#define AR5K_SREV_VER_AR5311A 0x20 -#define AR5K_SREV_VER_AR5311B 0x30 -#define AR5K_SREV_VER_AR5211 0x40 -#define AR5K_SREV_VER_AR5212 0x50 -#define AR5K_SREV_VER_AR5213 0x55 -#define AR5K_SREV_VER_AR5213A 0x59 -#define AR5K_SREV_VER_AR2413 0x78 -#define AR5K_SREV_VER_AR2414 0x79 -#define AR5K_SREV_VER_AR2424 0xa0 /* PCI-E */ -#define AR5K_SREV_VER_AR5424 0xa3 /* PCI-E */ -#define AR5K_SREV_VER_AR5413 0xa4 -#define AR5K_SREV_VER_AR5414 0xa5 -#define AR5K_SREV_VER_AR5416 0xc0 /* PCI-E */ -#define AR5K_SREV_VER_AR5418 0xca /* PCI-E */ -#define AR5K_SREV_VER_AR2425 0xe2 /* PCI-E */ +#define AR5K_SREV_AR5210 0x00 /* Crete */ +#define AR5K_SREV_AR5311 0x10 /* Maui 1 */ +#define AR5K_SREV_AR5311A 0x20 /* Maui 2 */ +#define AR5K_SREV_AR5311B 0x30 /* Spirit */ +#define AR5K_SREV_AR5211 0x40 /* Oahu */ +#define AR5K_SREV_AR5212 0x50 /* Venice */ +#define AR5K_SREV_AR5213 0x55 /* ??? */ +#define AR5K_SREV_AR5213A 0x59 /* Hainan */ +#define AR5K_SREV_AR2413 0x78 /* Griffin lite */ +#define AR5K_SREV_AR2414 0x70 /* Griffin */ +#define AR5K_SREV_AR5424 0x90 /* Condor */ +#define AR5K_SREV_AR5413 0xa4 /* Eagle lite */ +#define AR5K_SREV_AR5414 0xa0 /* Eagle */ +#define AR5K_SREV_AR2415 0xb0 /* Cobra */ +#define AR5K_SREV_AR5416 0xc0 /* PCI-E */ +#define AR5K_SREV_AR5418 0xca /* PCI-E */ +#define AR5K_SREV_AR2425 0xe0 /* Swan */ +#define AR5K_SREV_AR2417 0xf0 /* Nala */ #define AR5K_SREV_RAD_5110 0x00 #define AR5K_SREV_RAD_5111 0x10 @@ -329,10 +332,20 @@ struct ath5k_srev_name { #define AR5K_SREV_RAD_2112 0x40 #define AR5K_SREV_RAD_2112A 0x45 #define AR5K_SREV_RAD_2112B 0x46 -#define AR5K_SREV_RAD_SC0 0x50 /* Found on 2413/2414 */ -#define AR5K_SREV_RAD_SC1 0x60 /* Found on 5413/5414 */ -#define AR5K_SREV_RAD_SC2 0xa0 /* Found on 2424-5/5424 */ -#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ +#define AR5K_SREV_RAD_2413 0x50 +#define AR5K_SREV_RAD_5413 0x60 +#define AR5K_SREV_RAD_2316 0x70 +#define AR5K_SREV_RAD_2317 0x80 +#define AR5K_SREV_RAD_5424 0xa0 /* Mostly same as 5413 */ +#define AR5K_SREV_RAD_2425 0xa2 +#define AR5K_SREV_RAD_5133 0xc0 + +#define AR5K_SREV_PHY_5211 0x30 +#define AR5K_SREV_PHY_5212 0x41 +#define AR5K_SREV_PHY_2112B 0x43 +#define AR5K_SREV_PHY_2413 0x45 +#define AR5K_SREV_PHY_5413 0x61 +#define AR5K_SREV_PHY_2425 0x70 /* IEEE defs */ #define IEEE80211_MAX_LEN 2500 diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 153c4111fab..d92b4a12567 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -168,19 +168,19 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) CHANNEL_2GHZ); /* Return on unsuported chips (unsupported eeprom etc) */ - if ((srev >= AR5K_SREV_VER_AR5416) && - (srev < AR5K_SREV_VER_AR2425)) { + if ((srev >= AR5K_SREV_AR5416) && + (srev < AR5K_SREV_AR2425)) { ATH5K_ERR(sc, "Device not yet supported.\n"); ret = -ENODEV; goto err_free; - } else if (srev == AR5K_SREV_VER_AR2425) { + } else if (srev == AR5K_SREV_AR2425) { ATH5K_WARN(sc, "Support for RF2425 is under development.\n"); } /* Identify single chip solutions */ - if (((srev <= AR5K_SREV_VER_AR5414) && - (srev >= AR5K_SREV_VER_AR2413)) || - (srev == AR5K_SREV_VER_AR2425)) { + if (((srev <= AR5K_SREV_AR5414) && + (srev >= AR5K_SREV_AR2413)) || + (srev == AR5K_SREV_AR2425)) { ah->ah_single_chip = true; } else { ah->ah_single_chip = false; @@ -199,24 +199,24 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) * correctly. For now we are based on mac's srev to * identify RF2425 radio. */ - } else if (srev == AR5K_SREV_VER_AR2425) { + } else if (srev == AR5K_SREV_AR2425) { ah->ah_radio = AR5K_RF2425; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { ah->ah_radio = AR5K_RF5111; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_2413) { ah->ah_radio = AR5K_RF5112; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5413) { ah->ah_radio = AR5K_RF2413; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) { + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_2316) { ah->ah_radio = AR5K_RF5413; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) { /* AR5424 */ - if (srev >= AR5K_SREV_VER_AR5424) { + if (srev >= AR5K_SREV_AR5424) { ah->ah_radio = AR5K_RF5413; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; /* AR2424 */ @@ -252,8 +252,8 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Write AR5K_PCICFG_UNK on 2112B and later chips */ if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B || - srev > AR5K_SREV_VER_AR2413) { - ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG); + srev > AR5K_SREV_AR2413) { + ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); } /* diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index e09ed2ce675..c8bb9bfb51f 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -100,34 +100,40 @@ MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); /* Known SREVs */ static struct ath5k_srev_name srev_names[] = { - { "5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210 }, - { "5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311 }, - { "5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A }, - { "5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B }, - { "5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211 }, - { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, - { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, - { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, - { "2413", AR5K_VERSION_VER, AR5K_SREV_VER_AR2413 }, - { "2414", AR5K_VERSION_VER, AR5K_SREV_VER_AR2414 }, - { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, - { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, - { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, - { "5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414 }, - { "5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416 }, - { "5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418 }, - { "2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425 }, - { "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN }, + { "5210", AR5K_VERSION_MAC, AR5K_SREV_AR5210 }, + { "5311", AR5K_VERSION_MAC, AR5K_SREV_AR5311 }, + { "5311A", AR5K_VERSION_MAC, AR5K_SREV_AR5311A }, + { "5311B", AR5K_VERSION_MAC, AR5K_SREV_AR5311B }, + { "5211", AR5K_VERSION_MAC, AR5K_SREV_AR5211 }, + { "5212", AR5K_VERSION_MAC, AR5K_SREV_AR5212 }, + { "5213", AR5K_VERSION_MAC, AR5K_SREV_AR5213 }, + { "5213A", AR5K_VERSION_MAC, AR5K_SREV_AR5213A }, + { "2413", AR5K_VERSION_MAC, AR5K_SREV_AR2413 }, + { "2414", AR5K_VERSION_MAC, AR5K_SREV_AR2414 }, + { "5424", AR5K_VERSION_MAC, AR5K_SREV_AR5424 }, + { "5413", AR5K_VERSION_MAC, AR5K_SREV_AR5413 }, + { "5414", AR5K_VERSION_MAC, AR5K_SREV_AR5414 }, + { "2415", AR5K_VERSION_MAC, AR5K_SREV_AR2415 }, + { "5416", AR5K_VERSION_MAC, AR5K_SREV_AR5416 }, + { "5418", AR5K_VERSION_MAC, AR5K_SREV_AR5418 }, + { "2425", AR5K_VERSION_MAC, AR5K_SREV_AR2425 }, + { "2417", AR5K_VERSION_MAC, AR5K_SREV_AR2417 }, + { "xxxxx", AR5K_VERSION_MAC, AR5K_SREV_UNKNOWN }, { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, + { "5111A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111A }, { "2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, { "5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, + { "5112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112B }, { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, - { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC0 }, - { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, - { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, + { "2112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112B }, + { "2413", AR5K_VERSION_RAD, AR5K_SREV_RAD_2413 }, + { "5413", AR5K_VERSION_RAD, AR5K_SREV_RAD_5413 }, + { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 }, + { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 }, + { "5424", AR5K_VERSION_RAD, AR5K_SREV_RAD_5424 }, { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, }; @@ -536,7 +542,7 @@ ath5k_pci_probe(struct pci_dev *pdev, goto err_ah; ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", - ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev), + ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev), sc->ah->ah_mac_srev, sc->ah->ah_phy_revision); diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c index 2e20f7816ca..01bf09176d2 100644 --- a/drivers/net/wireless/ath5k/qcu.c +++ b/drivers/net/wireless/ath5k/qcu.c @@ -375,7 +375,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) case AR5K_TX_QUEUE_BEACON: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_DBA_GT | - AR5K_QCU_MISC_CBREXP_BCN | + AR5K_QCU_MISC_CBREXP_BCN_DIS | AR5K_QCU_MISC_BCN_ENABLE); AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), @@ -395,8 +395,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) case AR5K_TX_QUEUE_CAB: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_DBA_GT | - AR5K_QCU_MISC_CBREXP | - AR5K_QCU_MISC_CBREXP_BCN); + AR5K_QCU_MISC_CBREXP_DIS | + AR5K_QCU_MISC_CBREXP_BCN_DIS); AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << @@ -405,7 +405,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) case AR5K_TX_QUEUE_UAPSD: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_CBREXP); + AR5K_QCU_MISC_CBREXP_DIS); break; case AR5K_TX_QUEUE_DATA: diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 410f99a6d61..55054b575e8 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -29,6 +29,10 @@ * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf * * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf + * + * This file also contains register values found on a memory dump of + * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal + * released by Atheros and on various debug messages found on the net. */ @@ -295,7 +299,7 @@ #define AR5K_ISR_RXPHY 0x00004000 /* PHY error */ #define AR5K_ISR_RXKCM 0x00008000 /* RX Key cache miss */ #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ -#define AR5K_ISR_BRSSI 0x00020000 +#define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ @@ -303,46 +307,56 @@ #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ #define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ -#define AR5K_ISR_TIM 0x00800000 /* [5210] */ -#define AR5K_ISR_BCNMISC 0x00800000 /* [5212+] */ -#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill)*/ -#define AR5K_ISR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ -#define AR5K_ISR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ -#define AR5K_ISR_QTRIG 0x08000000 /* [5211+] */ +#define AR5K_ISR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ +#define AR5K_ISR_TIM 0x00800000 /* [5211+] */ +#define AR5K_ISR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, + CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ +#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill) */ +#define AR5K_ISR_QCBRORN 0x02000000 /* QCU CBR overrun [5211+] */ +#define AR5K_ISR_QCBRURN 0x04000000 /* QCU CBR underrun [5211+] */ +#define AR5K_ISR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ /* * Secondary status registers [5211+] (0 - 4) * - * I guess from the names that these give the status for each - * queue, that's why only masks are defined here, haven't got - * any info about them (couldn't find them anywhere in ar5k code). + * These give the status for each QCU, only QCUs 0-9 are + * represented. */ #define AR5K_SISR0 0x0084 /* Register Address [5211+] */ #define AR5K_SISR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ +#define AR5K_SISR0_QCU_TXOK_S 0 #define AR5K_SISR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ +#define AR5K_SISR0_QCU_TXDESC_S 16 #define AR5K_SISR1 0x0088 /* Register Address [5211+] */ #define AR5K_SISR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ +#define AR5K_SISR1_QCU_TXERR_S 0 #define AR5K_SISR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ +#define AR5K_SISR1_QCU_TXEOL_S 16 #define AR5K_SISR2 0x008c /* Register Address [5211+] */ #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ +#define AR5K_SISR2_QCU_TXURN_S 0 #define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */ #define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SISR2_DPERR 0x00400000 /* Det par Error (?) */ +#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */ #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ #define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ +#define AR5K_SISR2_TSFOOR 0x80000000 /* TSF OOR (?) */ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ +#define AR5K_SISR3_QCBORN_S 0 #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ +#define AR5K_SISR3_QCBRURN_S 16 #define AR5K_SISR4 0x0094 /* Register Address [5211+] */ #define AR5K_SISR4_QTRIG 0x000003ff /* Mask for QTRIG */ +#define AR5K_SISR4_QTRIG_S 0 /* * Shadow read-and-clear interrupt status registers [5211+] @@ -379,7 +393,7 @@ #define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/ #define AR5K_IMR_RXKCM 0x00008000 /* RX Key cache miss */ #define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/ -#define AR5K_IMR_BRSSI 0x00020000 +#define AR5K_IMR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ #define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ @@ -387,12 +401,14 @@ #define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/ #define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */ #define AR5K_IMR_DPERR 0x00400000 /* Det par Error (?) [5210] */ +#define AR5K_IMR_RXDOPPLER 0x00400000 /* Doppler chirp received [5212+] */ #define AR5K_IMR_TIM 0x00800000 /* [5211+] */ -#define AR5K_IMR_BCNMISC 0x00800000 /* [5212+] */ +#define AR5K_IMR_BCNMISC 0x00800000 /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT, + CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */ #define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ -#define AR5K_IMR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ -#define AR5K_IMR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ -#define AR5K_IMR_QTRIG 0x08000000 /* [5211+] */ +#define AR5K_IMR_QCBRORN 0x02000000 /* QCU CBR overrun (?) [5211+] */ +#define AR5K_IMR_QCBRURN 0x04000000 /* QCU CBR underrun (?) [5211+] */ +#define AR5K_IMR_QTRIG 0x08000000 /* QCU scheduling trigger [5211+] */ /* * Secondary interrupt mask registers [5211+] (0 - 4) @@ -414,13 +430,14 @@ #define AR5K_SIMR2_QCU_TXURN_S 0 #define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */ #define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SIMR2_DPERR 0x00400000 /* Det par Error (?) */ +#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */ #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ #define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ #define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */ +#define AR5K_SIMR2_TSFOOR 0x80000000 /* TSF OOR (?) */ #define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ #define AR5K_SIMR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ @@ -586,15 +603,15 @@ #define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */ #define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ #define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ -#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */ -#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */ -#define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated (?) */ +#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated */ +#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* TIMT gated */ +#define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated */ #define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */ -#define AR5K_QCU_MISC_CBREXP 0x00000020 /* CBR expired (normal queue) */ -#define AR5K_QCU_MISC_CBREXP_BCN 0x00000040 /* CBR expired (beacon queue) */ +#define AR5K_QCU_MISC_CBREXP_DIS 0x00000020 /* Disable CBR expired counter (normal queue) */ +#define AR5K_QCU_MISC_CBREXP_BCN_DIS 0x00000040 /* Disable CBR expired counter (beacon queue) */ #define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Enable Beacon use */ -#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled */ -#define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME enalbed */ +#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR expired threshold enabled */ +#define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME expired or VEOL */ #define AR5K_QCU_MISC_CBR_RESET_CNT 0x00000400 /* CBR threshold (counter) reset */ #define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU early termination */ #define AR5K_QCU_MISC_DCU_CMP_EN 0x00001000 /* Enable frame compression */ @@ -663,6 +680,7 @@ #define AR5K_DCU_LCL_IFS_CW_MAX_S 10 #define AR5K_DCU_LCL_IFS_AIFS 0x0ff00000 /* Arbitrated Interframe Space */ #define AR5K_DCU_LCL_IFS_AIFS_S 20 +#define AR5K_DCU_LCL_IFS_AIFS_MAX 0xfc /* Anything above that can cause DCU to hang */ #define AR5K_QUEUE_DFS_LOCAL_IFS(_q) AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q) /* @@ -691,11 +709,7 @@ /* * DCU misc registers [5211+] * - * For some of the registers i couldn't find in the code - * (only backoff stuff is there realy) i tried to match the - * names with 802.11e parameters etc, so i guess VIRTCOL here - * means Virtual Collision and HCFPOLL means Hybrid Coordination - * factor Poll (CF- Poll). Arbiter lockout control controls the + * Note: Arbiter lockout control controls the * behaviour on low priority queues when we have multiple queues * with pending frames. Intra-frame lockout means we wait until * the queue's current frame transmits (with post frame backoff and bursting) @@ -705,15 +719,20 @@ * No lockout means there is no special handling. */ #define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ -#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff threshold */ +#define AR5K_DCU_MISC_BACKOFF 0x0000003f /* Mask for backoff threshold */ +#define AR5K_DCU_MISC_ETS_RTS_POL 0x00000040 /* End of transmission series + station RTS/data failure count + reset policy (?) */ +#define AR5K_DCU_MISC_ETS_CW_POL 0x00000080 /* End of transmission series + CW reset policy */ +#define AR5K_DCU_MISC_FRAG_WAIT 0x00000100 /* Wait for next fragment */ #define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */ #define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll enable */ #define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff */ #define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch */ #define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */ -#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 -#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1 -#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2 +#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 +#define AR5K_DCU_MISC_VIRTCOL_IGNORE 1 #define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Enable Beacon use */ #define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */ #define AR5K_DCU_MISC_ARBLOCK_CTL_S 17 @@ -768,8 +787,9 @@ #define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */ #define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */ #define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */ +#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S 10 #define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */ -#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFC cnt reset policy (?) */ +#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFS cnt reset policy (?) */ #define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST 0x00800000 /* AIFS cnt reset policy (?) */ #define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS 0x01000000 /* Disable random LFSR slice */ @@ -831,9 +851,11 @@ #define AR5K_SLEEP_CTL_SLE_S 16 #define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */ #define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */ -#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 +#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 /* Normal sleep policy */ #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ -/* more bits */ +#define AR5K_SLEEP_CTL_DUR_TIM_POL 0x00040000 /* Sleep duration timing policy */ +#define AR5K_SLEEP_CTL_DUR_WRITE_POL 0x00080000 /* Sleep duration write policy */ +#define AR5K_SLEEP_CTL_SLE_POL 0x00100000 /* Sleep policy mode */ /* * Interrupt pending register @@ -849,27 +871,28 @@ /* * PCI configuration register + * TODO: Fix LED stuff */ #define AR5K_PCICFG 0x4010 /* Register Address */ #define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ -#define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock (?) */ +#define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock */ #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ #define AR5K_PCICFG_EESIZE_S 3 #define AR5K_PCICFG_EESIZE_4K 0 /* 4K */ #define AR5K_PCICFG_EESIZE_8K 1 /* 8K */ #define AR5K_PCICFG_EESIZE_16K 2 /* 16K */ -#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size (?) [5211+] */ +#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size [5211+] */ #define AR5K_PCICFG_LED 0x00000060 /* Led status [5211+] */ #define AR5K_PCICFG_LED_NONE 0x00000000 /* Default [5211+] */ #define AR5K_PCICFG_LED_PEND 0x00000020 /* Scan / Auth pending */ #define AR5K_PCICFG_LED_ASSOC 0x00000040 /* Associated */ #define AR5K_PCICFG_BUS_SEL 0x00000380 /* Mask for "bus select" [5211+] (?) */ -#define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix (?) */ -#define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep (?) */ +#define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix */ +#define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep */ #define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ -#define AR5K_PCICFG_UNK 0x00001000 /* Passed on some parts durring attach (?) */ -#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts (?) */ +#define AR5K_PCICFG_RETRY_FIX 0x00001000 /* Enable pci core retry fix */ +#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts*/ #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ #define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ #define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ @@ -882,7 +905,8 @@ #define AR5K_PCICFG_LEDSTATE \ (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) -#define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate (field) */ +#define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate */ +#define AR5K_PCICFG_SLEEP_CLOCK_RATE_S 24 /* * "General Purpose Input/Output" (GPIO) control register @@ -904,8 +928,8 @@ #define AR5K_GPIOCR 0x4014 /* Register Address */ #define AR5K_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ -#define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is off (?) */ -#define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is on */ +#define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is low */ +#define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is high */ #define AR5K_GPIOCR_IN(n) (0 << ((n) * 2)) /* Mode 0 for pin n */ #define AR5K_GPIOCR_OUT0(n) (1 << ((n) * 2)) /* Mode 1 for pin n */ #define AR5K_GPIOCR_OUT1(n) (2 << ((n) * 2)) /* Mode 2 for pin n */ @@ -923,7 +947,6 @@ #define AR5K_GPIODI 0x401c #define AR5K_GPIODI_M 0x0000002f - /* * Silicon revision register */ @@ -933,7 +956,59 @@ #define AR5K_SREV_VER 0x000000ff /* Mask for version */ #define AR5K_SREV_VER_S 4 +/* + * TXE write posting register + */ +#define AR5K_TXEPOST 0x4028 + +/* + * QCU sleep mask + */ +#define AR5K_QCU_SLEEP_MASK 0x402c + +/* 0x4068 is compression buffer configuration + * register on 5414 and pm configuration register + * on 5424 and newer pci-e chips. */ + +/* + * Compression buffer configuration + * register (enable/disable) [5414] + */ +#define AR5K_5414_CBCFG 0x4068 +#define AR5K_5414_CBCFG_BUF_DIS 0x10 /* Disable buffer */ + +/* + * PCI-E Power managment configuration + * and status register [5424+] + */ +#define AR5K_PCIE_PM_CTL 0x4068 /* Register address */ +/* Only 5424 */ +#define AR5K_PCIE_PM_CTL_L1_WHEN_D2 0x00000001 /* enable PCIe core enter L1 + when d2_sleep_en is asserted */ +#define AR5K_PCIE_PM_CTL_L0_L0S_CLEAR 0x00000002 /* Clear L0 and L0S counters */ +#define AR5K_PCIE_PM_CTL_L0_L0S_EN 0x00000004 /* Start L0 nd L0S counters */ +#define AR5K_PCIE_PM_CTL_LDRESET_EN 0x00000008 /* Enable reset when link goes + down */ +/* Wake On Wireless */ +#define AR5K_PCIE_PM_CTL_PME_EN 0x00000010 /* PME Enable */ +#define AR5K_PCIE_PM_CTL_AUX_PWR_DET 0x00000020 /* Aux power detect */ +#define AR5K_PCIE_PM_CTL_PME_CLEAR 0x00000040 /* Clear PME */ +#define AR5K_PCIE_PM_CTL_PSM_D0 0x00000080 +#define AR5K_PCIE_PM_CTL_PSM_D1 0x00000100 +#define AR5K_PCIE_PM_CTL_PSM_D2 0x00000200 +#define AR5K_PCIE_PM_CTL_PSM_D3 0x00000400 + +/* + * PCI-E Workaround enable register + */ +#define AR5K_PCIE_WAEN 0x407c +/* + * PCI-E Serializer/Desirializer + * registers + */ +#define AR5K_PCIE_SERDES 0x4080 +#define AR5K_PCIE_SERDES_RESET 0x4084 /*====EEPROM REGISTERS====*/ @@ -1006,13 +1081,27 @@ * EEPROM config register */ #define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ -#define AR5K_EEPROM_CFG_SIZE_OVR 0x00000001 +#define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ +#define AR5K_EEPROM_CFG_SIZE_AUTO 0 +#define AR5K_EEPROM_CFG_SIZE_4KBIT 1 +#define AR5K_EEPROM_CFG_SIZE_8KBIT 2 +#define AR5K_EEPROM_CFG_SIZE_16KBIT 3 #define AR5K_EEPROM_CFG_WR_WAIT_DIS 0x00000004 /* Disable write wait */ #define AR5K_EEPROM_CFG_CLK_RATE 0x00000018 /* Clock rate */ -#define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protectio key */ +#define AR5K_EEPROM_CFG_CLK_RATE_S 3 +#define AR5K_EEPROM_CFG_CLK_RATE_156KHZ 0 +#define AR5K_EEPROM_CFG_CLK_RATE_312KHZ 1 +#define AR5K_EEPROM_CFG_CLK_RATE_625KHZ 2 +#define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protection key */ +#define AR5K_EEPROM_CFG_PROT_KEY_S 8 #define AR5K_EEPROM_CFG_LIND_EN 0x01000000 /* Enable length indicator (?) */ +/* + * TODO: Wake On Wireless registers + * Range 0x7000 - 0x7ce0 + */ + /* * Protocol Control Unit (PCU) registers */ @@ -1045,11 +1134,13 @@ #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ #define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ -#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */ -#define AR5K_STA_ID1_SELF_GEN_SECTORE 0x04000000 /* Self generate sectore (?) */ +#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ +#define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ -#define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Keysearch mode (?) */ +#define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ #define AR5K_STA_ID1_PRESERVE_SEQ_NUM 0x20000000 /* Preserve sequence number */ +#define AR5K_STA_ID1_CBCIV_ENDIAN 0x40000000 /* ??? */ +#define AR5K_STA_ID1_KEYSRCH_MCAST 0x80000000 /* Do key cache search for mcast frames */ /* * First BSSID register (MAC address, lower 32bits) @@ -1308,16 +1399,16 @@ #define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 #define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) -#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 +#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */ #define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 #define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) -#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 +#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */ #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) -#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Enable scrambler seed */ -#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 +#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 /* Enable fixed scrambler seed */ +#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 #define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211) #define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */ @@ -1326,12 +1417,15 @@ #define AR5K_DIAG_SW_SCRAM_SEED_S 10 #define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 -#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 +#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */ #define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) -#define AR5K_DIAG_SW_OBSPT_M 0x000c0000 +#define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */ #define AR5K_DIAG_SW_OBSPT_S 18 -/* more bits */ +#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ +#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ +#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high (?) */ +#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ /* * TSF (clock) register (lower 32 bits) @@ -1542,16 +1636,16 @@ * * XXX: PCDAC steps (0.5dbm) or DBM ? * - * XXX: Mask changes for newer chips to 7f - * like tx power table ? */ #define AR5K_TXPC 0x80e8 /* Register Address */ -#define AR5K_TXPC_ACK_M 0x0000003f /* Mask for ACK tx power */ +#define AR5K_TXPC_ACK_M 0x0000003f /* ACK tx power */ #define AR5K_TXPC_ACK_S 0 -#define AR5K_TXPC_CTS_M 0x00003f00 /* Mask for CTS tx power */ +#define AR5K_TXPC_CTS_M 0x00003f00 /* CTS tx power */ #define AR5K_TXPC_CTS_S 8 -#define AR5K_TXPC_CHIRP_M 0x003f0000 /* Mask for CHIRP tx power */ -#define AR5K_TXPC_CHIRP_S 22 +#define AR5K_TXPC_CHIRP_M 0x003f0000 /* CHIRP tx power */ +#define AR5K_TXPC_CHIRP_S 16 +#define AR5K_TXPC_DOPPLER 0x0f000000 /* Doppler chirp span (?) */ +#define AR5K_TXPC_DOPPLER_S 24 /* * Profile count registers @@ -1562,14 +1656,19 @@ #define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ /* - * Quiet (period) control registers (?) + * Quiet period control registers */ #define AR5K_QUIET_CTL1 0x80fc /* Register Address */ -#define AR5K_QUIET_CTL1_NEXT_QT 0x0000ffff /* Mask for next quiet (period?) (?) */ -#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet (period?) */ +#define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */ +#define AR5K_QUIET_CTL1_NEXT_QT_TSF_0 +#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */ +#define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */ + #define AR5K_QUIET_CTL2 0x8100 /* Register Address */ -#define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period (?) */ -#define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet duration (?) */ +#define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period periodicity */ +#define AR5K_QUIET_CTL2_QT_PER_S 0 +#define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet period duration */ +#define AR5K_QUIET_CTL2_QT_DUR_S 16 /* * TSF parameter register @@ -1579,12 +1678,15 @@ #define AR5K_TSF_PARM_INC_S 0 /* - * QoS register (?) + * QoS NOACK policy */ -#define AR5K_QOS 0x8108 /* Register Address */ -#define AR5K_QOS_NOACK_2BIT_VALUES 0x00000000 /* (field) */ -#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000020 /* (field) */ -#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000080 /* (field) */ +#define AR5K_QOS_NOACK 0x8108 /* Register Address */ +#define AR5K_QOS_NOACK_2BIT_VALUES 0x0000000f /* ??? */ +#define AR5K_QOS_NOACK_2BIT_VALUES_S 0 +#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000070 /* ??? */ +#define AR5K_QOS_NOACK_BIT_OFFSET_S 4 +#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000180 /* ??? */ +#define AR5K_QOS_NOACK_BYTE_OFFSET_S 8 /* * PHY error filter register @@ -1608,29 +1710,15 @@ /* * MIC QoS control register (?) */ -#define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ -#define AR5K_MIC_QOS_CTL_0 0x00000001 /* MIC QoS control 0 (?) */ -#define AR5K_MIC_QOS_CTL_1 0x00000004 /* MIC QoS control 1 (?) */ -#define AR5K_MIC_QOS_CTL_2 0x00000010 /* MIC QoS control 2 (?) */ -#define AR5K_MIC_QOS_CTL_3 0x00000040 /* MIC QoS control 3 (?) */ -#define AR5K_MIC_QOS_CTL_4 0x00000100 /* MIC QoS control 4 (?) */ -#define AR5K_MIC_QOS_CTL_5 0x00000400 /* MIC QoS control 5 (?) */ -#define AR5K_MIC_QOS_CTL_6 0x00001000 /* MIC QoS control 6 (?) */ -#define AR5K_MIC_QOS_CTL_7 0x00004000 /* MIC QoS control 7 (?) */ -#define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ +#define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ +#define AR5K_MIC_QOS_CTL_OFF(_n) (1 << (_n * 2)) +#define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ /* * MIC QoS select register (?) */ -#define AR5K_MIC_QOS_SEL 0x811c -#define AR5K_MIC_QOS_SEL_0 0x00000001 -#define AR5K_MIC_QOS_SEL_1 0x00000010 -#define AR5K_MIC_QOS_SEL_2 0x00000100 -#define AR5K_MIC_QOS_SEL_3 0x00001000 -#define AR5K_MIC_QOS_SEL_4 0x00010000 -#define AR5K_MIC_QOS_SEL_5 0x00100000 -#define AR5K_MIC_QOS_SEL_6 0x01000000 -#define AR5K_MIC_QOS_SEL_7 0x10000000 +#define AR5K_MIC_QOS_SEL 0x811c +#define AR5K_MIC_QOS_SEL_OFF(_n) (1 << (_n * 4)) /* * Misc mode control register (?) @@ -1664,6 +1752,11 @@ */ #define AR5K_TSF_THRES 0x813c +/* + * TODO: Wake On Wireless registers + * Range: 0x8147 - 0x818c + */ + /* * Rate -> ACK SIFS mapping table (32 entries) */ @@ -1779,7 +1872,8 @@ */ #define AR5K_PHY_TURBO 0x9804 /* Register Address */ #define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ -#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Short mode (20Mhz channels) (?) */ +#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */ +#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */ /* * PHY agility command register @@ -1789,6 +1883,11 @@ #define AR5K_PHY_TST1 0x9808 #define AR5K_PHY_AGC_DISABLE 0x08000000 /* Disable AGC to A2 (?)*/ #define AR5K_PHY_TST1_TXHOLD 0x00003800 /* Set tx hold (?) */ +#define AR5K_PHY_TST1_TXSRC_SRC 0x00000002 /* Used with bit 7 (?) */ +#define AR5K_PHY_TST1_TXSRC_SRC_S 1 +#define AR5K_PHY_TST1_TXSRC_ALT 0x00000080 /* Set input to tsdac (?) */ +#define AR5K_PHY_TST1_TXSRC_ALT_S 7 + /* * PHY timing register 3 [5112+] @@ -1813,15 +1912,23 @@ /* * PHY RF control registers - * (i think these are delay times, - * these calibration values exist - * in EEPROM) */ #define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ -#define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* Mask for TX frame to TX d(esc?) start */ +#define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* TX frame to TX data start */ +#define AR5K_PHY_RF_CTL2_TXF2TXD_START_S 0 #define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */ -#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* Mask for TX end to XLNA on */ +#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* TX end to XLNA on */ +#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S 0 + +#define AR5K_PHY_ADC_CTL 0x982c +#define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF 0x00000003 +#define AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S 0 +#define AR5K_PHY_ADC_CTL_PWD_DAC_OFF 0x00002000 +#define AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF 0x00004000 +#define AR5K_PHY_ADC_CTL_PWD_ADC_OFF 0x00008000 +#define AR5K_PHY_ADC_CTL_INBUFGAIN_ON 0x00030000 +#define AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S 16 #define AR5K_PHY_RF_CTL4 0x9834 /* Register Address */ #define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON 0x00000001 /* TX frame to XPA A on (field) */ @@ -1843,14 +1950,19 @@ * PHY settling register */ #define AR5K_PHY_SETTLING 0x9844 /* Register Address */ -#define AR5K_PHY_SETTLING_AGC 0x0000007f /* Mask for AGC settling time */ -#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Mask for Switch settlig time */ +#define AR5K_PHY_SETTLING_AGC 0x0000007f /* AGC settling time */ +#define AR5K_PHY_SETTLING_AGC_S 0 +#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settlig time */ +#define AR5K_PHY_SETTLINK_SWITCH_S 7 /* * PHY Gain registers */ #define AR5K_PHY_GAIN 0x9848 /* Register Address */ -#define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* Mask for TX-RX Attenuation */ +#define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* TX-RX Attenuation */ +#define AR5K_PHY_GAIN_TXRX_ATTEN_S 12 +#define AR5K_PHY_GAIN_TXRX_RF_MAX 0x007c0000 +#define AR5K_PHY_GAIN_TXRX_RF_MAX_S 18 #define AR5K_PHY_GAIN_OFFSET 0x984c /* Register Address */ #define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */ @@ -1860,18 +1972,21 @@ * (for more infos read ANI patent) */ #define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */ -#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* Mask for ADC desired size */ -#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* Mask for PGA desired size */ -#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size */ +#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* ADC desired size */ +#define AR5K_PHY_DESIRED_SIZE_ADC_S 0 +#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* PGA desired size */ +#define AR5K_PHY_DESIRED_SIZE_PGA_S 8 +#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Total desired size */ +#define AR5K_PHY_DESIRED_SIZE_TOT_S 20 /* * PHY signal register * (for more infos read ANI patent) */ #define AR5K_PHY_SIG 0x9858 /* Register Address */ -#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* Mask for FIRSTEP */ +#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* FIRSTEP */ #define AR5K_PHY_SIG_FIRSTEP_S 12 -#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* Mask for FIPWR */ +#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* FIPWR */ #define AR5K_PHY_SIG_FIRPWR_S 18 /* @@ -1879,9 +1994,9 @@ * (for more infos read ANI patent) */ #define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ -#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* Mask for AGC Coarse low */ +#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* AGC Coarse low */ #define AR5K_PHY_AGCCOARSE_LO_S 7 -#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* Mask for AGC Coarse high */ +#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* AGC Coarse high */ #define AR5K_PHY_AGCCOARSE_HI_S 15 /* @@ -1890,6 +2005,8 @@ #define AR5K_PHY_AGCCTL 0x9860 /* Register address */ #define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ #define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ +#define AR5K_PHY_AGCCTL_NF_EN 0x00008000 /* Enable nf calibration to happen (?) */ +#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ /* * PHY noise floor status register @@ -1900,7 +2017,10 @@ #define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) #define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) #define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) -#define AR5K_PHY_NF_THRESH62 0x00001000 /* Thresh62 -check ANI patent- (field) */ +#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ +#define AR5K_PHY_NF_THRESH62_S 12 +#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ +#define AR5K_PHY_NF_MINCCA_PWR_S 19 /* * PHY ADC saturation register [5110] @@ -1940,24 +2060,31 @@ */ #define AR5K_PHY_SCR 0x9870 #define AR5K_PHY_SCR_32MHZ 0x0000001f + #define AR5K_PHY_SLMT 0x9874 #define AR5K_PHY_SLMT_32MHZ 0x0000007f + #define AR5K_PHY_SCAL 0x9878 #define AR5K_PHY_SCAL_32MHZ 0x0000000e + /* * PHY PLL (Phase Locked Loop) control register */ #define AR5K_PHY_PLL 0x987c -#define AR5K_PHY_PLL_20MHZ 0x13 /* For half rate (?) [5111+] */ -#define AR5K_PHY_PLL_40MHZ_5211 0x18 /* For 802.11a */ +#define AR5K_PHY_PLL_20MHZ 0x00000013 /* For half rate (?) */ +/* 40MHz -> 5GHz band */ +#define AR5K_PHY_PLL_40MHZ_5211 0x00000018 #define AR5K_PHY_PLL_40MHZ_5212 0x000000aa +#define AR5K_PHY_PLL_40MHZ_5413 0x00000004 #define AR5K_PHY_PLL_40MHZ (ah->ah_version == AR5K_AR5211 ? \ AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212) -#define AR5K_PHY_PLL_44MHZ_5211 0x19 /* For 802.11b/g */ +/* 44MHz -> 2.4GHz band */ +#define AR5K_PHY_PLL_44MHZ_5211 0x00000019 #define AR5K_PHY_PLL_44MHZ_5212 0x000000ab #define AR5K_PHY_PLL_44MHZ (ah->ah_version == AR5K_AR5211 ? \ AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) + #define AR5K_PHY_PLL_RF5111 0x00000000 #define AR5K_PHY_PLL_RF5112 0x00000040 #define AR5K_PHY_PLL_HALF_RATE 0x00000100 @@ -2023,6 +2150,19 @@ #define AR5K_PHY_RFSTG 0x98d4 #define AR5K_PHY_RFSTG_DISABLE 0x00000021 +/* + * BIN masks (?) + */ +#define AR5K_PHY_BIN_MASK_1 0x9900 +#define AR5K_PHY_BIN_MASK_2 0x9904 +#define AR5K_PHY_BIN_MASK_3 0x9908 + +#define AR5K_PHY_BIN_MASK_CTL 0x990c +#define AR5K_PHY_BIN_MASK_CTL_MASK_4 0x00003fff +#define AR5K_PHY_BIN_MASK_CTL_MASK_4_S 0 +#define AR5K_PHY_BIN_MASK_CTL_RATE 0xff000000 +#define AR5K_PHY_BIN_MASK_CTL_RATE_S 24 + /* * PHY Antenna control register */ @@ -2070,6 +2210,7 @@ #define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */ #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */ #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */ +#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S 0 #define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */ #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */ #define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */ @@ -2116,7 +2257,6 @@ #define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ #define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ - /* * PHY TX rate power registers [5112+] */ @@ -2138,6 +2278,8 @@ #define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */ #define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3 #define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */ +#define AR5K_PHY_FRAME_CTL_EMU 0x80000000 +#define AR5K_PHY_FRAME_CTL_EMU_S 31 /*---[5110/5111]---*/ #define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 /* PHY timing error */ #define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 /* Parity error */ @@ -2156,48 +2298,36 @@ * PHY radar detection register [5111+] */ #define AR5K_PHY_RADAR 0x9954 - -/* Radar enable ........ ........ ........ .......1 */ #define AR5K_PHY_RADAR_ENABLE 0x00000001 -#define AR5K_PHY_RADAR_DISABLE 0x00000000 -#define AR5K_PHY_RADAR_ENABLE_S 0 - -/* This is the value found on the card .1.111.1 .1.1.... 111....1 1...1... -at power on. */ -#define AR5K_PHY_RADAR_PWONDEF_AR5213 0x5d50e188 - -/* This is the value found on the card .1.1.111 ..11...1 .1...1.1 1...11.1 -after DFS is enabled */ -#define AR5K_PHY_RADAR_ENABLED_AR5213 0x5731458d - -/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........ - * power out threshold. - * 7-bits, standard power range {0..127} in 1/2 dBm units. */ -#define AR5K_PHY_RADAR_FIRPWROUTTHR 0x7f000000 -#define AR5K_PHY_RADAR_FIRPWROUTTHR_S 24 - -/* Radar RSSI/SNR threshold. ........ 111111.. ........ ........ - * 6-bits, dBm range {0..63} in dBm units. */ -#define AR5K_PHY_RADAR_RADARRSSITHR 0x00fc0000 -#define AR5K_PHY_RADAR_RADARRSSITHR_S 18 - -/* Pulse height threshold ........ ......11 1111.... ........ - * 6-bits, dBm range {0..63} in dBm units. */ -#define AR5K_PHY_RADAR_PULSEHEIGHTTHR 0x0003f000 -#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S 12 - -/* Pulse RSSI/SNR threshold ........ ........ ....1111 11...... - * 6-bits, dBm range {0..63} in dBm units. */ -#define AR5K_PHY_RADAR_PULSERSSITHR 0x00000fc0 -#define AR5K_PHY_RADAR_PULSERSSITHR_S 6 - -/* Inband threshold ........ ........ ........ ..11111. - * 5-bits, units unknown {0..31} (? MHz ?) */ -#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e +#define AR5K_PHY_RADAR_DISABLE 0x00000000 +#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e /* Inband threshold + 5-bits, units unknown {0..31} + (? MHz ?) */ #define AR5K_PHY_RADAR_INBANDTHR_S 1 +#define AR5K_PHY_RADAR_PRSSI_THR 0x00000fc0 /* Pulse RSSI/SNR threshold + 6-bits, dBm range {0..63} + in dBm units. */ +#define AR5K_PHY_RADAR_PRSSI_THR_S 6 + +#define AR5K_PHY_RADAR_PHEIGHT_THR 0x0003f000 /* Pulse height threshold + 6-bits, dBm range {0..63} + in dBm units. */ +#define AR5K_PHY_RADAR_PHEIGHT_THR_S 12 + +#define AR5K_PHY_RADAR_RSSI_THR 0x00fc0000 /* Radar RSSI/SNR threshold. + 6-bits, dBm range {0..63} + in dBm units. */ +#define AR5K_PHY_RADAR_RSSI_THR_S 18 + +#define AR5K_PHY_RADAR_FIRPWR_THR 0x7f000000 /* Finite Impulse Response + filter power out threshold. + 7-bits, standard power range + {0..127} in 1/2 dBm units. */ +#define AR5K_PHY_RADAR_FIRPWR_THRS 24 + /* - * PHY antenna switch table registers [5110] + * PHY antenna switch table registers */ #define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 #define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 @@ -2208,25 +2338,65 @@ after DFS is enabled */ #define AR5K_PHY_NFTHRES 0x9968 /* - * PHY clock sleep registers [5112+] + * Sigma Delta register (?) [5213] */ -#define AR5K_PHY_SCLOCK 0x99f0 -#define AR5K_PHY_SCLOCK_32MHZ 0x0000000c -#define AR5K_PHY_SDELAY 0x99f4 -#define AR5K_PHY_SDELAY_32MHZ 0x000000ff -#define AR5K_PHY_SPENDING 0x99f8 -#define AR5K_PHY_SPENDING_14 0x00000014 -#define AR5K_PHY_SPENDING_18 0x00000018 -#define AR5K_PHY_SPENDING_RF5111 0x00000018 -#define AR5K_PHY_SPENDING_RF5112 0x00000014 -/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */ -/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */ -#define AR5K_PHY_SPENDING_RF5413 0x00000014 -#define AR5K_PHY_SPENDING_RF2413 0x00000014 -#define AR5K_PHY_SPENDING_RF2425 0x00000018 +#define AR5K_PHY_SIGMA_DELTA 0x996C +#define AR5K_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 +#define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S 0 +#define AR5K_PHY_SIGMA_DELTA_FILT2 0x000000f8 +#define AR5K_PHY_SIGMA_DELTA_FILT2_S 3 +#define AR5K_PHY_SIGMA_DELTA_FILT1 0x00001f00 +#define AR5K_PHY_SIGMA_DELTA_FILT1_S 8 +#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP 0x01ff3000 +#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S 13 + +/* + * RF restart register [5112+] (?) + */ +#define AR5K_PHY_RESTART 0x9970 /* restart */ +#define AR5K_PHY_RESTART_DIV_GC 0x001c0000 /* Fast diversity gc_limit (?) */ +#define AR5K_PHY_RESTART_DIV_GC_S 18 + +/* + * RF Bus access request register (for synth-oly channel switching) + */ +#define AR5K_PHY_RFBUS_REQ 0x997C +#define AR5K_PHY_RFBUS_REQ_REQUEST 0x00000001 /* - * Misc PHY/radio registers [5110 - 5111] + * Spur mitigation masks (?) + */ +#define AR5K_PHY_TIMING_7 0x9980 +#define AR5K_PHY_TIMING_8 0x9984 +#define AR5K_PHY_TIMING_8_PILOT_MASK_2 0x000fffff +#define AR5K_PHY_TIMING_8_PILOT_MASK_2_S 0 + +#define AR5K_PHY_BIN_MASK2_1 0x9988 +#define AR5K_PHY_BIN_MASK2_2 0x998c +#define AR5K_PHY_BIN_MASK2_3 0x9990 + +#define AR5K_PHY_BIN_MASK2_4 0x9994 +#define AR5K_PHY_BIN_MASK2_4_MASK_4 0x00003fff +#define AR5K_PHY_BIN_MASK2_4_MASK_4_S 0 + +#define AR_PHY_TIMING_9 0x9998 +#define AR_PHY_TIMING_10 0x999c +#define AR_PHY_TIMING_10_PILOT_MASK_2 0x000fffff +#define AR_PHY_TIMING_10_PILOT_MASK_2_S 0 + +/* + * Spur mitigation control + */ +#define AR_PHY_TIMING_11 0x99a0 /* Register address */ +#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE 0x000fffff /* Spur delta phase */ +#define AR_PHY_TIMING_11_SPUR_DELTA_PHASE_S 0 +#define AR_PHY_TIMING_11_SPUR_FREQ_SD 0x3ff00000 /* Freq sigma delta */ +#define AR_PHY_TIMING_11_SPUR_FREQ_SD_S 20 +#define AR_PHY_TIMING_11_USE_SPUR_IN_AGC 0x40000000 /* Spur filter in AGC detector */ +#define AR_PHY_TIMING_11_USE_SPUR_IN_SELFCOR 0x80000000 /* Spur filter in OFDM self correlator */ + +/* + * Gain tables */ #define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ #define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2)) @@ -2246,9 +2416,10 @@ after DFS is enabled */ #define AR5K_PHY_CURRENT_RSSI 0x9c1c /* - * PHY RF Bus grant register (?) + * PHY RF Bus grant register */ #define AR5K_PHY_RFBUS_GRANT 0x9c20 +#define AR5K_PHY_RFBUS_GRANT_OK 0x00000001 /* * PHY ADC test register @@ -2291,6 +2462,31 @@ after DFS is enabled */ #define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004 #define AR5K_PHY_CHAN_STATUS_RX_CLR_PAP 0x00000008 +/* + * Heavy clip enable register + */ +#define AR5K_PHY_HEAVY_CLIP_ENABLE 0x99e0 + +/* + * PHY clock sleep registers [5112+] + */ +#define AR5K_PHY_SCLOCK 0x99f0 +#define AR5K_PHY_SCLOCK_32MHZ 0x0000000c +#define AR5K_PHY_SDELAY 0x99f4 +#define AR5K_PHY_SDELAY_32MHZ 0x000000ff +#define AR5K_PHY_SPENDING 0x99f8 +#define AR5K_PHY_SPENDING_14 0x00000014 +#define AR5K_PHY_SPENDING_18 0x00000018 +#define AR5K_PHY_SPENDING_RF5111 0x00000018 +#define AR5K_PHY_SPENDING_RF5112 0x00000014 +/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */ +/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */ +#define AR5K_PHY_SPENDING_RF5413 0x00000018 +#define AR5K_PHY_SPENDING_RF2413 0x00000018 +#define AR5K_PHY_SPENDING_RF2316 0x00000018 +#define AR5K_PHY_SPENDING_RF2317 0x00000018 +#define AR5K_PHY_SPENDING_RF2425 0x00000014 + /* * PHY PAPD I (power?) table (?) * (92! entries) @@ -2342,10 +2538,47 @@ after DFS is enabled */ #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000000f #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 +/* Same address is used for antenna diversity activation */ +#define AR5K_PHY_FAST_ANT_DIV 0xa208 +#define AR5K_PHY_FAST_ANT_DIV_EN 0x00002000 + /* * PHY 2GHz gain register [5111+] */ -#define AR5K_PHY_GAIN_2GHZ 0xa20c -#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 +#define AR5K_PHY_GAIN_2GHZ 0xa20c +#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 #define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S 18 -#define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c +#define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c + +#define AR5K_PHY_CCK_RX_CTL_4 0xa21c +#define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT 0x01f80000 +#define AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S 19 + +#define AR5K_PHY_DAG_CCK_CTL 0xa228 +#define AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR 0x00000200 +#define AR5K_PHY_DAG_CCK_CTL_RSSI_THR 0x0001fc00 +#define AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S 10 + +#define AR5K_PHY_FAST_ADC 0xa24c + +#define AR5K_PHY_BLUETOOTH 0xa254 + +/* + * Transmit Power Control register + * [2413+] + */ +#define AR5K_PHY_TPC_RG1 0xa258 +#define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 +#define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 + +#define AR5K_PHY_TPC_RG5 0xa26C +#define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F +#define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S 0 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1 0x000003F0 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S 4 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2 0x0000FC00 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S 10 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3 0x003F0000 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S 16 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4 0x0FC00000 +#define AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S 22 diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 953ba3b19ff..8f1886834e6 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -543,13 +543,13 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); if (channel->hw_value == CHANNEL_G) - if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) + if (ah->ah_mac_srev < AR5K_SREV_AR2413) ath5k_hw_reg_write(ah, 0x00f80d80, 0x994c); - else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) + else if (ah->ah_mac_srev < AR5K_SREV_AR5424) ath5k_hw_reg_write(ah, 0x00380140, 0x994c); - else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) + else if (ah->ah_mac_srev < AR5K_SREV_AR2425) ath5k_hw_reg_write(ah, 0x00fc0ec0, 0x994c); else /* 2425 */ @@ -915,7 +915,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_reg_write(ah, 0x000100aa, 0x8118); ath5k_hw_reg_write(ah, 0x00003210, 0x811c); ath5k_hw_reg_write(ah, 0x00000052, 0x8108); - if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413) + if (ah->ah_mac_srev >= AR5K_SREV_AR2413) ath5k_hw_reg_write(ah, 0x00000004, 0x8120); } -- cgit v1.2.3 From 1d280ddcfd6666a45915ccc3a76dee033a6b917b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 29 Sep 2008 14:19:29 -0500 Subject: b43: Increase loop tries in do_dummy_tx One of the spin-on-condition loops in routine do_dummy_tx always exits before the condition is satisfied. The hardware might be left in an inconsistent state that might be the cause of the PHY transmission errors seen by some users. Signed-off-by: Larry Finger Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e5e71220e7d..3bf74e236ab 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -815,7 +815,7 @@ void b43_dummy_transmission(struct b43_wldev *dev) break; udelay(10); } - for (i = 0x00; i < 0x0A; i++) { + for (i = 0x00; i < 0x19; i++) { value = b43_read16(dev, 0x0690); if (!(value & 0x0100)) break; -- cgit v1.2.3 From ee81c5544bbf49ea5b301784a605d865947ac1b0 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 29 Sep 2008 01:18:16 +0300 Subject: ath5k: Use new srevs to properly attach radio chips * Use new SREV values and PHY srevs to identify radio type durring attach Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/attach.c | 182 ++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 69 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index d92b4a12567..51d569883cd 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -137,7 +137,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; /* - * Set the mac revision based on the pci id + * Set the mac version based on the pci id */ ah->ah_version = mac_version; @@ -160,87 +160,132 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) 0xffffffff; ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_5GHZ); + ah->ah_phy = AR5K_PHY(0); - if (ah->ah_version == AR5K_AR5210) - ah->ah_radio_2ghz_revision = 0; - else - ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_2GHZ); - - /* Return on unsuported chips (unsupported eeprom etc) */ - if ((srev >= AR5K_SREV_AR5416) && - (srev < AR5K_SREV_AR2425)) { - ATH5K_ERR(sc, "Device not yet supported.\n"); - ret = -ENODEV; - goto err_free; - } else if (srev == AR5K_SREV_AR2425) { - ATH5K_WARN(sc, "Support for RF2425 is under development.\n"); - } - - /* Identify single chip solutions */ - if (((srev <= AR5K_SREV_AR5414) && - (srev >= AR5K_SREV_AR2413)) || - (srev == AR5K_SREV_AR2425)) { - ah->ah_single_chip = true; - } else { - ah->ah_single_chip = false; - } - - /* Single chip radio */ - if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision) - ah->ah_radio_2ghz_revision = 0; - - /* Identify the radio chip*/ - if (ah->ah_version == AR5K_AR5210) { - ah->ah_radio = AR5K_RF5110; - /* - * Register returns 0x0/0x04 for radio revision - * so ath5k_hw_radio_revision doesn't parse the value - * correctly. For now we are based on mac's srev to - * identify RF2425 radio. - */ - } else if (srev == AR5K_SREV_AR2425) { - ah->ah_radio = AR5K_RF2425; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { + /* Try to identify radio chip based on it's srev */ + switch (ah->ah_radio_5ghz_revision & 0xf0) { + case AR5K_SREV_RAD_5111: ah->ah_radio = AR5K_RF5111; + ah->ah_single_chip = false; + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_2413) { + break; + case AR5K_SREV_RAD_5112: + case AR5K_SREV_RAD_2112: ah->ah_radio = AR5K_RF5112; + ah->ah_single_chip = false; + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5413) { + break; + case AR5K_SREV_RAD_2413: ah->ah_radio = AR5K_RF2413; + ah->ah_single_chip = true; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_2316) { + break; + case AR5K_SREV_RAD_5413: ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; - } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) { - /* AR5424 */ - if (srev >= AR5K_SREV_AR5424) { + break; + case AR5K_SREV_RAD_2316: + ah->ah_radio = AR5K_RF2316; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316; + break; + case AR5K_SREV_RAD_2317: + ah->ah_radio = AR5K_RF2317; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317; + break; + case AR5K_SREV_RAD_5424: + if (ah->ah_mac_version == AR5K_SREV_AR2425 || + ah->ah_mac_version == AR5K_SREV_AR2417){ + ah->ah_radio = AR5K_RF2425; + ah->ah_single_chip = true; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; + } else { ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; - /* AR2424 */ - } else { - ah->ah_radio = AR5K_RF2413; /* For testing */ + } + break; + default: + /* Identify radio based on mac/phy srev */ + if (ah->ah_version == AR5K_AR5210) { + ah->ah_radio = AR5K_RF5110; + ah->ah_single_chip = false; + } else if (ah->ah_version == AR5K_AR5211) { + ah->ah_radio = AR5K_RF5111; + ah->ah_single_chip = false; + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); + } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || + ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_2425) { + ah->ah_radio = AR5K_RF2425; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; + } else if (srev == AR5K_SREV_AR5213A && + ah->ah_phy_revision == AR5K_SREV_PHY_2112B) { + ah->ah_radio = AR5K_RF5112; + ah->ah_single_chip = false; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B; + } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) { + ah->ah_radio = AR5K_RF2316; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316; + } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_5413) { + ah->ah_radio = AR5K_RF5413; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; + } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_2413) { + ah->ah_radio = AR5K_RF2413; + ah->ah_single_chip = true; + ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; + } else { + ATH5K_ERR(sc, "Couldn't identify radio revision.\n"); + ret = -ENODEV; + goto err_free; } } - ah->ah_phy = AR5K_PHY(0); + + + /* Return on unsuported chips (unsupported eeprom etc) */ + if ((srev >= AR5K_SREV_AR5416) && + (srev < AR5K_SREV_AR2425)) { + ATH5K_ERR(sc, "Device not yet supported.\n"); + ret = -ENODEV; + goto err_free; + } /* * Write PCI-E power save settings */ if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { - ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080); - ath5k_hw_reg_write(ah, 0x24924924, 0x4080); - ath5k_hw_reg_write(ah, 0x28000039, 0x4080); - ath5k_hw_reg_write(ah, 0x53160824, 0x4080); - ath5k_hw_reg_write(ah, 0xe5980579, 0x4080); - ath5k_hw_reg_write(ah, 0x001defff, 0x4080); - ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080); - ath5k_hw_reg_write(ah, 0xbe105554, 0x4080); - ath5k_hw_reg_write(ah, 0x000e3007, 0x4080); - ath5k_hw_reg_write(ah, 0x00000000, 0x4084); + ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); + /* Shut off RX when elecidle is asserted */ + ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); + /* TODO: EEPROM work */ + ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); + /* Shut off PLL and CLKREQ active in L1 */ + ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); + /* Preserce other settings */ + ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); + /* Reset SERDES to load new settings */ + ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); + mdelay(1); } /* @@ -250,14 +295,13 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) if (ret) goto err_free; - /* Write AR5K_PCICFG_UNK on 2112B and later chips */ - if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B || - srev > AR5K_SREV_AR2413) { + /* Enable pci core retry fix on Hainan (5213A) and later chips */ + if (srev >= AR5K_SREV_AR5213A) ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); - } /* - * Get card capabilities, values, ... + * Get card capabilities, calibration values etc + * TODO: EEPROM work */ ret = ath5k_eeprom_init(ah); if (ret) { @@ -273,7 +317,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } - /* Get MAC address */ + /* Set MAC address */ ret = ath5k_eeprom_read_mac(ah, mac); if (ret) { ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", -- cgit v1.2.3 From 509a106e68aa42acc1a0c44ab365d0de6869bd9e Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 29 Sep 2008 01:23:07 +0300 Subject: ath5k: Use QUIET mechanism on tx dma stop * Use QUIET mechanism to drain tx buffer on PCU for newer chips * Make sure that INTPEND is really 1 and not 0xffffffff while checking for pending interrupts Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/dma.c | 49 ++++++++++++++++++++++++++++++++++++---- drivers/net/wireless/ath5k/reg.h | 4 ++-- 2 files changed, 46 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c index a28090be960..7adceb2c7fa 100644 --- a/drivers/net/wireless/ath5k/dma.c +++ b/drivers/net/wireless/ath5k/dma.c @@ -68,7 +68,7 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) /* * It may take some time to disable the DMA receive unit */ - for (i = 2000; i > 0 && + for (i = 1000; i > 0 && (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; i--) udelay(10); @@ -182,11 +182,10 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) * have any pending frames. Returns -EBUSY if we still have pending frames, * -EINVAL if queue number is out of range. * - * TODO: Test queue drain code */ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) { - unsigned int i = 100; + unsigned int i = 40; u32 tx_queue, pending; ATH5K_TRACE(ah->ah_sc); @@ -233,13 +232,53 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) udelay(100); } while (--i && pending); + /* For 2413+ order PCU to drop packets using + * QUIET mechanism */ + if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && + pending){ + /* Set periodicity and duration */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)| + AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR), + AR5K_QUIET_CTL2); + + /* Enable quiet period for current TSF */ + ath5k_hw_reg_write(ah, + AR5K_QUIET_CTL1_QT_EN | + AR5K_REG_SM(ath5k_hw_reg_read(ah, + AR5K_TSF_L32_5211) >> 10, + AR5K_QUIET_CTL1_NEXT_QT_TSF), + AR5K_QUIET_CTL1); + + /* Force channel idle high */ + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, + AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + + /* Wait a while and disable mechanism */ + udelay(200); + AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1, + AR5K_QUIET_CTL1_QT_EN); + + /* Re-check for pending frames */ + i = 40; + do { + pending = ath5k_hw_reg_read(ah, + AR5K_QUEUE_STATUS(queue)) & + AR5K_QCU_STS_FRMPENDCNT; + udelay(100); + } while (--i && pending); + + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, + AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + } + /* Clear register */ ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); if (pending) return -EBUSY; } - /* TODO: Check for success else return error */ + /* TODO: Check for success on 5210 else return error */ return 0; } @@ -415,7 +454,7 @@ done: bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_INTPEND); + return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0; } /** diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 55054b575e8..e557fe178bb 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -1424,7 +1424,7 @@ #define AR5K_DIAG_SW_OBSPT_S 18 #define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ #define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ -#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high (?) */ +#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */ #define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ /* @@ -1660,7 +1660,7 @@ */ #define AR5K_QUIET_CTL1 0x80fc /* Register Address */ #define AR5K_QUIET_CTL1_NEXT_QT_TSF 0x0000ffff /* Next quiet period TSF (TU) */ -#define AR5K_QUIET_CTL1_NEXT_QT_TSF_0 +#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S 0 #define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet period */ #define AR5K_QUIET_CTL1_ACK_CTS_EN 0x00020000 /* Send ACK/CTS during quiet period */ -- cgit v1.2.3 From 75d0edb82269a1bcf83d32b1d77ab94a5e3ed8af Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 29 Sep 2008 01:24:44 +0300 Subject: ath5k: Fix SREV reporting after SREV updates * Fix srev reporting during attach Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c8bb9bfb51f..3b784358a7c 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -396,7 +396,11 @@ ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) for (i = 0; i < ARRAY_SIZE(srev_names); i++) { if (srev_names[i].sr_type != type) continue; - if ((val & 0xff) < srev_names[i + 1].sr_val) { + + if ((val & 0xf0) == srev_names[i].sr_val) + name = srev_names[i].sr_name; + + if ((val & 0xff) == srev_names[i].sr_val) { name = srev_names[i].sr_name; break; } -- cgit v1.2.3 From 0d5f0316593df606515b17b037a1fd36c4b8bfdf Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 29 Sep 2008 01:27:27 +0300 Subject: ath5k: Add support for AR2417 v2 * Add support for AR2417 (include pci id) since my previous patch doesn't sit on top of base.c/ath5k.h anymore. * Update module version to 0.6.0 Changes-Licensed-under: ISC Signed-Off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3b784358a7c..c151588aa48 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -72,7 +72,7 @@ MODULE_AUTHOR("Nick Kossifidis"); MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards."); MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION("0.5.0 (EXPERIMENTAL)"); +MODULE_VERSION("0.6.0 (EXPERIMENTAL)"); /* Known PCI ids */ @@ -93,7 +93,8 @@ static struct pci_device_id ath5k_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ - { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/ + { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */ + { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */ { 0 } }; MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); -- cgit v1.2.3 From 8ec8ebaeceedf3a845f9e23885f26d0d00eefeb7 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 6 Oct 2008 16:16:38 -0400 Subject: ath9k: fixup some merge damage This hunk was originally removed as part of "ath9k: Fix IRQ nobody cared issue with ath9k". Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 6c433a4d003..d7f5257d2ec 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -288,8 +288,6 @@ static int ath_stop(struct ath_softc *sc) * hardware is gone (invalid). */ - if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_hw_set_interrupts(ah, 0); ath_draintxq(sc, false); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_stoprecv(sc); -- cgit v1.2.3 From 0345f37be64905846a1ef38378061d4c2730242e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 3 Oct 2008 15:45:25 -0700 Subject: ath9k: kill ath9k's memzero() and use memset() instead Part of the cleanup on ath9k -- this was also causing some annoying compile time warnings. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/beacon.c | 8 ++++---- drivers/net/wireless/ath9k/core.c | 14 +++++++------- drivers/net/wireless/ath9k/core.h | 5 +---- drivers/net/wireless/ath9k/recv.c | 4 ++-- drivers/net/wireless/ath9k/xmit.c | 10 +++++----- 5 files changed, 19 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index eedb465d25d..9e15c30bbc0 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -129,7 +129,7 @@ static void ath_beacon_setup(struct ath_softc *sc, ds /* first descriptor */ ); - memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); series[0].Tries = 1; series[0].Rate = rate; series[0].ChSel = sc->sc_tx_chainmask; @@ -282,7 +282,7 @@ int ath_beaconq_setup(struct ath_hal *ah) { struct ath9k_tx_queue_info qi; - memzero(&qi, sizeof(qi)); + memset(&qi, 0, sizeof(qi)); qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; @@ -662,7 +662,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) else av_opmode = sc->sc_ah->ah_opmode; - memzero(&conf, sizeof(struct ath_beacon_config)); + memset(&conf, 0, sizeof(struct ath_beacon_config)); conf.beacon_interval = sc->hw->conf.beacon_int ? sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; @@ -738,7 +738,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) } } while (nexttbtt < tsftu); #undef FUDGE - memzero(&bs, sizeof(bs)); + memset(&bs, 0, sizeof(bs)); bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; bs.bs_dtimperiod = dtimperiod*intval; diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index d7f5257d2ec..5af7dfbd423 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -65,7 +65,7 @@ static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) for (i = 0; i < rt->rateCount; i++) sc->sc_rixmap[rt->info[i].rateCode] = (u8) i; - memzero(sc->sc_hwmap, sizeof(sc->sc_hwmap)); + memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); for (i = 0; i < 256; i++) { u8 ix = rt->rateCodeToIndex[i]; @@ -417,7 +417,7 @@ static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an) { struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - memzero(cm, sizeof(struct ath_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; @@ -526,7 +526,7 @@ int ath_vap_attach(struct ath_softc *sc, if (avp == NULL) return -ENOMEM; - memzero(avp, sizeof(struct ath_vap)); + memset(avp, 0, sizeof(struct ath_vap)); avp->av_if_data = if_data; /* Set the VAP opmode */ avp->av_opmode = opmode; @@ -1219,7 +1219,7 @@ struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC); if (an == NULL) return NULL; - memzero(an, sizeof(*an)); + memset(an, 0, sizeof(*an)); an->an_sc = sc; memcpy(an->an_addr, addr, ETH_ALEN); @@ -1606,7 +1606,7 @@ int ath_descdma_setup(struct ath_softc *sc, error = -ENOMEM; goto fail2; } - memzero(bf, bsize); + memset(bf, 0, bsize); dd->dd_bufptr = bf; INIT_LIST_HEAD(head); @@ -1638,7 +1638,7 @@ fail2: pci_free_consistent(sc->pdev, dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); fail: - memzero(dd, sizeof(*dd)); + memset(dd, 0, sizeof(*dd)); return error; #undef ATH_DESC_4KB_BOUND_CHECK #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED @@ -1663,7 +1663,7 @@ void ath_descdma_cleanup(struct ath_softc *sc, INIT_LIST_HEAD(head); kfree(dd->dd_bufptr); - memzero(dd, sizeof(*dd)); + memset(dd, 0, sizeof(*dd)); } /*************/ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 872f0c5a0b0..80814c9910c 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -84,9 +84,6 @@ struct ath_node; #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -/* XXX: remove */ -#define memzero(_buf, _len) memset(_buf, 0, _len) - #define ATH9K_BH_STATUS_INTACT 0 #define ATH9K_BH_STATUS_CHANGE 1 @@ -184,7 +181,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht); (_bf)->bf_lastbf = NULL; \ (_bf)->bf_lastfrm = NULL; \ (_bf)->bf_next = NULL; \ - memzero(&((_bf)->bf_state), \ + memset(&((_bf)->bf_state), 0, \ sizeof(struct ath_buf_state)); \ } while (0) diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 498256309ab..f4be5d11c9d 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -892,7 +892,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - memzero(&rx_status, sizeof(struct ath_recv_status)); + memset(&rx_status, 0, sizeof(struct ath_recv_status)); if (ds->ds_rxstat.rs_more) { /* @@ -1166,7 +1166,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, } else { /* Ensure the memory is zeroed out (all internal * pointers are null) */ - memzero(rxtid->rxbuf, ATH_TID_MAX_BUFS * + memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * sizeof(struct ath_rxbuf)); DPRINTF(sc, ATH_DBG_AGGR, "%s: Allocated @%p\n", __func__, rxtid->rxbuf); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 25929059c7d..bdcb9e1799c 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -729,7 +729,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* * Setup HAL rate series */ - memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); for (i = 0; i < 4; i++) { if (!bf->bf_rcs[i].tries) @@ -817,7 +817,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Disable multi-rate retry when using RTS/CTS by clearing * series 1, 2 and 3. */ - memzero(&series[1], sizeof(struct ath9k_11n_rate_series) * 3); + memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3); } /* @@ -930,7 +930,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); } else { - memzero(ba, WME_BA_BMP_SIZE >> 3); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); /* * AR5416 can become deaf/mute when BA @@ -943,7 +943,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, needreset = 1; } } else { - memzero(ba, WME_BA_BMP_SIZE >> 3); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); } } @@ -2098,7 +2098,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) struct ath9k_tx_queue_info qi; int qnum; - memzero(&qi, sizeof(qi)); + memset(&qi, 0, sizeof(qi)); qi.tqi_subtype = subtype; qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; -- cgit v1.2.3 From a477e4e6d48d3ac7c7a75bad40585cb391e5c237 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 3 Oct 2008 15:45:26 -0700 Subject: ath9k: fix oops on trying to hold the wrong spinlock We were trying to hold the wrong spinlock due to a typo on IEEE80211_BAR_CTL_TID_S's definition. We use this to compute the tid number and then hold this this tid number's spinlock. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Sujith Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 80814c9910c..5b4f1c48a61 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -309,7 +309,7 @@ void ath_descdma_cleanup(struct ath_softc *sc, #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 2 /* tid shift */ +#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ enum ATH_RX_TYPE { ATH_RX_NON_CONSUMED = 0, -- cgit v1.2.3 From 6f255425ac3b10c3352c926e7b53e5ea1c364ca4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 3 Oct 2008 15:45:27 -0700 Subject: ath9k: enable ANI to help with noisy environments This enables Adaptive Noise Immunity (ANI) on ath9k. ANI is as algorithm designed to minimize the detrimental effects of time-varying interferences. This should help with throughput in noisy environments. To use ANI we re-enable the MIB interrupt. Since ANI works on a timer and updates the noise floor we take advantage of this and also report a non-static noise floor now to mac80211. Signed-off-by: Sujith Manoharan Signed-off-by: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath9k/core.c | 129 +++++++++++++++++++++++++++++++++++-- drivers/net/wireless/ath9k/core.h | 25 +++++++ drivers/net/wireless/ath9k/hw.c | 35 ++++++++-- drivers/net/wireless/ath9k/main.c | 18 +++++- drivers/net/wireless/ath9k/recv.c | 13 +--- 6 files changed, 197 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 0e897c27685..accace5f7ef 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -854,7 +854,7 @@ bool ath9k_hw_calibrate(struct ath_hal *ah, u8 rxchainmask, bool longcal, bool *isCalDone); -int16_t ath9k_hw_getchan_noise(struct ath_hal *ah, +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); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 5af7dfbd423..c5033f6f42a 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -490,6 +490,122 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) __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 */ /******************/ @@ -676,12 +792,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) sc->sc_imask |= ATH9K_INT_CST; - /* Note: We disable MIB interrupts for now as we don't yet - * handle processing ANI, otherwise you will get an interrupt - * storm after about 7 hours of usage making the system unusable - * with huge latency. Once we do have ANI processing included - * we can re-enable this interrupt. */ -#if 0 /* * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. @@ -690,7 +800,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) sc->sc_imask |= ATH9K_INT_MIB; -#endif /* * Some hardware processes the TIM IE and fires an * interrupt when the TIM bit is set. For hardware @@ -991,6 +1100,10 @@ int ath_init(u16 devid, struct ath_softc *sc) } sc->sc_ah = ah; + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; + /* Get the hardware key cache size. */ sc->sc_keymax = ah->ah_caps.keycache_size; if (sc->sc_keymax > ATH_KEYMAX) { @@ -1098,6 +1211,8 @@ int ath_init(u16 devid, struct ath_softc *sc) 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; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 5b4f1c48a61..cb3e61e57c4 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -800,6 +800,28 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv, struct ath_rx_status *rx_stats); void ath_setdefantenna(void *sc, u32 antenna); +/*******/ +/* ANI */ +/*******/ + +/* ANI values for STA only. + FIXME: Add appropriate values for AP later */ + +#define ATH_ANI_POLLINTERVAL 100 /* 100 milliseconds between ANI poll */ +#define ATH_SHORT_CALINTERVAL 1000 /* 1 second between calibrations */ +#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds between calibrations */ +#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */ + +struct ath_ani { + bool sc_caldone; + int16_t sc_noise_floor; + unsigned int sc_longcal_timer; + unsigned int sc_shortcal_timer; + unsigned int sc_resetcal_timer; + unsigned int sc_checkani_timer; + struct timer_list timer; +}; + /********************/ /* LED Control */ /********************/ @@ -1028,6 +1050,9 @@ struct ath_softc { /* Rfkill */ struct ath_rfkill rf_kill; + + /* ANI */ + struct ath_ani sc_ani; }; int ath_init(u16 devid, struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 272c7581660..62e44a0ef99 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -329,7 +329,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) 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 = 0; + 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; @@ -8405,23 +8405,48 @@ u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) } } -int16_t +/* We can tune this as we go by monitoring really low values */ +#define ATH9K_NF_TOO_LOW -60 + +/* AR5416 may return very high value (like -31 dBm), in those cases the nf + * is incorrect and we should use the static NF value. Later we can try to + * find out why they are reporting these values */ +static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) +{ + if (nf > ATH9K_NF_TOO_LOW) { + DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, + "%s: noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + __func__, nf, ATH9K_NF_TOO_LOW); + return false; + } + return true; +} + +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) { struct ath9k_channel *ichan; + s16 nf; ichan = ath9k_regd_check_channel(ah, chan); if (ichan == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->channel, chan->channelFlags); - return 0; + return ATH_DEFAULT_NOISE_FLOOR; } if (ichan->rawNoiseFloor == 0) { enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); - return NOISE_FLOOR[mode]; + nf = NOISE_FLOOR[mode]; } else - return ichan->rawNoiseFloor; + nf = ichan->rawNoiseFloor; + + if (!ath9k_hw_nf_in_range(ah, nf)) + nf = ATH_DEFAULT_NOISE_FLOOR; + + return nf; } bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2caba440316..74726990d59 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -274,10 +274,12 @@ static void ath9k_rx_prepare(struct ath_softc *sc, rx_status->mactime = status->tsf; rx_status->band = curchan->band; rx_status->freq = curchan->center_freq; - rx_status->noise = ATH_DEFAULT_NOISE_FLOOR; + 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) @@ -427,6 +429,11 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, 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__); @@ -1173,6 +1180,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, return error; } + if (conf->type == NL80211_IFTYPE_AP) { + /* TODO: is this a suitable place to start ANI for AP mode? */ + /* Start ANI */ + mod_timer(&sc->sc_ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + } + return 0; } @@ -1195,6 +1209,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, #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); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index f4be5d11c9d..4983402af55 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -999,20 +999,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) rx_status.flags |= ATH_RX_SHORT_GI; } - /* sc->sc_noise_floor is only available when the station + /* 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. */ - - /* XXX we should use either sc->sc_noise_floor or - * ath_hal_getChanNoise(ah, &sc->sc_curchan) - * to calculate the noise floor. - * However, the value returned by ath_hal_getChanNoise - * seems to be incorrect (-31dBm on the last test), - * so we will use a hard-coded value until we - * figure out what is going on. - */ rx_status.abs_rssi = - ds->ds_rxstat.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; + ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor; pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, -- cgit v1.2.3 From cf3e74c2e4a438480c11782b17e90029f5d24696 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 30 Sep 2008 23:36:00 +0200 Subject: p54: report appropriate rate and band values for 802.11a This patch adds the a few lines that went missing in "p54: 802.11a 5GHz phy support" Essentially: the rx-code wasn't updated and therefore reported the wrong band, but more importantly the rate index was off as well, since 802.11a doesn't allow the "four" 802.11b rates... Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index de5e8f44b20..1994aa199d3 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -507,9 +507,10 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; - rx_status.rate_idx = hdr->rate & 0xf; + rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? + hdr->rate : (hdr->rate - 4)) & 0xf; rx_status.freq = freq; - rx_status.band = IEEE80211_BAND_2GHZ; + rx_status.band = dev->conf.channel->band; rx_status.antenna = hdr->antenna; tsf32 = le32_to_cpu(hdr->tsf32); -- cgit v1.2.3 From 5b5d13afeeee959a74114b73c560d3e243f34a11 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Fri, 3 Oct 2008 20:20:32 +0200 Subject: rt2x00: Fix rfkill structure initialization to prevent rfkill WARN_ON. The state field of the rfkill structure was incorrectly initialized to -1, which results in rfkill issueing a WARN_ON. Fix this by initializing the state field to the proper value as indicated by the driver. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 55eff58f188..c3f53a92180 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -145,10 +145,15 @@ void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) rt2x00dev->rfkill->name = rt2x00dev->ops->name; rt2x00dev->rfkill->data = rt2x00dev; - rt2x00dev->rfkill->state = -1; rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; - if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) { rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; + rt2x00dev->rfkill->state = + rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? + RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; + } else { + rt2x00dev->rfkill->state = RFKILL_STATE_UNBLOCKED; + } INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); -- cgit v1.2.3 From 76708dee382a69b2f9d0e50f413f99fefb2dc509 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 5 Oct 2008 18:02:48 +0200 Subject: mac80211: free up 2 bytes in skb->cb Free up 2 bytes in skb->cb to be used for multi-rate retry later. Move iv_len and icv_len initialization into key alloc. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 +- drivers/net/wireless/ath9k/xmit.c | 2 +- drivers/net/wireless/b43/xmit.c | 4 ++-- drivers/net/wireless/b43legacy/xmit.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00crypto.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00queue.c | 7 +++++-- 6 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c151588aa48..47be49acf55 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1188,7 +1188,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) if (info->control.hw_key) { keyidx = info->control.hw_key->hw_key_idx; - pktlen += info->control.icv_len; + pktlen += info->control.hw_key->icv_len; } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index bdcb9e1799c..3a4757942b3 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -237,7 +237,7 @@ static int ath_tx_prepare(struct ath_softc *sc, if (tx_info->control.hw_key) { txctl->keyix = tx_info->control.hw_key->hw_key_idx; - txctl->frmlen += tx_info->control.icv_len; + txctl->frmlen += tx_info->control.hw_key->icv_len; if (tx_info->control.hw_key->alg == ALG_WEP) txctl->keytype = ATH9K_KEY_TYPE_WEP; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5e0b71c3ad0..e0749c0074c 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -252,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Hardware appends ICV. */ - plcp_fragment_len += info->control.icv_len; + plcp_fragment_len += info->control.hw_key->icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & @@ -260,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(fctl); - iv_len = min((size_t) info->control.iv_len, + iv_len = min((size_t) info->control.hw_key->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 6835064758f..a894169411c 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -243,7 +243,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (key->enabled) { /* Hardware appends ICV. */ - plcp_fragment_len += info->control.icv_len; + plcp_fragment_len += info->control.hw_key->icv_len; key_idx = b43legacy_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & @@ -252,7 +252,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control); - iv_len = min((size_t)info->control.iv_len, + iv_len = min((size_t)info->control.hw_key->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); } else { diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index e1448cfa944..5a858e5106c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -56,10 +56,10 @@ unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) * note that these lengths should only be added when * mac80211 does not generate it. */ - overhead += tx_info->control.icv_len; + overhead += key->icv_len; if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) - overhead += tx_info->control.iv_len; + overhead += key->iv_len; if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { if (key->alg == ALG_TKIP) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index b7f4fe8fba6..1676ac48479 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -374,7 +374,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; - unsigned int iv_len = IEEE80211_SKB_CB(skb)->control.iv_len; + unsigned int iv_len; if (unlikely(rt2x00queue_full(queue))) return -EINVAL; @@ -410,8 +410,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) * the frame so we can provide it to the driver seperately. */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && - !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags) && + (IEEE80211_SKB_CB(skb)->control.hw_key != NULL)) { + iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; rt2x00crypto_tx_remove_iv(skb, iv_len); + } /* * It could be possible that the queue was corrupted and this -- cgit v1.2.3 From 870abdf67170daa9f1022e55a35c469239fcc74c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 5 Oct 2008 18:04:24 +0200 Subject: mac80211: add multi-rate retry support This patch adjusts the rate control API to allow multi-rate retry if supported by the driver. The ieee80211_hw struct specifies how many alternate rate selections the driver supports. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 + drivers/net/wireless/b43/xmit.c | 2 +- drivers/net/wireless/b43legacy/main.c | 1 + drivers/net/wireless/b43legacy/xmit.c | 2 +- drivers/net/wireless/rtl8180_dev.c | 5 +++-- 5 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3bf74e236ab..14c44df584d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4588,6 +4588,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; 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/xmit.c b/drivers/net/wireless/b43/xmit.c index e0749c0074c..2fabcf8f047 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -208,7 +208,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, txrate = ieee80211_get_tx_rate(dev->wl->hw, info); rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 9fb1421cbec..c66d57560e7 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3710,6 +3710,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; 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/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index a894169411c..65e83378160 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -210,7 +210,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index abcd641c54b..df7e78ee8a8 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -292,8 +292,8 @@ 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.alt_retry_rate_idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0; + entry->flags2 = info->control.retries[0].rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; entry->retry_limit = info->control.retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); @@ -855,6 +855,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; + dev->max_altrates = 1; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); -- cgit v1.2.3 From 2f7fe87034298d94301315ba4bb65c7284c709d0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 5 Oct 2008 18:05:48 +0200 Subject: ath5k: implement multi-rate retry support, fix tx status reporting Clean up the tx status reporting, fix retry counters (short retries are virtual collisions, not actual retries). Implement multi-rate retry support. This also fixes strong throughput fluctuations with rc80211_pid Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 4 ++- drivers/net/wireless/ath5k/base.c | 48 ++++++++++++++++++++++++-- drivers/net/wireless/ath5k/desc.c | 69 ++++++++++++++++++++++++++------------ 3 files changed, 95 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 7134c40d6a6..53ea439aff4 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -431,7 +431,9 @@ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_rate; + u8 ts_rate[4]; + u8 ts_retry[4]; + u8 ts_final_idx; s8 ts_rssi; u8 ts_shortretry; u8 ts_longretry; diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 47be49acf55..9b95c4049b3 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -541,6 +541,12 @@ ath5k_pci_probe(struct pci_dev *pdev, goto err_irq; } + /* set up multi-rate retry capabilities */ + if (sc->ah->ah_version == AR5K_AR5212) { + hw->max_altrates = 3; + hw->max_altrate_tries = 11; + } + /* Finish private driver data initialization */ ret = ath5k_attach(pdev, hw); if (ret) @@ -1173,7 +1179,9 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct sk_buff *skb = bf->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; - int ret; + struct ieee80211_rate *rate; + unsigned int mrr_rate[3], mrr_tries[3]; + int i, ret; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; @@ -1198,6 +1206,22 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) if (ret) goto err_unmap; + memset(mrr_rate, 0, sizeof(mrr_rate)); + memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i < 3; i++) { + rate = ieee80211_get_alt_retry_rate(sc->hw, info, i); + if (!rate) + break; + + mrr_rate[i] = rate->hw_value; + mrr_tries[i] = info->control.retries[i].limit; + } + + ah->ah_setup_mrr_tx_desc(ah, ds, + mrr_rate[0], mrr_tries[0], + mrr_rate[1], mrr_tries[1], + mrr_rate[2], mrr_tries[2]); + ds->ds_link = 0; ds->ds_data = bf->skbaddr; @@ -1814,7 +1838,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) struct ath5k_desc *ds; struct sk_buff *skb; struct ieee80211_tx_info *info; - int ret; + int i, ret; spin_lock(&txq->lock); list_for_each_entry_safe(bf, bf0, &txq->q, list) { @@ -1836,7 +1860,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; + 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; + + for (i = 0; i < 4; i++) { + struct ieee80211_tx_altrate *r = + &info->status.retries[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]; + } else { + r->rate_idx = -1; + r->limit = 0; + } + } + + info->status.excessive_retries = 0; if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; if (ts.ts_status & AR5K_TXERR_XRETRY) diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index d45b90a6e06..dd1374052ba 100644 --- a/drivers/net/wireless/ath5k/desc.c +++ b/drivers/net/wireless/ath5k/desc.c @@ -318,6 +318,15 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, return 0; } +/* no mrr support for cards older than 5212 */ +static int +ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, + u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) +{ + return 0; +} + /* * Proccess the tx status descriptor on 5210/5211 */ @@ -352,8 +361,10 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = 1; ts->ts_status = 0; - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, + ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + ts->ts_retry[0] = ts->ts_longretry; + ts->ts_final_idx = 0; if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { if (tx_status->tx_status_0 & @@ -405,29 +416,43 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; ts->ts_status = 0; - switch (AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { - case 0: - ts->ts_rate = tx_ctl->tx_control_3 & - AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - break; + ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX); + + /* The longretry counter has the number of un-acked retries + * for the final rate. To get the total number of retries + * we have to add the retry counters for the other rates + * as well + */ + ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; + switch (ts->ts_final_idx) { + case 3: + ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); + + ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); + ts->ts_longretry += ts->ts_retry[2]; + /* fall through */ + case 2: + ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); + + ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); + ts->ts_longretry += ts->ts_retry[1]; + /* fall through */ case 1: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, + ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, + + ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - break; - case 2: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); - break; - case 3: - ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); + ts->ts_longretry += ts->ts_retry[0]; + /* fall through */ + case 0: + ts->ts_rate[0] = tx_ctl->tx_control_3 & + AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; break; } @@ -653,7 +678,7 @@ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) } else { ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; - ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; + ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr; ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; } -- cgit v1.2.3 From d588be6bae40f7965f1b681a4dbc3254411787b9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 6 Oct 2008 16:05:29 +0800 Subject: iwlwifi: scan correct setting of valid rx_chains This patch sets rx_chain bitmap correctly according hw configuration. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index bf855c35b0c..debdbd94dda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -703,7 +703,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; - u8 rx_chain = 0x7; /* bitmap: ABC chains */ + u8 rx_chain = priv->hw_params.valid_rx_ant; conf = ieee80211_get_hw_conf(priv->hw); -- cgit v1.2.3 From 5118303f7cc0520ce2969ea3d890dc05d586ceb2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 6 Oct 2008 16:05:30 +0800 Subject: iwlwifi: scan fix comment This patch moves comment to proper line, it has moved during code shuffling. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index debdbd94dda..639904a7283 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -843,7 +843,7 @@ static void iwl_bg_request_scan(struct work_struct *data) /* Force use of chains B and C (0x6) for scan Rx for 4965 * Avoid A (0x1) because of its off-channel reception on A-band. - * MIMO is not used here, but value is required */ + */ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) rx_chain = 0x6; } else { @@ -851,6 +851,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } + /* 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) | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | -- cgit v1.2.3 From eedda3670ea8e6d7649e3c8847759b0a6e532f8d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 6 Oct 2008 16:05:32 +0800 Subject: iwlwifi: remove STATUS_CONF_PENDING in scanning This patch removes STATUS_CONF_PENDING usage that called from iwl4965_mac_config internally after scan completed. It's called anyway from the mac80211 ieee80211_scan_completed(): if (local->hw_scanning) { local->hw_scanning = false; if (ieee80211_hw_config(local)) ... } Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 28 ---------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 3 +-- drivers/net/wireless/iwlwifi/iwl-scan.c | 23 +++++++++++++++++++++-- 3 files changed, 22 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 204abab7644..24a1aeb6448 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2569,30 +2569,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv) } -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); - -static void iwl_bg_scan_completed(struct work_struct *work) -{ - struct iwl_priv *priv = - container_of(work, struct iwl_priv, scan_completed); - - IWL_DEBUG_SCAN("SCAN complete scan\n"); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); - - ieee80211_scan_completed(priv->hw); - - /* Since setting the TXPOWER may have been deferred while - * performing the scan, fire one off */ - mutex_lock(&priv->mutex); - iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - mutex_unlock(&priv->mutex); -} - /***************************************************************************** * * mac80211 entry point functions @@ -2812,7 +2788,6 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co if (unlikely(!priv->cfg->mod_params->disable_hw_scan && test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); - set_bit(STATUS_CONF_PENDING, &priv->status); mutex_unlock(&priv->mutex); return 0; } @@ -2898,7 +2873,6 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co IWL_DEBUG_MAC80211("leave\n"); out: - clear_bit(STATUS_CONF_PENDING, &priv->status); mutex_unlock(&priv->mutex); return ret; } @@ -4117,8 +4091,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); - /* FIXME : remove when resolved PENDING */ - INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); iwl_setup_scan_deferred_work(priv); iwl_setup_power_deferred_work(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 55a4b584ce0..288b6a800e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -333,8 +333,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 -#define STATUS_CONF_PENDING 18 -#define STATUS_MODE_PENDING 19 +#define STATUS_MODE_PENDING 18 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 639904a7283..3b0bee331a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -916,10 +916,29 @@ static void iwl_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG_SCAN("SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + mutex_unlock(&priv->mutex); +} + + void iwl_setup_scan_deferred_work(struct iwl_priv *priv) { - /* FIXME: move here when resolved PENDING - * INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */ + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); INIT_WORK(&priv->request_scan, iwl_bg_request_scan); INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); -- cgit v1.2.3 From 1cf69cfbe117d645640a9230d6deb07c9db46c5f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 10 Oct 2008 12:25:45 -0700 Subject: ath9k: remove nasty FAIL macro from ath9k_hw_reset() This is fucking horribe crap code so nuke it. There I cursed too in a commit log. Signed-off-by: Luis R. Rodriguez Signed-off-by: David S. Miller --- drivers/net/wireless/ath9k/hw.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 62e44a0ef99..372ae61c7b1 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -5867,7 +5867,6 @@ bool ath9k_hw_reset(struct ath_hal *ah, bool bChannelChange, int *status) { -#define FAIL(_code) do { ecode = _code; goto bad; } while (0) u32 saveLedState; struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_channel *curchan = ah->ah_curchan; @@ -5889,7 +5888,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->channel, chan->channelFlags); - FAIL(-EINVAL); + ecode = -EINVAL; + goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) @@ -5930,7 +5930,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (!ath9k_hw_chip_reset(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n", __func__); - FAIL(-EIO); + ecode = -EINVAL; + goto bad; } if (AR_SREV_9280(ah)) { @@ -5947,8 +5948,10 @@ bool ath9k_hw_reset(struct ath_hal *ah, } ecode = ath9k_hw_process_ini(ah, chan, macmode); - if (ecode != 0) + if (ecode != 0) { + ecode = -EINVAL; goto bad; + } if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); @@ -5961,7 +5964,8 @@ 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__); - FAIL(-EIO); + ecode = -EIO; + goto bad; } ath9k_hw_decrease_chain_power(ah, chan); @@ -5989,11 +5993,15 @@ bool ath9k_hw_reset(struct ath_hal *ah, REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) - FAIL(-EIO); + if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { + ecode = -EIO; + goto bad; + } } else { - if (!(ath9k_hw_set_channel(ah, chan))) - FAIL(-EIO); + if (!(ath9k_hw_set_channel(ah, chan))) { + ecode = -EIO; + goto bad; + } } for (i = 0; i < AR_NUM_DCU; i++) @@ -6027,8 +6035,10 @@ bool ath9k_hw_reset(struct ath_hal *ah, ath9k_hw_init_bb(ah, chan); - if (!ath9k_hw_init_cal(ah, chan)) - FAIL(-ENODEV); + if (!ath9k_hw_init_cal(ah, chan)){ + ecode = -EIO;; + goto bad; + } rx_chainmask = ahp->ah_rxchainmask; if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { @@ -6064,7 +6074,6 @@ bad: if (status) *status = ecode; return false; -#undef FAIL } bool ath9k_hw_phy_disable(struct ath_hal *ah) -- cgit v1.2.3 From d2a3b222cf976bc44bb9aed13f7b17feea28f633 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 10 Oct 2008 12:26:24 -0700 Subject: ath9k: Fix return code when ath9k_hw_setpower() fails on reset We were not reporting a status code back ath9k_hw_setpower() failed during reset so lets correct this. Reported-by: Jiri Slaby Signed-off-by: Luis R. Rodriguez Signed-off-by: David S. Miller --- drivers/net/wireless/ath9k/hw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 372ae61c7b1..98bc25c9b3c 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -5892,8 +5892,10 @@ bool ath9k_hw_reset(struct ath_hal *ah, goto bad; } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + ecode = -EIO; + goto bad; + } if (curchan) ath9k_hw_getnf(ah, curchan); -- cgit v1.2.3 From 113aa838ec3a235d883f8357d31d90e16c47fc89 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 13 Oct 2008 19:01:08 -0700 Subject: net: Rationalise email address: Network Specific Parts Clean up the various different email addresses of mine listed in the code to a single current and valid address. As Dave says his network merges for 2.6.28 are now done this seems a good point to send them in where they won't risk disrupting real changes. Signed-off-by: Alan Cox Signed-off-by: David S. Miller --- drivers/net/wireless/wavelan.c | 2 +- drivers/net/wireless/wavelan.p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 136220b5ca8..e939a73ff79 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -4387,7 +4387,7 @@ MODULE_LICENSE("GPL"); * * Thanks go also to: * James Ashton (jaa101@syseng.anu.edu.au), - * Alan Cox (alan@redhat.com), + * Alan Cox (alan@lxorguk.ukuu.org.uk), * Allan Creighton (allanc@cs.usyd.edu.au), * Matthew Geier (matthew@cs.usyd.edu.au), * Remo di Giovanni (remo@cs.usyd.edu.au), diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index b33ac47dd8d..44d31bbf39e 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -186,7 +186,7 @@ * * Thanks go also to: * James Ashton , - * Alan Cox , + * Alan Cox , * Allan Creighton , * Matthew Geier , * Remo di Giovanni , -- cgit v1.2.3 From 746db510395e32ff57b9f8582e520df6b3fac618 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 10 Oct 2008 14:16:46 -0400 Subject: rtl8187: add device ID 0bda:8198 Reported by zOOmER.gm@gmail.com to work here: http://bugzilla.kernel.org/show_bug.cgi?id=11728 Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index e9902613e2e..78232776727 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -37,6 +37,7 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B}, /* Netgear */ {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, -- cgit v1.2.3 From 45527c2c4f698f8927239cfdec9f515cafed5f10 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 7 Oct 2008 09:50:01 +0200 Subject: iwlwifi: fix compilation warning when CONFIG_IWLWIFI_DEBUG is not set. When CONFIG_IWLWIFI_DEBUG is not set and CONFIG_IWLWIFI is set, we get this compilation warning: /wireless-next-2.6/drivers/net/wireless/iwlwifi/iwl-agn-rs.c: In function 'rs_free_sta': /wireless-next-2.6/drivers/net/wireless/iwlwifi/iwl-agn-rs.c:2425: warning: unused variable 'priv' This patch fixes it by adding __maybe_unused attribute. Signed-off-by: Rami Rosen Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 93944de923c..e2a58e47703 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2422,7 +2422,7 @@ static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { struct iwl_lq_sta *lq_sta = priv_sta; - struct iwl_priv *priv = priv_r; + struct iwl_priv *priv __maybe_unused = priv_r; IWL_DEBUG_RATE("enter\n"); kfree(lq_sta); -- cgit v1.2.3 From 3eadd751eb8cb8090a65b4fa72c6360fd1aa5f06 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 7 Oct 2008 08:27:45 -0700 Subject: p54: Fix compilation problem on PPC The commit entitled "p54: Fix sparse warnings" introduced a compile error on PPC architecture. Thanks to Johannes Berg for reporting this problem. Signed-off-by: Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1994aa199d3..117c7d3a52b 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -479,7 +479,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) printk(KERN_ERR "p54: eeprom parse failed!\n"); return err; } -EXPORT_SYMBOL_GPL(p54_parse_eeprom); static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) { -- cgit v1.2.3 From d5d7c584810b3be2b70c979af3283a1e48b6574d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 8 Oct 2008 09:37:28 +0800 Subject: iwlwifi: fix ct kill configuration for 5350 This patch fixes ct kill configuration for 5350. Temperature units that HW expects are in Celsius not in kelvins. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f6003e7996a..5155b8a760a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -833,12 +833,12 @@ 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: case CSR_HW_REV_TYPE_5300: - /* 5X00 wants in Celsius */ + case CSR_HW_REV_TYPE_5350: + /* 5X00 and 5350 wants in Celsius */ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; break; case CSR_HW_REV_TYPE_5150: - case CSR_HW_REV_TYPE_5350: - /* 5X50 wants in Kelvin */ + /* 5150 wants in Kelvin */ priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); break; -- cgit v1.2.3 From 552a71515eef5cba9af8bfe608149557059c4463 Mon Sep 17 00:00:00 2001 From: Andrey Borzenkov Date: Fri, 10 Oct 2008 20:22:38 +0400 Subject: orinoco: fix unsafe locking in orinoco_cs_resume [ 6972.562035] ================================= [ 6972.562040] [ INFO: inconsistent lock state ] [ 6972.562048] 2.6.27-1avb #17 [ 6972.562053] --------------------------------- [ 6972.562060] inconsistent {in-hardirq-W} -> {hardirq-on-W} usage. [ 6972.562068] pm-suspend/17062 [HC0[0]:SC0[0]:HE1:SE1] takes: [ 6972.562076] (&priv->lock){++..}, at: [] orinoco_cs_resume+0x5b/0xd0 [orinoco_cs] [ 6972.562122] {in-hardirq-W} state was registered at: [ 6972.562128] [] __lock_acquire+0x6cb/0x1640 [ 6972.562171] [] lock_acquire+0x5c/0x80 [ 6972.562181] [] _spin_lock_irqsave+0x49/0x80 [ 6972.562210] [] orinoco_interrupt+0x4d/0x16d0 [orinoco] [ 6972.562257] [] handle_IRQ_event+0x31/0x60 [ 6972.562278] [] handle_level_irq+0x6e/0xe0 [ 6972.562291] [] do_IRQ+0xb0/0x130 [ 6972.562313] [] 0xffffffff Signed-off-by: Andrey Borzenkov Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco_cs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 9eaa252c243..65fd054e017 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -403,6 +403,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; + unsigned long flags; if (! test_bit(0, &card->hard_reset_in_progress)) { err = orinoco_reinit_firmware(dev); @@ -412,7 +413,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) return -EIO; } - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); priv->hw_unavailable--; @@ -424,7 +425,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) dev->name, err); } - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); } return err; -- cgit v1.2.3 From c25bab54fe30d26a2cddf7058d77da72be630b23 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Fri, 10 Oct 2008 22:58:32 +0100 Subject: orinoco: fix unsafe locking in spectrum_cs_suspend A similar problem was highlighted in the orinoco_cs driver by lockdep. This patch fixes the spectrum_cs driver. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/spectrum_cs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 67b26d3c3cd..f5513cd4db3 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -450,10 +450,11 @@ spectrum_cs_suspend(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; int err = 0; /* Mark the device as stopped, to block IO until later */ - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); err = __orinoco_down(dev); if (err) @@ -463,7 +464,7 @@ spectrum_cs_suspend(struct pcmcia_device *link) netif_device_detach(dev); priv->hw_unavailable++; - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); return err; } -- cgit v1.2.3 From 96d46d5d792d96f80e9bd274ab6d433b8a3c22bc Mon Sep 17 00:00:00 2001 From: Manish Katiyar Date: Mon, 13 Oct 2008 16:22:42 +0530 Subject: libertas : Remove unused variable warning for "old_channel" from cmd.c Below patch removes the following warning during compilation. drivers/net/wireless/libertas/cmd.c:826: warning: unused variable 'old_channel' Signed-off-by : Manish Katiyar Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index a912fb68c09..297696de2da 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -823,7 +823,9 @@ int lbs_update_channel(struct lbs_private *priv) int lbs_set_channel(struct lbs_private *priv, u8 channel) { struct cmd_ds_802_11_rf_channel cmd; +#ifdef DEBUG u8 old_channel = priv->curbssparams.channel; +#endif int ret = 0; lbs_deb_enter(LBS_DEB_CMD); -- cgit v1.2.3 From 4233df6b748193d45f79fb7448991a473061a65d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Oct 2008 13:35:05 +0200 Subject: ath9k/mac80211: disallow fragmentation in ath9k, report to userspace As I've reported, ath9k currently fails utterly when fragmentation is enabled. This makes ath9k "support" hardware fragmentation by not supporting fragmentation at all to avoid the double-free issue. The patch also changes mac80211 to report errors from the driver operation to userspace. That hack in ath9k should be removed once the rate control algorithm it has is fixed, and we can at that time consider removing the hw fragmentation support entirely since it's not used by any driver. Signed-off-by: Johannes Berg Cc: stable@kernel.org Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 74726990d59..f05f584ab7b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1640,6 +1640,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, return ret; } +static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value) +{ + return -EOPNOTSUPP; +} + static struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -1664,7 +1669,8 @@ static struct ieee80211_ops ath9k_ops = { .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, .tx_last_beacon = NULL, - .ampdu_action = ath9k_ampdu_action + .ampdu_action = ath9k_ampdu_action, + .set_frag_threshold = ath9k_no_fragmentation, }; static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -- cgit v1.2.3 From ec366eba3b8d96fdb2e629c64fa2750be2723ba7 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 13 Oct 2008 23:41:53 +0200 Subject: p54usb: Device ID updates This patch updates p54usb's device list. It adds the ID for SMC 2862W-G v2 and marks the "Spinnaker Proto board" as a first generation device. Reported-by: Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 1912f5e9a0a..75d749bccb0 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -39,6 +39,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ + {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ @@ -63,8 +64,8 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ - {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */ + {USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ -- cgit v1.2.3 From eaca90dab6ab9853223029deffdd226f41b2028c Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Mon, 13 Oct 2008 16:34:26 -0700 Subject: rtl8187: Add USB ID for Belkin F5D7050 with RTL8187B chip The Belkin F5D7050rev5000de (id 050d:705e) has the Realtek RTL8187B chip and works with the 2.6.27 driver. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 78232776727..431e3c78bf2 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -33,6 +33,8 @@ MODULE_LICENSE("GPL"); static struct usb_device_id rtl8187_table[] __devinitdata = { /* Asus */ {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, + /* Belkin */ + {USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B}, /* Realtek */ {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, -- cgit v1.2.3 From 8713a7ccd88d93d9f8a72436088d6627c82490db Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 14 Oct 2008 23:57:43 +0200 Subject: rt2x00: fix regression introduced by "mac80211: free up 2 bytes in skb->cb" The hw_key pointer is used (and obviously NULL) after skb->cb is memset to 0. This patch grabs the iv_len before the memset call. Signed-off-by: Felix Fietkau Signed-off-by: Stephen Blackheath Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 1676ac48479..451d410ecda 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -374,7 +374,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; - unsigned int iv_len; + unsigned int iv_len = 0; if (unlikely(rt2x00queue_full(queue))) return -EINVAL; @@ -395,6 +395,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) entry->skb = skb; rt2x00queue_create_tx_descriptor(entry, &txdesc); + if (IEEE80211_SKB_CB(skb)->control.hw_key != NULL) + iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; + /* * All information is retreived from the skb->cb array, * now we should claim ownership of the driver part of that @@ -410,9 +413,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) * the frame so we can provide it to the driver seperately. */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && - !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags) && - (IEEE80211_SKB_CB(skb)->control.hw_key != NULL)) { - iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { rt2x00crypto_tx_remove_iv(skb, iv_len); } -- cgit v1.2.3 From 6e05d6c4676408b46b01eef29fd472b89ba1f98a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 21 Jul 2008 20:03:34 -0700 Subject: device create: net: convert device_create_drvdata to device_create Now that device_create() has been audited, rename things back to the original call to be sane. Cc: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c9e4a435b2f..1a019e98dac 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -533,11 +533,11 @@ static int __init init_mac80211_hwsim(void) data = hw->priv; data->hw = hw; - data->dev = device_create_drvdata(hwsim_class, NULL, 0, hw, - "hwsim%d", i); + data->dev = device_create(hwsim_class, NULL, 0, hw, + "hwsim%d", i); if (IS_ERR(data->dev)) { printk(KERN_DEBUG - "mac80211_hwsim: device_create_drvdata " + "mac80211_hwsim: device_create " "failed (%ld)\n", PTR_ERR(data->dev)); err = -ENOMEM; goto failed_drvdata; -- cgit v1.2.3