diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-lib.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 422 |
1 files changed, 416 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index eedd71f5506b..a8f2adfd799e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -247,7 +247,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, | |||
247 | struct iwl_ht_agg *agg; | 247 | struct iwl_ht_agg *agg; |
248 | 248 | ||
249 | agg = &priv->stations[sta_id].tid[tid].agg; | 249 | agg = &priv->stations[sta_id].tid[tid].agg; |
250 | 250 | /* | |
251 | * If the BT kill count is non-zero, we'll get this | ||
252 | * notification again. | ||
253 | */ | ||
254 | if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && | ||
255 | priv->cfg->advanced_bt_coexist) { | ||
256 | IWL_WARN(priv, "receive reply tx with bt_kill\n"); | ||
257 | } | ||
251 | iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); | 258 | iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); |
252 | 259 | ||
253 | /* check if BAR is needed */ | 260 | /* check if BAR is needed */ |
@@ -1156,6 +1163,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1156 | }; | 1163 | }; |
1157 | struct iwl_scan_cmd *scan; | 1164 | struct iwl_scan_cmd *scan; |
1158 | struct ieee80211_conf *conf = NULL; | 1165 | struct ieee80211_conf *conf = NULL; |
1166 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
1159 | u32 rate_flags = 0; | 1167 | u32 rate_flags = 0; |
1160 | u16 cmd_len; | 1168 | u16 cmd_len; |
1161 | u16 rx_chain = 0; | 1169 | u16 rx_chain = 0; |
@@ -1168,6 +1176,9 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1168 | u8 active_chains; | 1176 | u8 active_chains; |
1169 | u8 scan_tx_antennas = priv->hw_params.valid_tx_ant; | 1177 | u8 scan_tx_antennas = priv->hw_params.valid_tx_ant; |
1170 | 1178 | ||
1179 | if (vif) | ||
1180 | ctx = iwl_rxon_ctx_from_vif(vif); | ||
1181 | |||
1171 | conf = ieee80211_get_hw_conf(priv->hw); | 1182 | conf = ieee80211_get_hw_conf(priv->hw); |
1172 | 1183 | ||
1173 | cancel_delayed_work(&priv->scan_check); | 1184 | cancel_delayed_work(&priv->scan_check); |
@@ -1225,7 +1236,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1225 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; | 1236 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; |
1226 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; | 1237 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; |
1227 | 1238 | ||
1228 | if (iwl_is_associated(priv)) { | 1239 | if (iwl_is_any_associated(priv)) { |
1229 | u16 interval = 0; | 1240 | u16 interval = 0; |
1230 | u32 extra; | 1241 | u32 extra; |
1231 | u32 suspend_time = 100; | 1242 | u32 suspend_time = 100; |
@@ -1276,13 +1287,15 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1276 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | 1287 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); |
1277 | 1288 | ||
1278 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; | 1289 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; |
1279 | scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; | 1290 | scan->tx_cmd.sta_id = ctx->bcast_sta_id; |
1280 | scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; | 1291 | scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; |
1281 | 1292 | ||
1282 | switch (priv->scan_band) { | 1293 | switch (priv->scan_band) { |
1283 | case IEEE80211_BAND_2GHZ: | 1294 | case IEEE80211_BAND_2GHZ: |
1284 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; | 1295 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; |
1285 | chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK) | 1296 | chan_mod = le32_to_cpu( |
1297 | priv->contexts[IWL_RXON_CTX_BSS].active.flags & | ||
1298 | RXON_FLG_CHANNEL_MODE_MSK) | ||
1286 | >> RXON_FLG_CHANNEL_MODE_POS; | 1299 | >> RXON_FLG_CHANNEL_MODE_POS; |
1287 | if (chan_mod == CHANNEL_MODE_PURE_40) { | 1300 | if (chan_mod == CHANNEL_MODE_PURE_40) { |
1288 | rate = IWL_RATE_6M_PLCP; | 1301 | rate = IWL_RATE_6M_PLCP; |
@@ -1290,6 +1303,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1290 | rate = IWL_RATE_1M_PLCP; | 1303 | rate = IWL_RATE_1M_PLCP; |
1291 | rate_flags = RATE_MCS_CCK_MSK; | 1304 | rate_flags = RATE_MCS_CCK_MSK; |
1292 | } | 1305 | } |
1306 | /* | ||
1307 | * Internal scans are passive, so we can indiscriminately set | ||
1308 | * the BT ignore flag on 2.4 GHz since it applies to TX only. | ||
1309 | */ | ||
1310 | if (priv->cfg->advanced_bt_coexist) | ||
1311 | scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; | ||
1293 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED; | 1312 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED; |
1294 | break; | 1313 | break; |
1295 | case IEEE80211_BAND_5GHZ: | 1314 | case IEEE80211_BAND_5GHZ: |
@@ -1327,6 +1346,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1327 | if (priv->cfg->scan_tx_antennas[band]) | 1346 | if (priv->cfg->scan_tx_antennas[band]) |
1328 | scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; | 1347 | scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; |
1329 | 1348 | ||
1349 | if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) { | ||
1350 | /* operated as 1x1 in full concurrency mode */ | ||
1351 | scan_tx_antennas = | ||
1352 | first_antenna(priv->cfg->scan_tx_antennas[band]); | ||
1353 | } | ||
1354 | |||
1330 | priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band], | 1355 | priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band], |
1331 | scan_tx_antennas); | 1356 | scan_tx_antennas); |
1332 | rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); | 1357 | rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); |
@@ -1345,6 +1370,11 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1345 | 1370 | ||
1346 | rx_ant = first_antenna(active_chains); | 1371 | rx_ant = first_antenna(active_chains); |
1347 | } | 1372 | } |
1373 | if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) { | ||
1374 | /* operated as 1x1 in full concurrency mode */ | ||
1375 | rx_ant = first_antenna(rx_ant); | ||
1376 | } | ||
1377 | |||
1348 | /* MIMO is not used here, but value is required */ | 1378 | /* MIMO is not used here, but value is required */ |
1349 | rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; | 1379 | rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; |
1350 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; | 1380 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; |
@@ -1394,6 +1424,11 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1394 | scan->len = cpu_to_le16(cmd.len); | 1424 | scan->len = cpu_to_le16(cmd.len); |
1395 | 1425 | ||
1396 | set_bit(STATUS_SCAN_HW, &priv->status); | 1426 | set_bit(STATUS_SCAN_HW, &priv->status); |
1427 | |||
1428 | if (priv->cfg->ops->hcmd->set_pan_params && | ||
1429 | priv->cfg->ops->hcmd->set_pan_params(priv)) | ||
1430 | goto done; | ||
1431 | |||
1397 | if (iwl_send_cmd_sync(priv, &cmd)) | 1432 | if (iwl_send_cmd_sync(priv, &cmd)) |
1398 | goto done; | 1433 | goto done; |
1399 | 1434 | ||
@@ -1420,7 +1455,8 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, | |||
1420 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | 1455 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; |
1421 | 1456 | ||
1422 | if (add) | 1457 | if (add) |
1423 | return iwl_add_bssid_station(priv, vif->bss_conf.bssid, true, | 1458 | return iwl_add_bssid_station(priv, vif_priv->ctx, |
1459 | vif->bss_conf.bssid, true, | ||
1424 | &vif_priv->ibss_bssid_sta_id); | 1460 | &vif_priv->ibss_bssid_sta_id); |
1425 | return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id, | 1461 | return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id, |
1426 | vif->bss_conf.bssid); | 1462 | vif->bss_conf.bssid); |
@@ -1453,7 +1489,7 @@ int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv) | |||
1453 | 1489 | ||
1454 | /* waiting for all the tx frames complete might take a while */ | 1490 | /* waiting for all the tx frames complete might take a while */ |
1455 | for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { | 1491 | for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { |
1456 | if (cnt == IWL_CMD_QUEUE_NUM) | 1492 | if (cnt == priv->cmd_queue) |
1457 | continue; | 1493 | continue; |
1458 | txq = &priv->txq[cnt]; | 1494 | txq = &priv->txq[cnt]; |
1459 | q = &txq->q; | 1495 | q = &txq->q; |
@@ -1518,3 +1554,377 @@ done: | |||
1518 | ieee80211_wake_queues(priv->hw); | 1554 | ieee80211_wake_queues(priv->hw); |
1519 | mutex_unlock(&priv->mutex); | 1555 | mutex_unlock(&priv->mutex); |
1520 | } | 1556 | } |
1557 | |||
1558 | /* | ||
1559 | * BT coex | ||
1560 | */ | ||
1561 | /* | ||
1562 | * Macros to access the lookup table. | ||
1563 | * | ||
1564 | * The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req, | ||
1565 | * wifi_prio, wifi_txrx and wifi_sh_ant_req. | ||
1566 | * | ||
1567 | * It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH | ||
1568 | * | ||
1569 | * The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits | ||
1570 | * one after another in 32-bit registers, and "registers" 0 through 7 contain | ||
1571 | * the WLAN_KILL and ANT_SWITCH bits interleaved (in that order). | ||
1572 | * | ||
1573 | * These macros encode that format. | ||
1574 | */ | ||
1575 | #define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \ | ||
1576 | wifi_txrx, wifi_sh_ant_req) \ | ||
1577 | (bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \ | ||
1578 | (wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6)) | ||
1579 | |||
1580 | #define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \ | ||
1581 | lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f))) | ||
1582 | #define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1583 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1584 | (!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \ | ||
1585 | bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ | ||
1586 | wifi_sh_ant_req)))) | ||
1587 | #define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1588 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1589 | LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \ | ||
1590 | bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ | ||
1591 | wifi_sh_ant_req)) | ||
1592 | #define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1593 | wifi_req, wifi_prio, wifi_txrx, \ | ||
1594 | wifi_sh_ant_req) \ | ||
1595 | LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \ | ||
1596 | bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ | ||
1597 | wifi_sh_ant_req)) | ||
1598 | |||
1599 | #define LUT_WLAN_KILL_OP(lut, op, val) \ | ||
1600 | lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e))) | ||
1601 | #define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1602 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1603 | (!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1604 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)))) | ||
1605 | #define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1606 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1607 | LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1608 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1609 | #define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1610 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1611 | LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1612 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1613 | |||
1614 | #define LUT_ANT_SWITCH_OP(lut, op, val) \ | ||
1615 | lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1))) | ||
1616 | #define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1617 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1618 | (!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1619 | wifi_req, wifi_prio, wifi_txrx, \ | ||
1620 | wifi_sh_ant_req)))) | ||
1621 | #define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1622 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1623 | LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1624 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1625 | #define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1626 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1627 | LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1628 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1629 | |||
1630 | static const __le32 iwlagn_def_3w_lookup[12] = { | ||
1631 | cpu_to_le32(0xaaaaaaaa), | ||
1632 | cpu_to_le32(0xaaaaaaaa), | ||
1633 | cpu_to_le32(0xaeaaaaaa), | ||
1634 | cpu_to_le32(0xaaaaaaaa), | ||
1635 | cpu_to_le32(0xcc00ff28), | ||
1636 | cpu_to_le32(0x0000aaaa), | ||
1637 | cpu_to_le32(0xcc00aaaa), | ||
1638 | cpu_to_le32(0x0000aaaa), | ||
1639 | cpu_to_le32(0xc0004000), | ||
1640 | cpu_to_le32(0x00004000), | ||
1641 | cpu_to_le32(0xf0005000), | ||
1642 | cpu_to_le32(0xf0004000), | ||
1643 | }; | ||
1644 | |||
1645 | static const __le32 iwlagn_concurrent_lookup[12] = { | ||
1646 | cpu_to_le32(0xaaaaaaaa), | ||
1647 | cpu_to_le32(0xaaaaaaaa), | ||
1648 | cpu_to_le32(0xaaaaaaaa), | ||
1649 | cpu_to_le32(0xaaaaaaaa), | ||
1650 | cpu_to_le32(0xaaaaaaaa), | ||
1651 | cpu_to_le32(0xaaaaaaaa), | ||
1652 | cpu_to_le32(0xaaaaaaaa), | ||
1653 | cpu_to_le32(0xaaaaaaaa), | ||
1654 | cpu_to_le32(0x00000000), | ||
1655 | cpu_to_le32(0x00000000), | ||
1656 | cpu_to_le32(0x00000000), | ||
1657 | cpu_to_le32(0x00000000), | ||
1658 | }; | ||
1659 | |||
1660 | void iwlagn_send_advance_bt_config(struct iwl_priv *priv) | ||
1661 | { | ||
1662 | struct iwlagn_bt_cmd bt_cmd = { | ||
1663 | .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT, | ||
1664 | .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT, | ||
1665 | .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT, | ||
1666 | .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT, | ||
1667 | }; | ||
1668 | |||
1669 | BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != | ||
1670 | sizeof(bt_cmd.bt3_lookup_table)); | ||
1671 | |||
1672 | bt_cmd.prio_boost = priv->cfg->bt_prio_boost; | ||
1673 | bt_cmd.kill_ack_mask = priv->kill_ack_mask; | ||
1674 | bt_cmd.kill_cts_mask = priv->kill_cts_mask; | ||
1675 | bt_cmd.valid = priv->bt_valid; | ||
1676 | |||
1677 | /* | ||
1678 | * Configure BT coex mode to "no coexistence" when the | ||
1679 | * user disabled BT coexistence, we have no interface | ||
1680 | * (might be in monitor mode), or the interface is in | ||
1681 | * IBSS mode (no proper uCode support for coex then). | ||
1682 | */ | ||
1683 | if (!bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) { | ||
1684 | bt_cmd.flags = 0; | ||
1685 | } else { | ||
1686 | bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W << | ||
1687 | IWLAGN_BT_FLAG_COEX_MODE_SHIFT; | ||
1688 | if (priv->bt_ch_announce) | ||
1689 | bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION; | ||
1690 | IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags); | ||
1691 | } | ||
1692 | if (priv->bt_full_concurrent) | ||
1693 | memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup, | ||
1694 | sizeof(iwlagn_concurrent_lookup)); | ||
1695 | else | ||
1696 | memcpy(bt_cmd.bt3_lookup_table, iwlagn_def_3w_lookup, | ||
1697 | sizeof(iwlagn_def_3w_lookup)); | ||
1698 | |||
1699 | IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n", | ||
1700 | bt_cmd.flags ? "active" : "disabled", | ||
1701 | priv->bt_full_concurrent ? | ||
1702 | "full concurrency" : "3-wire"); | ||
1703 | |||
1704 | if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd)) | ||
1705 | IWL_ERR(priv, "failed to send BT Coex Config\n"); | ||
1706 | |||
1707 | /* | ||
1708 | * When we are doing a restart, need to also reconfigure BT | ||
1709 | * SCO to the device. If not doing a restart, bt_sco_active | ||
1710 | * will always be false, so there's no need to have an extra | ||
1711 | * variable to check for it. | ||
1712 | */ | ||
1713 | if (priv->bt_sco_active) { | ||
1714 | struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; | ||
1715 | |||
1716 | if (priv->bt_sco_active) | ||
1717 | sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE; | ||
1718 | if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_SCO, | ||
1719 | sizeof(sco_cmd), &sco_cmd)) | ||
1720 | IWL_ERR(priv, "failed to send BT SCO command\n"); | ||
1721 | } | ||
1722 | } | ||
1723 | |||
1724 | static void iwlagn_bt_traffic_change_work(struct work_struct *work) | ||
1725 | { | ||
1726 | struct iwl_priv *priv = | ||
1727 | container_of(work, struct iwl_priv, bt_traffic_change_work); | ||
1728 | struct iwl_rxon_context *ctx; | ||
1729 | int smps_request = -1; | ||
1730 | |||
1731 | IWL_DEBUG_INFO(priv, "BT traffic load changes: %d\n", | ||
1732 | priv->bt_traffic_load); | ||
1733 | |||
1734 | switch (priv->bt_traffic_load) { | ||
1735 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1736 | smps_request = IEEE80211_SMPS_AUTOMATIC; | ||
1737 | break; | ||
1738 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1739 | smps_request = IEEE80211_SMPS_DYNAMIC; | ||
1740 | break; | ||
1741 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1742 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1743 | smps_request = IEEE80211_SMPS_STATIC; | ||
1744 | break; | ||
1745 | default: | ||
1746 | IWL_ERR(priv, "Invalid BT traffic load: %d\n", | ||
1747 | priv->bt_traffic_load); | ||
1748 | break; | ||
1749 | } | ||
1750 | |||
1751 | mutex_lock(&priv->mutex); | ||
1752 | |||
1753 | if (priv->cfg->ops->lib->update_chain_flags) | ||
1754 | priv->cfg->ops->lib->update_chain_flags(priv); | ||
1755 | |||
1756 | if (smps_request != -1) { | ||
1757 | for_each_context(priv, ctx) { | ||
1758 | if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) | ||
1759 | ieee80211_request_smps(ctx->vif, smps_request); | ||
1760 | } | ||
1761 | } | ||
1762 | |||
1763 | mutex_unlock(&priv->mutex); | ||
1764 | } | ||
1765 | |||
1766 | static void iwlagn_print_uartmsg(struct iwl_priv *priv, | ||
1767 | struct iwl_bt_uart_msg *uart_msg) | ||
1768 | { | ||
1769 | IWL_DEBUG_NOTIF(priv, "Message Type = 0x%X, SSN = 0x%X, " | ||
1770 | "Update Req = 0x%X", | ||
1771 | (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >> | ||
1772 | BT_UART_MSG_FRAME1MSGTYPE_POS, | ||
1773 | (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >> | ||
1774 | BT_UART_MSG_FRAME1SSN_POS, | ||
1775 | (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >> | ||
1776 | BT_UART_MSG_FRAME1UPDATEREQ_POS); | ||
1777 | |||
1778 | IWL_DEBUG_NOTIF(priv, "Open connections = 0x%X, Traffic load = 0x%X, " | ||
1779 | "Chl_SeqN = 0x%X, In band = 0x%X", | ||
1780 | (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >> | ||
1781 | BT_UART_MSG_FRAME2OPENCONNECTIONS_POS, | ||
1782 | (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >> | ||
1783 | BT_UART_MSG_FRAME2TRAFFICLOAD_POS, | ||
1784 | (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >> | ||
1785 | BT_UART_MSG_FRAME2CHLSEQN_POS, | ||
1786 | (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >> | ||
1787 | BT_UART_MSG_FRAME2INBAND_POS); | ||
1788 | |||
1789 | IWL_DEBUG_NOTIF(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, " | ||
1790 | "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X", | ||
1791 | (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >> | ||
1792 | BT_UART_MSG_FRAME3SCOESCO_POS, | ||
1793 | (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >> | ||
1794 | BT_UART_MSG_FRAME3SNIFF_POS, | ||
1795 | (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >> | ||
1796 | BT_UART_MSG_FRAME3A2DP_POS, | ||
1797 | (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >> | ||
1798 | BT_UART_MSG_FRAME3ACL_POS, | ||
1799 | (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >> | ||
1800 | BT_UART_MSG_FRAME3MASTER_POS, | ||
1801 | (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >> | ||
1802 | BT_UART_MSG_FRAME3OBEX_POS); | ||
1803 | |||
1804 | IWL_DEBUG_NOTIF(priv, "Idle duration = 0x%X", | ||
1805 | (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >> | ||
1806 | BT_UART_MSG_FRAME4IDLEDURATION_POS); | ||
1807 | |||
1808 | IWL_DEBUG_NOTIF(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, " | ||
1809 | "eSCO Retransmissions = 0x%X", | ||
1810 | (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >> | ||
1811 | BT_UART_MSG_FRAME5TXACTIVITY_POS, | ||
1812 | (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >> | ||
1813 | BT_UART_MSG_FRAME5RXACTIVITY_POS, | ||
1814 | (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >> | ||
1815 | BT_UART_MSG_FRAME5ESCORETRANSMIT_POS); | ||
1816 | |||
1817 | IWL_DEBUG_NOTIF(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X", | ||
1818 | (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >> | ||
1819 | BT_UART_MSG_FRAME6SNIFFINTERVAL_POS, | ||
1820 | (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >> | ||
1821 | BT_UART_MSG_FRAME6DISCOVERABLE_POS); | ||
1822 | |||
1823 | IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Inquiry/Page SR Mode = " | ||
1824 | "0x%X, Connectable = 0x%X", | ||
1825 | (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >> | ||
1826 | BT_UART_MSG_FRAME7SNIFFACTIVITY_POS, | ||
1827 | (BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK & uart_msg->frame7) >> | ||
1828 | BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS, | ||
1829 | (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >> | ||
1830 | BT_UART_MSG_FRAME7CONNECTABLE_POS); | ||
1831 | } | ||
1832 | |||
1833 | static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv, | ||
1834 | struct iwl_bt_uart_msg *uart_msg) | ||
1835 | { | ||
1836 | u8 kill_ack_msk; | ||
1837 | __le32 bt_kill_ack_msg[2] = { | ||
1838 | cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) }; | ||
1839 | |||
1840 | kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK | | ||
1841 | BT_UART_MSG_FRAME3SNIFF_MSK | | ||
1842 | BT_UART_MSG_FRAME3SCOESCO_MSK) & | ||
1843 | uart_msg->frame3) == 0) ? 1 : 0; | ||
1844 | if (priv->kill_ack_mask != bt_kill_ack_msg[kill_ack_msk]) { | ||
1845 | priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK; | ||
1846 | priv->kill_ack_mask = bt_kill_ack_msg[kill_ack_msk]; | ||
1847 | /* schedule to send runtime bt_config */ | ||
1848 | queue_work(priv->workqueue, &priv->bt_runtime_config); | ||
1849 | } | ||
1850 | |||
1851 | } | ||
1852 | |||
1853 | void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, | ||
1854 | struct iwl_rx_mem_buffer *rxb) | ||
1855 | { | ||
1856 | unsigned long flags; | ||
1857 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1858 | struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; | ||
1859 | struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; | ||
1860 | struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg; | ||
1861 | u8 last_traffic_load; | ||
1862 | |||
1863 | IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n"); | ||
1864 | IWL_DEBUG_NOTIF(priv, " status: %d\n", coex->bt_status); | ||
1865 | IWL_DEBUG_NOTIF(priv, " traffic load: %d\n", coex->bt_traffic_load); | ||
1866 | IWL_DEBUG_NOTIF(priv, " CI compliance: %d\n", | ||
1867 | coex->bt_ci_compliance); | ||
1868 | iwlagn_print_uartmsg(priv, uart_msg); | ||
1869 | |||
1870 | last_traffic_load = priv->notif_bt_traffic_load; | ||
1871 | priv->notif_bt_traffic_load = coex->bt_traffic_load; | ||
1872 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { | ||
1873 | if (priv->bt_status != coex->bt_status || | ||
1874 | last_traffic_load != coex->bt_traffic_load) { | ||
1875 | if (coex->bt_status) { | ||
1876 | /* BT on */ | ||
1877 | if (!priv->bt_ch_announce) | ||
1878 | priv->bt_traffic_load = | ||
1879 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH; | ||
1880 | else | ||
1881 | priv->bt_traffic_load = | ||
1882 | coex->bt_traffic_load; | ||
1883 | } else { | ||
1884 | /* BT off */ | ||
1885 | priv->bt_traffic_load = | ||
1886 | IWL_BT_COEX_TRAFFIC_LOAD_NONE; | ||
1887 | } | ||
1888 | priv->bt_status = coex->bt_status; | ||
1889 | queue_work(priv->workqueue, | ||
1890 | &priv->bt_traffic_change_work); | ||
1891 | } | ||
1892 | if (priv->bt_sco_active != | ||
1893 | (uart_msg->frame3 & BT_UART_MSG_FRAME3SCOESCO_MSK)) { | ||
1894 | priv->bt_sco_active = uart_msg->frame3 & | ||
1895 | BT_UART_MSG_FRAME3SCOESCO_MSK; | ||
1896 | if (priv->bt_sco_active) | ||
1897 | sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE; | ||
1898 | iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO, | ||
1899 | sizeof(sco_cmd), &sco_cmd, NULL); | ||
1900 | } | ||
1901 | } | ||
1902 | |||
1903 | iwlagn_set_kill_ack_msk(priv, uart_msg); | ||
1904 | |||
1905 | /* FIXME: based on notification, adjust the prio_boost */ | ||
1906 | |||
1907 | spin_lock_irqsave(&priv->lock, flags); | ||
1908 | priv->bt_ci_compliance = coex->bt_ci_compliance; | ||
1909 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1910 | } | ||
1911 | |||
1912 | void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv) | ||
1913 | { | ||
1914 | iwlagn_rx_handler_setup(priv); | ||
1915 | priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] = | ||
1916 | iwlagn_bt_coex_profile_notif; | ||
1917 | } | ||
1918 | |||
1919 | void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv) | ||
1920 | { | ||
1921 | iwlagn_setup_deferred_work(priv); | ||
1922 | |||
1923 | INIT_WORK(&priv->bt_traffic_change_work, | ||
1924 | iwlagn_bt_traffic_change_work); | ||
1925 | } | ||
1926 | |||
1927 | void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv) | ||
1928 | { | ||
1929 | cancel_work_sync(&priv->bt_traffic_change_work); | ||
1930 | } | ||