diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-08-23 10:56:57 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-25 14:33:21 -0400 |
commit | 9e4afc21895476114f131b70d1e8fdc3a9c75bb3 (patch) | |
tree | 53c858628a54f258589b5b5d7ea23871f0c58992 /drivers/net/wireless/iwlwifi | |
parent | d44ae69e80358ff88d39a14d92c27dba4e90c0c5 (diff) |
iwlwifi: add BT notification support for bt coex
When advanced bt coex enabled, uCode will send bt status
notification to driver, here add support for it.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 161 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 4 |
3 files changed, 171 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index fc2eeb00c78c..f049ebc4a6aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -377,6 +377,90 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, | |||
377 | return iwl_send_cmd_sync(priv, &hcmd); | 377 | return iwl_send_cmd_sync(priv, &hcmd); |
378 | } | 378 | } |
379 | 379 | ||
380 | static void iwl6000g2b_bt_traffic_change_work(struct work_struct *work) | ||
381 | { | ||
382 | struct iwl_priv *priv = | ||
383 | container_of(work, struct iwl_priv, bt_traffic_change_work); | ||
384 | int smps_request = -1; | ||
385 | |||
386 | switch (priv->bt_traffic_load) { | ||
387 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
388 | smps_request = IEEE80211_SMPS_AUTOMATIC; | ||
389 | break; | ||
390 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
391 | smps_request = IEEE80211_SMPS_DYNAMIC; | ||
392 | break; | ||
393 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
394 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
395 | smps_request = IEEE80211_SMPS_STATIC; | ||
396 | break; | ||
397 | default: | ||
398 | IWL_ERR(priv, "Invalid BT traffic load: %d\n", | ||
399 | priv->bt_traffic_load); | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | mutex_lock(&priv->mutex); | ||
404 | |||
405 | if (smps_request != -1 && | ||
406 | priv->vif && priv->vif->type == NL80211_IFTYPE_STATION) | ||
407 | ieee80211_request_smps(priv->vif, smps_request); | ||
408 | |||
409 | mutex_unlock(&priv->mutex); | ||
410 | } | ||
411 | |||
412 | static void iwl6000g2b_bt_coex_profile_notif(struct iwl_priv *priv, | ||
413 | struct iwl_rx_mem_buffer *rxb) | ||
414 | { | ||
415 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
416 | struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; | ||
417 | struct iwl6000g2b_bt_sco_cmd sco_cmd = { .flags = 0 }; | ||
418 | |||
419 | IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n"); | ||
420 | IWL_DEBUG_NOTIF(priv, " status: %d\n", coex->bt_status); | ||
421 | IWL_DEBUG_NOTIF(priv, " traffic load: %d\n", coex->bt_traffic_load); | ||
422 | IWL_DEBUG_NOTIF(priv, " CI compliance: %d\n", coex->bt_ci_compliance); | ||
423 | IWL_DEBUG_NOTIF(priv, " UART msg: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x:" | ||
424 | "%.2x:%.2x\n", | ||
425 | coex->uart_msg[0], coex->uart_msg[1], coex->uart_msg[2], | ||
426 | coex->uart_msg[3], coex->uart_msg[4], coex->uart_msg[5], | ||
427 | coex->uart_msg[6], coex->uart_msg[7]); | ||
428 | |||
429 | if (coex->bt_traffic_load != priv->bt_traffic_load) { | ||
430 | priv->bt_traffic_load = coex->bt_traffic_load; | ||
431 | |||
432 | queue_work(priv->workqueue, &priv->bt_traffic_change_work); | ||
433 | } | ||
434 | |||
435 | /* FIXME: add defines for this check */ | ||
436 | priv->bt_sco_active = coex->uart_msg[3] & 1; | ||
437 | if (priv->bt_sco_active) | ||
438 | sco_cmd.flags |= IWL6000G2B_BT_SCO_ACTIVE; | ||
439 | iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO, | ||
440 | sizeof(sco_cmd), &sco_cmd, NULL); | ||
441 | } | ||
442 | |||
443 | void iwl6000g2b_rx_handler_setup(struct iwl_priv *priv) | ||
444 | { | ||
445 | iwlagn_rx_handler_setup(priv); | ||
446 | priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] = | ||
447 | iwl6000g2b_bt_coex_profile_notif; | ||
448 | } | ||
449 | |||
450 | static void iwl6000g2b_bt_setup_deferred_work(struct iwl_priv *priv) | ||
451 | { | ||
452 | iwlagn_setup_deferred_work(priv); | ||
453 | |||
454 | INIT_WORK(&priv->bt_traffic_change_work, | ||
455 | iwl6000g2b_bt_traffic_change_work); | ||
456 | |||
457 | } | ||
458 | |||
459 | static void iwl6000g2b_bt_cancel_deferred_work(struct iwl_priv *priv) | ||
460 | { | ||
461 | cancel_work_sync(&priv->bt_traffic_change_work); | ||
462 | } | ||
463 | |||
380 | static struct iwl_lib_ops iwl6000_lib = { | 464 | static struct iwl_lib_ops iwl6000_lib = { |
381 | .set_hw_params = iwl6000_hw_set_hw_params, | 465 | .set_hw_params = iwl6000_hw_set_hw_params, |
382 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | 466 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, |
@@ -451,6 +535,81 @@ static struct iwl_lib_ops iwl6000_lib = { | |||
451 | } | 535 | } |
452 | }; | 536 | }; |
453 | 537 | ||
538 | static struct iwl_lib_ops iwl6000g2b_lib = { | ||
539 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
540 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | ||
541 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | ||
542 | .txq_set_sched = iwlagn_txq_set_sched, | ||
543 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
544 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
545 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | ||
546 | .txq_free_tfd = iwl_hw_txq_free_tfd, | ||
547 | .txq_init = iwl_hw_tx_queue_init, | ||
548 | .rx_handler_setup = iwl6000g2b_rx_handler_setup, | ||
549 | .setup_deferred_work = iwl6000g2b_bt_setup_deferred_work, | ||
550 | .cancel_deferred_work = iwl6000g2b_bt_cancel_deferred_work, | ||
551 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, | ||
552 | .load_ucode = iwlagn_load_ucode, | ||
553 | .dump_nic_event_log = iwl_dump_nic_event_log, | ||
554 | .dump_nic_error_log = iwl_dump_nic_error_log, | ||
555 | .dump_csr = iwl_dump_csr, | ||
556 | .dump_fh = iwl_dump_fh, | ||
557 | .init_alive_start = iwlagn_init_alive_start, | ||
558 | .alive_notify = iwlagn_alive_notify, | ||
559 | .send_tx_power = iwlagn_send_tx_power, | ||
560 | .update_chain_flags = iwl_update_chain_flags, | ||
561 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
562 | .apm_ops = { | ||
563 | .init = iwl_apm_init, | ||
564 | .stop = iwl_apm_stop, | ||
565 | .config = iwl6000_nic_config, | ||
566 | .set_pwr_src = iwl_set_pwr_src, | ||
567 | }, | ||
568 | .eeprom_ops = { | ||
569 | .regulatory_bands = { | ||
570 | EEPROM_REG_BAND_1_CHANNELS, | ||
571 | EEPROM_REG_BAND_2_CHANNELS, | ||
572 | EEPROM_REG_BAND_3_CHANNELS, | ||
573 | EEPROM_REG_BAND_4_CHANNELS, | ||
574 | EEPROM_REG_BAND_5_CHANNELS, | ||
575 | EEPROM_6000_REG_BAND_24_HT40_CHANNELS, | ||
576 | EEPROM_REG_BAND_52_HT40_CHANNELS | ||
577 | }, | ||
578 | .verify_signature = iwlcore_eeprom_verify_signature, | ||
579 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | ||
580 | .release_semaphore = iwlcore_eeprom_release_semaphore, | ||
581 | .calib_version = iwlagn_eeprom_calib_version, | ||
582 | .query_addr = iwlagn_eeprom_query_addr, | ||
583 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, | ||
584 | }, | ||
585 | .post_associate = iwl_post_associate, | ||
586 | .isr = iwl_isr_ict, | ||
587 | .config_ap = iwl_config_ap, | ||
588 | .temp_ops = { | ||
589 | .temperature = iwlagn_temperature, | ||
590 | .set_ct_kill = iwl6000_set_ct_threshold, | ||
591 | .set_calib_version = iwl6000_set_calib_version, | ||
592 | }, | ||
593 | .manage_ibss_station = iwlagn_manage_ibss_station, | ||
594 | .update_bcast_station = iwl_update_bcast_station, | ||
595 | .debugfs_ops = { | ||
596 | .rx_stats_read = iwl_ucode_rx_stats_read, | ||
597 | .tx_stats_read = iwl_ucode_tx_stats_read, | ||
598 | .general_stats_read = iwl_ucode_general_stats_read, | ||
599 | .bt_stats_read = iwl_ucode_bt_stats_read, | ||
600 | }, | ||
601 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
602 | .check_plcp_health = iwl_good_plcp_health, | ||
603 | .check_ack_health = iwl_good_ack_health, | ||
604 | .txfifo_flush = iwlagn_txfifo_flush, | ||
605 | .dev_txfifo_flush = iwlagn_dev_txfifo_flush, | ||
606 | .tt_ops = { | ||
607 | .lower_power_detection = iwl_tt_is_low_power_state, | ||
608 | .tt_power_mode = iwl_tt_current_power_mode, | ||
609 | .ct_kill_check = iwl_check_for_ct_kill, | ||
610 | } | ||
611 | }; | ||
612 | |||
454 | static const struct iwl_ops iwl6000_ops = { | 613 | static const struct iwl_ops iwl6000_ops = { |
455 | .lib = &iwl6000_lib, | 614 | .lib = &iwl6000_lib, |
456 | .hcmd = &iwlagn_hcmd, | 615 | .hcmd = &iwlagn_hcmd, |
@@ -467,7 +626,7 @@ static struct iwl_hcmd_ops iwl6000g2b_hcmd = { | |||
467 | }; | 626 | }; |
468 | 627 | ||
469 | static const struct iwl_ops iwl6000g2b_ops = { | 628 | static const struct iwl_ops iwl6000g2b_ops = { |
470 | .lib = &iwl6000_lib, | 629 | .lib = &iwl6000g2b_lib, |
471 | .hcmd = &iwl6000g2b_hcmd, | 630 | .hcmd = &iwl6000g2b_hcmd, |
472 | .utils = &iwlagn_hcmd_utils, | 631 | .utils = &iwlagn_hcmd_utils, |
473 | .led = &iwlagn_led_ops, | 632 | .led = &iwlagn_led_ops, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 69fc7745edaa..67eaeb6822cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -178,6 +178,7 @@ enum { | |||
178 | REPLY_BT_COEX_PRIO_TABLE = 0xcc, | 178 | REPLY_BT_COEX_PRIO_TABLE = 0xcc, |
179 | REPLY_BT_COEX_PROT_ENV = 0xcd, | 179 | REPLY_BT_COEX_PROT_ENV = 0xcd, |
180 | REPLY_BT_COEX_PROFILE_NOTIF = 0xce, | 180 | REPLY_BT_COEX_PROFILE_NOTIF = 0xce, |
181 | REPLY_BT_COEX_SCO = 0xcf, | ||
181 | 182 | ||
182 | REPLY_MAX = 0xff | 183 | REPLY_MAX = 0xff |
183 | }; | 184 | }; |
@@ -2456,6 +2457,12 @@ struct iwl6000g2b_bt_cmd { | |||
2456 | u8 reserved[3]; | 2457 | u8 reserved[3]; |
2457 | }; | 2458 | }; |
2458 | 2459 | ||
2460 | #define IWL6000G2B_BT_SCO_ACTIVE cpu_to_le32(BIT(0)) | ||
2461 | |||
2462 | struct iwl6000g2b_bt_sco_cmd { | ||
2463 | __le32 flags; | ||
2464 | }; | ||
2465 | |||
2459 | /****************************************************************************** | 2466 | /****************************************************************************** |
2460 | * (6) | 2467 | * (6) |
2461 | * Spectrum Management (802.11h) Commands, Responses, Notifications: | 2468 | * Spectrum Management (802.11h) Commands, Responses, Notifications: |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1ad330342ffc..5d327b44533b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1362,6 +1362,10 @@ struct iwl_priv { | |||
1362 | #endif | 1362 | #endif |
1363 | }; | 1363 | }; |
1364 | 1364 | ||
1365 | u8 bt_traffic_load; | ||
1366 | bool bt_sco_active; | ||
1367 | struct work_struct bt_traffic_change_work; | ||
1368 | |||
1365 | struct iwl_hw_params hw_params; | 1369 | struct iwl_hw_params hw_params; |
1366 | 1370 | ||
1367 | u32 inta_mask; | 1371 | u32 inta_mask; |