ar->cookie_count++;
}
-/* set the window address register (using 4-byte register access ). */
-static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
-{
- int status;
- s32 i;
- __le32 addr_val;
-
- /*
- * Write bytes 1,2,3 of the register to set the upper address bytes,
- * the LSB is written last to initiate the access cycle
- */
-
- for (i = 1; i <= 3; i++) {
- /*
- * Fill the buffer with the address byte value we want to
- * hit 4 times. No need to worry about endianness as the
- * same byte is copied to all four bytes of addr_val at
- * any time.
- */
- memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);
-
- /*
- * Hit each byte of the register address with a 4-byte
- * write operation to the same address, this is a harmless
- * operation.
- */
- status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
- 4, HIF_WR_SYNC_BYTE_FIX);
- if (status)
- break;
- }
-
- if (status) {
- ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
- addr, reg_addr);
- return status;
- }
-
- /*
- * Write the address register again, this time write the whole
- * 4-byte value. The effect here is that the LSB write causes the
- * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
- * effect since we are writing the same values again
- */
- addr_val = cpu_to_le32(addr);
- status = hif_read_write_sync(ar, reg_addr,
- (u8 *)&(addr_val),
- 4, HIF_WR_SYNC_BYTE_INC);
-
- if (status) {
- ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
- addr, reg_addr);
- return status;
- }
-
- return 0;
-}
-
/*
* Read from the hardware through its diagnostic window. No cooperation
* from the firmware is required for this.
{
int ret;
- /* set window register to start read cycle */
- ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
- if (ret)
- return ret;
-
- /* read the data */
- ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
- sizeof(*value), HIF_RD_SYNC_BYTE_INC);
+ ret = ath6kl_hif_diag_read32(ar, address, value);
if (ret) {
ath6kl_warn("failed to read32 through diagnose window: %d\n",
ret);
{
int ret;
- /* set write data */
- ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
- sizeof(value), HIF_WR_SYNC_BYTE_INC);
+ ret = ath6kl_hif_diag_write32(ar, address, value);
+
if (ret) {
ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
address, value);
return ret;
}
- /* set window register, which starts the write cycle */
- return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
- address);
+ return 0;
}
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
WEP_CRYPT,
keyusage,
vif->wep_key_list[index].key_len,
- NULL,
+ NULL, 0,
vif->wep_key_list[index].key,
KEY_OP_INIT_VAL, NULL,
NO_SYNC_WMIFLAG);
case NONE_AUTH:
if (vif->prwise_crypto == WEP_CRYPT)
ath6kl_install_static_wep_keys(vif);
- break;
+ if (!ik->valid || ik->key_type != WAPI_CRYPT)
+ break;
+ /* for WAPI, we need to set the delayed group key, continue: */
case WPA_PSK_AUTH:
case WPA2_PSK_AUTH:
case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
memset(key_rsc, 0, sizeof(key_rsc));
res = ath6kl_wmi_addkey_cmd(
ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type,
- GROUP_USAGE, ik->key_len, key_rsc, ik->key,
+ GROUP_USAGE, ik->key_len, key_rsc, ATH6KL_KEY_SEQ_LEN,
+ ik->key,
KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
if (res) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
wpa_ie = pos; /* WPS IE */
break; /* overrides WPA/RSN IE */
}
+ } else if (pos[0] == 0x44 && wpa_ie == NULL) {
+ /*
+ * Note: WAPI Parameter Set IE re-uses Element ID that
+ * was officially allocated for BSS AC Access Delay. As
+ * such, we need to be a bit more careful on when
+ * parsing the frame. However, BSS AC Access Delay
+ * element is not supposed to be included in
+ * (Re)Association Request frames, so this should not
+ * cause problems.
+ */
+ wpa_ie = pos; /* WAPI IE */
+ break;
}
pos += 2 + pos[1];
}
}
}
-void ath6kl_deep_sleep_enable(struct ath6kl *ar)
-{
- struct ath6kl_vif *vif;
-
- /* FIXME: for multi vif */
- vif = ath6kl_vif_first(ar);
- if (!vif) {
- /* save the current power mode before enabling power save */
- ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
-
- if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
- ath6kl_warn("ath6kl_deep_sleep_enable: "
- "wmi_powermode_cmd failed\n");
- return;
- }
-
- switch (vif->sme_state) {
- case SME_CONNECTING:
- cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
- NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
- break;
- case SME_CONNECTED:
- default:
- /*
- * FIXME: oddly enough smeState is in DISCONNECTED during
- * suspend, why? Need to send disconnected event in that
- * state.
- */
- cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
- break;
- }
-
- if (test_bit(CONNECTED, &vif->flags) ||
- test_bit(CONNECT_PEND, &vif->flags))
- ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
-
- vif->sme_state = SME_DISCONNECTED;
-
- /* disable scanning */
- if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
- 0, 0, 0, 0, 0, 0, 0) != 0)
- printk(KERN_WARNING "ath6kl: failed to disable scan "
- "during suspend\n");
-
- ath6kl_cfg80211_scan_complete_event(vif, -ECANCELED);
-
- /* save the current power mode before enabling power save */
- ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
-
- if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
- ath6kl_warn("ath6kl_deep_sleep_enable: "
- "wmi_powermode_cmd failed\n");
-}
-
/* WMI Event handlers */
-static const char *get_hw_id_string(u32 id)
-{
- switch (id) {
- case AR6003_REV1_VERSION:
- return "1.0";
- case AR6003_REV2_VERSION:
- return "2.0";
- case AR6003_REV3_VERSION:
- return "2.1.1";
- default:
- return "unknown";
- }
-}
-
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
{
struct ath6kl *ar = devt;
/* indicate to the waiting thread that the ready event was received */
set_bit(WMI_READY, &ar->flag);
wake_up(&ar->event_wq);
-
- if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
- ath6kl_info("hw %s fw %s%s\n",
- get_hw_id_string(ar->wiphy->hw_version),
- ar->wiphy->fw_version,
- test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
- }
}
void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
{
struct ath6kl *ar = vif->ar;
+ bool aborted = false;
+
+ if (status != WMI_SCAN_STATUS_SUCCESS)
+ aborted = true;
- ath6kl_cfg80211_scan_complete_event(vif, status);
+ ath6kl_cfg80211_scan_complete_event(vif, aborted);
if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
{
struct ath6kl_vif *vif;
- spin_lock(&ar->list_lock);
+ spin_lock_bh(&ar->list_lock);
if (list_empty(&ar->vif_list)) {
- spin_unlock(&ar->list_lock);
+ spin_unlock_bh(&ar->list_lock);
return NULL;
}
vif = list_first_entry(&ar->vif_list, struct ath6kl_vif, list);
- spin_unlock(&ar->list_lock);
+ spin_unlock_bh(&ar->list_lock);
return vif;
}
static int ath6kl_open(struct net_device *dev)
{
struct ath6kl_vif *vif = netdev_priv(dev);
- int ret;
-
- /* FIXME: how to handle multi vif support? */
- ret = ath6kl_init_hw_start(vif->ar);
- if (ret)
- return ret;
set_bit(WLAN_ENABLED, &vif->flags);
static int ath6kl_close(struct net_device *dev)
{
- struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
- int ret;
netif_stop_queue(dev);
- ath6kl_disconnect(vif);
-
- if (test_bit(WMI_READY, &ar->flag)) {
- if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF,
- 0, 0, 0, 0, 0, 0, 0, 0, 0))
- return -EIO;
+ ath6kl_cfg80211_stop(vif);
- clear_bit(WLAN_ENABLED, &vif->flags);
- }
-
- ath6kl_cfg80211_scan_complete_event(vif, -ECANCELED);
-
- /* FIXME: how to handle multi vif support? */
- ret = ath6kl_init_hw_stop(ar);
- if (ret)
- return ret;
+ clear_bit(WLAN_ENABLED, &vif->flags);
return 0;
}
return &vif->net_stats;
}
+static int ath6kl_set_features(struct net_device *dev, u32 features)
+{
+ struct ath6kl_vif *vif = netdev_priv(dev);
+ struct ath6kl *ar = vif->ar;
+ int err = 0;
+
+ if ((features & NETIF_F_RXCSUM) &&
+ (ar->rx_meta_ver != WMI_META_VERSION_2)) {
+ ar->rx_meta_ver = WMI_META_VERSION_2;
+ err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+ vif->fw_vif_idx,
+ ar->rx_meta_ver, 0, 0);
+ if (err) {
+ dev->features = features & ~NETIF_F_RXCSUM;
+ return err;
+ }
+ } else if (!(features & NETIF_F_RXCSUM) &&
+ (ar->rx_meta_ver == WMI_META_VERSION_2)) {
+ ar->rx_meta_ver = 0;
+ err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+ vif->fw_vif_idx,
+ ar->rx_meta_ver, 0, 0);
+ if (err) {
+ dev->features = features | NETIF_F_RXCSUM;
+ return err;
+ }
+
+ }
+
+ return err;
+}
+
static struct net_device_ops ath6kl_netdev_ops = {
.ndo_open = ath6kl_open,
.ndo_stop = ath6kl_close,
.ndo_start_xmit = ath6kl_data_tx,
.ndo_get_stats = ath6kl_get_stats,
+ .ndo_set_features = ath6kl_set_features,
};
void init_netdev(struct net_device *dev)