diff options
148 files changed, 3919 insertions, 3413 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index e45fa5c0aa20..e824c1e74202 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -508,18 +508,6 @@ Who: Kees Cook <keescook@chromium.org> | |||
508 | 508 | ||
509 | ---------------------------- | 509 | ---------------------------- |
510 | 510 | ||
511 | What: Removing the pn544 raw driver. | ||
512 | When: 3.6 | ||
513 | Why: With the introduction of the NFC HCI and SHDL kernel layers, pn544.c | ||
514 | is being replaced by pn544_hci.c which is accessible through the netlink | ||
515 | and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to | ||
516 | work properly with the latest Android stacks. | ||
517 | Having 2 drivers for the same hardware is confusing and as such we | ||
518 | should only keep the one following the kernel NFC APIs. | ||
519 | Who: Samuel Ortiz <sameo@linux.intel.com> | ||
520 | |||
521 | ---------------------------- | ||
522 | |||
523 | What: setitimer accepts user NULL pointer (value) | 511 | What: setitimer accepts user NULL pointer (value) |
524 | When: 3.6 | 512 | When: 3.6 |
525 | Why: setitimer is not returning -EFAULT if user pointer is NULL. This | 513 | Why: setitimer is not returning -EFAULT if user pointer is NULL. This |
diff --git a/MAINTAINERS b/MAINTAINERS index 9a6c4da3b2ff..64458f0ee80e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4799,6 +4799,7 @@ M: Lauro Ramos Venancio <lauro.venancio@openbossa.org> | |||
4799 | M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org> | 4799 | M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org> |
4800 | M: Samuel Ortiz <sameo@linux.intel.com> | 4800 | M: Samuel Ortiz <sameo@linux.intel.com> |
4801 | L: linux-wireless@vger.kernel.org | 4801 | L: linux-wireless@vger.kernel.org |
4802 | L: linux-nfc@lists.01.org (moderated for non-subscribers) | ||
4802 | S: Maintained | 4803 | S: Maintained |
4803 | F: net/nfc/ | 4804 | F: net/nfc/ |
4804 | F: include/linux/nfc.h | 4805 | F: include/linux/nfc.h |
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index f7b0af7100cd..b6b4b5ebd4c2 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c | |||
@@ -273,6 +273,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { | |||
273 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, | 273 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, |
274 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, | 274 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, |
275 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, | 275 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, |
276 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) }, | ||
276 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, | 277 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, |
277 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, | 278 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, |
278 | { 0, }, | 279 | { 0, }, |
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 9ea4627dc0c2..0d546b64be34 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c | |||
@@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) | |||
507 | /* for these chips OTP is always available */ | 507 | /* for these chips OTP is always available */ |
508 | present = true; | 508 | present = true; |
509 | break; | 509 | break; |
510 | case BCMA_CHIP_ID_BCM43227: | ||
510 | case BCMA_CHIP_ID_BCM43228: | 511 | case BCMA_CHIP_ID_BCM43228: |
512 | case BCMA_CHIP_ID_BCM43428: | ||
511 | present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT; | 513 | present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT; |
512 | break; | 514 | break; |
513 | default: | 515 | default: |
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 0c0838d9b56c..0d26851d6e49 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c | |||
@@ -681,7 +681,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb) | |||
681 | case HCI_SCODATA_PKT: | 681 | case HCI_SCODATA_PKT: |
682 | hdev->stat.sco_tx++; | 682 | hdev->stat.sco_tx++; |
683 | break; | 683 | break; |
684 | }; | 684 | } |
685 | 685 | ||
686 | /* Prepend skb with frame type */ | 686 | /* Prepend skb with frame type */ |
687 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); | 687 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); |
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 03b3acba6143..3f4bfc814dc7 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c | |||
@@ -600,8 +600,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) | |||
600 | exit: | 600 | exit: |
601 | if (ret) { | 601 | if (ret) { |
602 | hdev->stat.err_rx++; | 602 | hdev->stat.err_rx++; |
603 | if (skb) | 603 | kfree_skb(skb); |
604 | kfree_skb(skb); | ||
605 | } | 604 | } |
606 | 605 | ||
607 | return ret; | 606 | return ret; |
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 2f510a87b28f..35a553a90616 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c | |||
@@ -446,7 +446,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb) | |||
446 | case HCI_SCODATA_PKT: | 446 | case HCI_SCODATA_PKT: |
447 | hdev->stat.sco_tx++; | 447 | hdev->stat.sco_tx++; |
448 | break; | 448 | break; |
449 | }; | 449 | } |
450 | 450 | ||
451 | /* Prepend skb with frame type */ | 451 | /* Prepend skb with frame type */ |
452 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); | 452 | memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); |
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e5921d681ddb..debda27df9b0 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -96,11 +96,12 @@ static struct usb_device_id btusb_table[] = { | |||
96 | { USB_DEVICE(0x0c10, 0x0000) }, | 96 | { USB_DEVICE(0x0c10, 0x0000) }, |
97 | 97 | ||
98 | /* Broadcom BCM20702A0 */ | 98 | /* Broadcom BCM20702A0 */ |
99 | { USB_DEVICE(0x04ca, 0x2003) }, | ||
99 | { USB_DEVICE(0x0489, 0xe042) }, | 100 | { USB_DEVICE(0x0489, 0xe042) }, |
100 | { USB_DEVICE(0x413c, 0x8197) }, | 101 | { USB_DEVICE(0x413c, 0x8197) }, |
101 | 102 | ||
102 | /* Foxconn - Hon Hai */ | 103 | /* Foxconn - Hon Hai */ |
103 | { USB_DEVICE(0x0489, 0xe033) }, | 104 | { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, |
104 | 105 | ||
105 | /*Broadcom devices with vendor specific id */ | 106 | /*Broadcom devices with vendor specific id */ |
106 | { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, | 107 | { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, |
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 4ad7b35cfc0e..60abf596f60e 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c | |||
@@ -358,21 +358,7 @@ static struct platform_driver btwilink_driver = { | |||
358 | }, | 358 | }, |
359 | }; | 359 | }; |
360 | 360 | ||
361 | /* ------- Module Init/Exit interfaces ------ */ | 361 | module_platform_driver(btwilink_driver); |
362 | static int __init btwilink_init(void) | ||
363 | { | ||
364 | BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION); | ||
365 | |||
366 | return platform_driver_register(&btwilink_driver); | ||
367 | } | ||
368 | |||
369 | static void __exit btwilink_exit(void) | ||
370 | { | ||
371 | platform_driver_unregister(&btwilink_driver); | ||
372 | } | ||
373 | |||
374 | module_init(btwilink_init); | ||
375 | module_exit(btwilink_exit); | ||
376 | 362 | ||
377 | /* ------ Module Info ------ */ | 363 | /* ------ Module Info ------ */ |
378 | 364 | ||
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 74e0966b3ead..c8abce3d2d9c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -531,7 +531,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, | |||
531 | default: | 531 | default: |
532 | err = n_tty_ioctl_helper(tty, file, cmd, arg); | 532 | err = n_tty_ioctl_helper(tty, file, cmd, arg); |
533 | break; | 533 | break; |
534 | }; | 534 | } |
535 | 535 | ||
536 | return err; | 536 | return err; |
537 | } | 537 | } |
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index ff6d589c34a5..cfc767938589 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c | |||
@@ -481,7 +481,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count) | |||
481 | hu->hdev->stat.err_rx++; | 481 | hu->hdev->stat.err_rx++; |
482 | ptr++; count--; | 482 | ptr++; count--; |
483 | continue; | 483 | continue; |
484 | }; | 484 | } |
485 | 485 | ||
486 | ptr++; count--; | 486 | ptr++; count--; |
487 | 487 | ||
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 3f72595a6017..d8b7aed6e4a9 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c | |||
@@ -156,7 +156,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, | |||
156 | case HCI_SCODATA_PKT: | 156 | case HCI_SCODATA_PKT: |
157 | data->hdev->stat.sco_tx++; | 157 | data->hdev->stat.sco_tx++; |
158 | break; | 158 | break; |
159 | }; | 159 | } |
160 | 160 | ||
161 | return total; | 161 | return total; |
162 | } | 162 | } |
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 6169fbd23ed1..4521342c62cc 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -159,6 +159,7 @@ struct ath_common { | |||
159 | 159 | ||
160 | bool btcoex_enabled; | 160 | bool btcoex_enabled; |
161 | bool disable_ani; | 161 | bool disable_ani; |
162 | bool antenna_diversity; | ||
162 | }; | 163 | }; |
163 | 164 | ||
164 | struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, | 165 | struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a0a202de1109..9fd6d9a9942e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -2446,6 +2446,7 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) | |||
2446 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 2446 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
2447 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 2447 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
2448 | IEEE80211_HW_SIGNAL_DBM | | 2448 | IEEE80211_HW_SIGNAL_DBM | |
2449 | IEEE80211_HW_MFP_CAPABLE | | ||
2449 | IEEE80211_HW_REPORTS_TX_ACK_STATUS; | 2450 | IEEE80211_HW_REPORTS_TX_ACK_STATUS; |
2450 | 2451 | ||
2451 | hw->wiphy->interface_modes = | 2452 | hw->wiphy->interface_modes = |
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index df61a09adb6d..7a28538e6e05 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -489,6 +489,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
489 | if (ath5k_modparam_nohwcrypt) | 489 | if (ath5k_modparam_nohwcrypt) |
490 | return -EOPNOTSUPP; | 490 | return -EOPNOTSUPP; |
491 | 491 | ||
492 | if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) | ||
493 | return -EOPNOTSUPP; | ||
494 | |||
492 | if (vif->type == NL80211_IFTYPE_ADHOC && | 495 | if (vif->type == NL80211_IFTYPE_ADHOC && |
493 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || | 496 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || |
494 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && | 497 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && |
@@ -523,7 +526,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
523 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) | 526 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) |
524 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 527 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
525 | if (key->cipher == WLAN_CIPHER_SUITE_CCMP) | 528 | if (key->cipher == WLAN_CIPHER_SUITE_CCMP) |
526 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | 529 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
527 | ret = 0; | 530 | ret = 0; |
528 | } | 531 | } |
529 | break; | 532 | break; |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 01c90ed58453..ab363f34b4df 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -1975,11 +1975,13 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, | |||
1975 | spur_delta_phase = (spur_offset << 18) / 25; | 1975 | spur_delta_phase = (spur_offset << 18) / 25; |
1976 | spur_freq_sigma_delta = (spur_delta_phase >> 10); | 1976 | spur_freq_sigma_delta = (spur_delta_phase >> 10); |
1977 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2; | 1977 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2; |
1978 | break; | ||
1978 | case AR5K_BWMODE_5MHZ: | 1979 | case AR5K_BWMODE_5MHZ: |
1979 | /* Both sample_freq and chip_freq are 10MHz (?) */ | 1980 | /* Both sample_freq and chip_freq are 10MHz (?) */ |
1980 | spur_delta_phase = (spur_offset << 19) / 25; | 1981 | spur_delta_phase = (spur_offset << 19) / 25; |
1981 | spur_freq_sigma_delta = (spur_delta_phase >> 10); | 1982 | spur_freq_sigma_delta = (spur_delta_phase >> 10); |
1982 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; | 1983 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; |
1984 | break; | ||
1983 | default: | 1985 | default: |
1984 | if (channel->band == IEEE80211_BAND_5GHZ) { | 1986 | if (channel->band == IEEE80211_BAND_5GHZ) { |
1985 | /* Both sample_freq and chip_freq are 40MHz */ | 1987 | /* Both sample_freq and chip_freq are 40MHz */ |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 86aeef4b9d7e..7089f8160ad5 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -1488,7 +1488,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | |||
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, | 1490 | static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, |
1491 | char *name, | 1491 | const char *name, |
1492 | enum nl80211_iftype type, | 1492 | enum nl80211_iftype type, |
1493 | u32 *flags, | 1493 | u32 *flags, |
1494 | struct vif_params *params) | 1494 | struct vif_params *params) |
@@ -3477,7 +3477,7 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) | |||
3477 | ar->num_vif--; | 3477 | ar->num_vif--; |
3478 | } | 3478 | } |
3479 | 3479 | ||
3480 | struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, | 3480 | struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, |
3481 | enum nl80211_iftype type, | 3481 | enum nl80211_iftype type, |
3482 | u8 fw_vif_idx, u8 nw_type) | 3482 | u8 fw_vif_idx, u8 nw_type) |
3483 | { | 3483 | { |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 56b1ebe79812..780f77775a91 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -25,7 +25,7 @@ enum ath6kl_cfg_suspend_mode { | |||
25 | ATH6KL_CFG_SUSPEND_SCHED_SCAN, | 25 | ATH6KL_CFG_SUSPEND_SCHED_SCAN, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, | 28 | struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, |
29 | enum nl80211_iftype type, | 29 | enum nl80211_iftype type, |
30 | u8 fw_vif_idx, u8 nw_type); | 30 | u8 fw_vif_idx, u8 nw_type); |
31 | void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, | 31 | void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, |
diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index bbcfeb3b2a60..664844c5d3d5 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c | |||
@@ -311,6 +311,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
311 | struct ath_ant_comb *antcomb, | 311 | struct ath_ant_comb *antcomb, |
312 | int alt_ratio) | 312 | int alt_ratio) |
313 | { | 313 | { |
314 | ant_conf->main_gaintb = 0; | ||
315 | ant_conf->alt_gaintb = 0; | ||
316 | |||
314 | if (ant_conf->div_group == 0) { | 317 | if (ant_conf->div_group == 0) { |
315 | /* Adjust the fast_div_bias based on main and alt lna conf */ | 318 | /* Adjust the fast_div_bias based on main and alt lna conf */ |
316 | switch ((ant_conf->main_lna_conf << 4) | | 319 | switch ((ant_conf->main_lna_conf << 4) | |
@@ -360,18 +363,12 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
360 | ant_conf->alt_lna_conf) { | 363 | ant_conf->alt_lna_conf) { |
361 | case 0x01: /* A-B LNA2 */ | 364 | case 0x01: /* A-B LNA2 */ |
362 | ant_conf->fast_div_bias = 0x1; | 365 | ant_conf->fast_div_bias = 0x1; |
363 | ant_conf->main_gaintb = 0; | ||
364 | ant_conf->alt_gaintb = 0; | ||
365 | break; | 366 | break; |
366 | case 0x02: /* A-B LNA1 */ | 367 | case 0x02: /* A-B LNA1 */ |
367 | ant_conf->fast_div_bias = 0x1; | 368 | ant_conf->fast_div_bias = 0x1; |
368 | ant_conf->main_gaintb = 0; | ||
369 | ant_conf->alt_gaintb = 0; | ||
370 | break; | 369 | break; |
371 | case 0x03: /* A-B A+B */ | 370 | case 0x03: /* A-B A+B */ |
372 | ant_conf->fast_div_bias = 0x1; | 371 | ant_conf->fast_div_bias = 0x1; |
373 | ant_conf->main_gaintb = 0; | ||
374 | ant_conf->alt_gaintb = 0; | ||
375 | break; | 372 | break; |
376 | case 0x10: /* LNA2 A-B */ | 373 | case 0x10: /* LNA2 A-B */ |
377 | if (!(antcomb->scan) && | 374 | if (!(antcomb->scan) && |
@@ -379,13 +376,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
379 | ant_conf->fast_div_bias = 0x3f; | 376 | ant_conf->fast_div_bias = 0x3f; |
380 | else | 377 | else |
381 | ant_conf->fast_div_bias = 0x1; | 378 | ant_conf->fast_div_bias = 0x1; |
382 | ant_conf->main_gaintb = 0; | ||
383 | ant_conf->alt_gaintb = 0; | ||
384 | break; | 379 | break; |
385 | case 0x12: /* LNA2 LNA1 */ | 380 | case 0x12: /* LNA2 LNA1 */ |
386 | ant_conf->fast_div_bias = 0x1; | 381 | ant_conf->fast_div_bias = 0x1; |
387 | ant_conf->main_gaintb = 0; | ||
388 | ant_conf->alt_gaintb = 0; | ||
389 | break; | 382 | break; |
390 | case 0x13: /* LNA2 A+B */ | 383 | case 0x13: /* LNA2 A+B */ |
391 | if (!(antcomb->scan) && | 384 | if (!(antcomb->scan) && |
@@ -393,8 +386,6 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
393 | ant_conf->fast_div_bias = 0x3f; | 386 | ant_conf->fast_div_bias = 0x3f; |
394 | else | 387 | else |
395 | ant_conf->fast_div_bias = 0x1; | 388 | ant_conf->fast_div_bias = 0x1; |
396 | ant_conf->main_gaintb = 0; | ||
397 | ant_conf->alt_gaintb = 0; | ||
398 | break; | 389 | break; |
399 | case 0x20: /* LNA1 A-B */ | 390 | case 0x20: /* LNA1 A-B */ |
400 | if (!(antcomb->scan) && | 391 | if (!(antcomb->scan) && |
@@ -402,13 +393,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
402 | ant_conf->fast_div_bias = 0x3f; | 393 | ant_conf->fast_div_bias = 0x3f; |
403 | else | 394 | else |
404 | ant_conf->fast_div_bias = 0x1; | 395 | ant_conf->fast_div_bias = 0x1; |
405 | ant_conf->main_gaintb = 0; | ||
406 | ant_conf->alt_gaintb = 0; | ||
407 | break; | 396 | break; |
408 | case 0x21: /* LNA1 LNA2 */ | 397 | case 0x21: /* LNA1 LNA2 */ |
409 | ant_conf->fast_div_bias = 0x1; | 398 | ant_conf->fast_div_bias = 0x1; |
410 | ant_conf->main_gaintb = 0; | ||
411 | ant_conf->alt_gaintb = 0; | ||
412 | break; | 399 | break; |
413 | case 0x23: /* LNA1 A+B */ | 400 | case 0x23: /* LNA1 A+B */ |
414 | if (!(antcomb->scan) && | 401 | if (!(antcomb->scan) && |
@@ -416,23 +403,15 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
416 | ant_conf->fast_div_bias = 0x3f; | 403 | ant_conf->fast_div_bias = 0x3f; |
417 | else | 404 | else |
418 | ant_conf->fast_div_bias = 0x1; | 405 | ant_conf->fast_div_bias = 0x1; |
419 | ant_conf->main_gaintb = 0; | ||
420 | ant_conf->alt_gaintb = 0; | ||
421 | break; | 406 | break; |
422 | case 0x30: /* A+B A-B */ | 407 | case 0x30: /* A+B A-B */ |
423 | ant_conf->fast_div_bias = 0x1; | 408 | ant_conf->fast_div_bias = 0x1; |
424 | ant_conf->main_gaintb = 0; | ||
425 | ant_conf->alt_gaintb = 0; | ||
426 | break; | 409 | break; |
427 | case 0x31: /* A+B LNA2 */ | 410 | case 0x31: /* A+B LNA2 */ |
428 | ant_conf->fast_div_bias = 0x1; | 411 | ant_conf->fast_div_bias = 0x1; |
429 | ant_conf->main_gaintb = 0; | ||
430 | ant_conf->alt_gaintb = 0; | ||
431 | break; | 412 | break; |
432 | case 0x32: /* A+B LNA1 */ | 413 | case 0x32: /* A+B LNA1 */ |
433 | ant_conf->fast_div_bias = 0x1; | 414 | ant_conf->fast_div_bias = 0x1; |
434 | ant_conf->main_gaintb = 0; | ||
435 | ant_conf->alt_gaintb = 0; | ||
436 | break; | 415 | break; |
437 | default: | 416 | default: |
438 | break; | 417 | break; |
@@ -443,18 +422,12 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
443 | ant_conf->alt_lna_conf) { | 422 | ant_conf->alt_lna_conf) { |
444 | case 0x01: /* A-B LNA2 */ | 423 | case 0x01: /* A-B LNA2 */ |
445 | ant_conf->fast_div_bias = 0x1; | 424 | ant_conf->fast_div_bias = 0x1; |
446 | ant_conf->main_gaintb = 0; | ||
447 | ant_conf->alt_gaintb = 0; | ||
448 | break; | 425 | break; |
449 | case 0x02: /* A-B LNA1 */ | 426 | case 0x02: /* A-B LNA1 */ |
450 | ant_conf->fast_div_bias = 0x1; | 427 | ant_conf->fast_div_bias = 0x1; |
451 | ant_conf->main_gaintb = 0; | ||
452 | ant_conf->alt_gaintb = 0; | ||
453 | break; | 428 | break; |
454 | case 0x03: /* A-B A+B */ | 429 | case 0x03: /* A-B A+B */ |
455 | ant_conf->fast_div_bias = 0x1; | 430 | ant_conf->fast_div_bias = 0x1; |
456 | ant_conf->main_gaintb = 0; | ||
457 | ant_conf->alt_gaintb = 0; | ||
458 | break; | 431 | break; |
459 | case 0x10: /* LNA2 A-B */ | 432 | case 0x10: /* LNA2 A-B */ |
460 | if (!(antcomb->scan) && | 433 | if (!(antcomb->scan) && |
@@ -462,13 +435,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
462 | ant_conf->fast_div_bias = 0x1; | 435 | ant_conf->fast_div_bias = 0x1; |
463 | else | 436 | else |
464 | ant_conf->fast_div_bias = 0x2; | 437 | ant_conf->fast_div_bias = 0x2; |
465 | ant_conf->main_gaintb = 0; | ||
466 | ant_conf->alt_gaintb = 0; | ||
467 | break; | 438 | break; |
468 | case 0x12: /* LNA2 LNA1 */ | 439 | case 0x12: /* LNA2 LNA1 */ |
469 | ant_conf->fast_div_bias = 0x1; | 440 | ant_conf->fast_div_bias = 0x1; |
470 | ant_conf->main_gaintb = 0; | ||
471 | ant_conf->alt_gaintb = 0; | ||
472 | break; | 441 | break; |
473 | case 0x13: /* LNA2 A+B */ | 442 | case 0x13: /* LNA2 A+B */ |
474 | if (!(antcomb->scan) && | 443 | if (!(antcomb->scan) && |
@@ -476,8 +445,6 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
476 | ant_conf->fast_div_bias = 0x1; | 445 | ant_conf->fast_div_bias = 0x1; |
477 | else | 446 | else |
478 | ant_conf->fast_div_bias = 0x2; | 447 | ant_conf->fast_div_bias = 0x2; |
479 | ant_conf->main_gaintb = 0; | ||
480 | ant_conf->alt_gaintb = 0; | ||
481 | break; | 448 | break; |
482 | case 0x20: /* LNA1 A-B */ | 449 | case 0x20: /* LNA1 A-B */ |
483 | if (!(antcomb->scan) && | 450 | if (!(antcomb->scan) && |
@@ -485,13 +452,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
485 | ant_conf->fast_div_bias = 0x1; | 452 | ant_conf->fast_div_bias = 0x1; |
486 | else | 453 | else |
487 | ant_conf->fast_div_bias = 0x2; | 454 | ant_conf->fast_div_bias = 0x2; |
488 | ant_conf->main_gaintb = 0; | ||
489 | ant_conf->alt_gaintb = 0; | ||
490 | break; | 455 | break; |
491 | case 0x21: /* LNA1 LNA2 */ | 456 | case 0x21: /* LNA1 LNA2 */ |
492 | ant_conf->fast_div_bias = 0x1; | 457 | ant_conf->fast_div_bias = 0x1; |
493 | ant_conf->main_gaintb = 0; | ||
494 | ant_conf->alt_gaintb = 0; | ||
495 | break; | 458 | break; |
496 | case 0x23: /* LNA1 A+B */ | 459 | case 0x23: /* LNA1 A+B */ |
497 | if (!(antcomb->scan) && | 460 | if (!(antcomb->scan) && |
@@ -499,23 +462,77 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, | |||
499 | ant_conf->fast_div_bias = 0x1; | 462 | ant_conf->fast_div_bias = 0x1; |
500 | else | 463 | else |
501 | ant_conf->fast_div_bias = 0x2; | 464 | ant_conf->fast_div_bias = 0x2; |
502 | ant_conf->main_gaintb = 0; | ||
503 | ant_conf->alt_gaintb = 0; | ||
504 | break; | 465 | break; |
505 | case 0x30: /* A+B A-B */ | 466 | case 0x30: /* A+B A-B */ |
506 | ant_conf->fast_div_bias = 0x1; | 467 | ant_conf->fast_div_bias = 0x1; |
507 | ant_conf->main_gaintb = 0; | ||
508 | ant_conf->alt_gaintb = 0; | ||
509 | break; | 468 | break; |
510 | case 0x31: /* A+B LNA2 */ | 469 | case 0x31: /* A+B LNA2 */ |
511 | ant_conf->fast_div_bias = 0x1; | 470 | ant_conf->fast_div_bias = 0x1; |
512 | ant_conf->main_gaintb = 0; | ||
513 | ant_conf->alt_gaintb = 0; | ||
514 | break; | 471 | break; |
515 | case 0x32: /* A+B LNA1 */ | 472 | case 0x32: /* A+B LNA1 */ |
516 | ant_conf->fast_div_bias = 0x1; | 473 | ant_conf->fast_div_bias = 0x1; |
517 | ant_conf->main_gaintb = 0; | 474 | break; |
518 | ant_conf->alt_gaintb = 0; | 475 | default: |
476 | break; | ||
477 | } | ||
478 | } else if (ant_conf->div_group == 3) { | ||
479 | switch ((ant_conf->main_lna_conf << 4) | | ||
480 | ant_conf->alt_lna_conf) { | ||
481 | case 0x01: /* A-B LNA2 */ | ||
482 | ant_conf->fast_div_bias = 0x1; | ||
483 | break; | ||
484 | case 0x02: /* A-B LNA1 */ | ||
485 | ant_conf->fast_div_bias = 0x39; | ||
486 | break; | ||
487 | case 0x03: /* A-B A+B */ | ||
488 | ant_conf->fast_div_bias = 0x1; | ||
489 | break; | ||
490 | case 0x10: /* LNA2 A-B */ | ||
491 | if ((antcomb->scan == 0) && | ||
492 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { | ||
493 | ant_conf->fast_div_bias = 0x3f; | ||
494 | } else { | ||
495 | ant_conf->fast_div_bias = 0x1; | ||
496 | } | ||
497 | break; | ||
498 | case 0x12: /* LNA2 LNA1 */ | ||
499 | ant_conf->fast_div_bias = 0x39; | ||
500 | break; | ||
501 | case 0x13: /* LNA2 A+B */ | ||
502 | if ((antcomb->scan == 0) && | ||
503 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { | ||
504 | ant_conf->fast_div_bias = 0x3f; | ||
505 | } else { | ||
506 | ant_conf->fast_div_bias = 0x1; | ||
507 | } | ||
508 | break; | ||
509 | case 0x20: /* LNA1 A-B */ | ||
510 | if ((antcomb->scan == 0) && | ||
511 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { | ||
512 | ant_conf->fast_div_bias = 0x3f; | ||
513 | } else { | ||
514 | ant_conf->fast_div_bias = 0x4; | ||
515 | } | ||
516 | break; | ||
517 | case 0x21: /* LNA1 LNA2 */ | ||
518 | ant_conf->fast_div_bias = 0x6; | ||
519 | break; | ||
520 | case 0x23: /* LNA1 A+B */ | ||
521 | if ((antcomb->scan == 0) && | ||
522 | (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { | ||
523 | ant_conf->fast_div_bias = 0x3f; | ||
524 | } else { | ||
525 | ant_conf->fast_div_bias = 0x6; | ||
526 | } | ||
527 | break; | ||
528 | case 0x30: /* A+B A-B */ | ||
529 | ant_conf->fast_div_bias = 0x1; | ||
530 | break; | ||
531 | case 0x31: /* A+B LNA2 */ | ||
532 | ant_conf->fast_div_bias = 0x6; | ||
533 | break; | ||
534 | case 0x32: /* A+B LNA1 */ | ||
535 | ant_conf->fast_div_bias = 0x1; | ||
519 | break; | 536 | break; |
520 | default: | 537 | default: |
521 | break; | 538 | break; |
@@ -759,6 +776,7 @@ div_comb_done: | |||
759 | void ath_ant_comb_update(struct ath_softc *sc) | 776 | void ath_ant_comb_update(struct ath_softc *sc) |
760 | { | 777 | { |
761 | struct ath_hw *ah = sc->sc_ah; | 778 | struct ath_hw *ah = sc->sc_ah; |
779 | struct ath_common *common = ath9k_hw_common(ah); | ||
762 | struct ath_hw_antcomb_conf div_ant_conf; | 780 | struct ath_hw_antcomb_conf div_ant_conf; |
763 | u8 lna_conf; | 781 | u8 lna_conf; |
764 | 782 | ||
@@ -773,4 +791,7 @@ void ath_ant_comb_update(struct ath_softc *sc) | |||
773 | div_ant_conf.alt_lna_conf = lna_conf; | 791 | div_ant_conf.alt_lna_conf = lna_conf; |
774 | 792 | ||
775 | ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); | 793 | ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); |
794 | |||
795 | if (common->antenna_diversity) | ||
796 | ath9k_hw_antctrl_shared_chain_lnadiv(ah, true); | ||
776 | } | 797 | } |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 884f9f0014ae..5bbe5057ba18 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
@@ -3566,9 +3566,9 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain, | |||
3566 | 3566 | ||
3567 | static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) | 3567 | static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) |
3568 | { | 3568 | { |
3569 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
3569 | int chain; | 3570 | int chain; |
3570 | u32 regval; | 3571 | u32 regval; |
3571 | u32 ant_div_ctl1; | ||
3572 | static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { | 3572 | static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { |
3573 | AR_PHY_SWITCH_CHAIN_0, | 3573 | AR_PHY_SWITCH_CHAIN_0, |
3574 | AR_PHY_SWITCH_CHAIN_1, | 3574 | AR_PHY_SWITCH_CHAIN_1, |
@@ -3633,6 +3633,16 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) | |||
3633 | /* enable_lnadiv */ | 3633 | /* enable_lnadiv */ |
3634 | regval &= (~AR_PHY_ANT_DIV_LNADIV); | 3634 | regval &= (~AR_PHY_ANT_DIV_LNADIV); |
3635 | regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; | 3635 | regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; |
3636 | |||
3637 | if (AR_SREV_9565(ah)) { | ||
3638 | if (ah->shared_chain_lnadiv) { | ||
3639 | regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); | ||
3640 | } else { | ||
3641 | regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S); | ||
3642 | regval &= ~(1 << AR_PHY_ANT_SW_RX_PROT_S); | ||
3643 | } | ||
3644 | } | ||
3645 | |||
3636 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); | 3646 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); |
3637 | 3647 | ||
3638 | /*enable fast_div */ | 3648 | /*enable fast_div */ |
@@ -3640,9 +3650,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) | |||
3640 | regval &= (~AR_FAST_DIV_ENABLE); | 3650 | regval &= (~AR_FAST_DIV_ENABLE); |
3641 | regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; | 3651 | regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; |
3642 | REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); | 3652 | REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); |
3643 | ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); | 3653 | |
3644 | /* check whether antenna diversity is enabled */ | 3654 | if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { |
3645 | if ((ant_div_ctl1 >> 0x6) == 0x3) { | ||
3646 | regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); | 3655 | regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); |
3647 | /* | 3656 | /* |
3648 | * clear bits 25-30 main_lnaconf, alt_lnaconf, | 3657 | * clear bits 25-30 main_lnaconf, alt_lnaconf, |
@@ -3659,10 +3668,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) | |||
3659 | AR_PHY_ANT_DIV_ALT_LNACONF_S); | 3668 | AR_PHY_ANT_DIV_ALT_LNACONF_S); |
3660 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); | 3669 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); |
3661 | } | 3670 | } |
3662 | |||
3663 | |||
3664 | } | 3671 | } |
3665 | |||
3666 | } | 3672 | } |
3667 | 3673 | ||
3668 | static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) | 3674 | static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index b2e39e8a21b5..8dbb60b53f1a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c | |||
@@ -1027,6 +1027,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) | |||
1027 | 1027 | ||
1028 | if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) | 1028 | if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) |
1029 | ar9003_mci_osla_setup(ah, true); | 1029 | ar9003_mci_osla_setup(ah, true); |
1030 | REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); | ||
1030 | } else { | 1031 | } else { |
1031 | ar9003_mci_send_lna_take(ah, true); | 1032 | ar9003_mci_send_lna_take(ah, true); |
1032 | udelay(5); | 1033 | udelay(5); |
@@ -1235,6 +1236,10 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) | |||
1235 | case MCI_STATE_NEED_FTP_STOMP: | 1236 | case MCI_STATE_NEED_FTP_STOMP: |
1236 | value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); | 1237 | value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); |
1237 | break; | 1238 | break; |
1239 | case MCI_STATE_NEED_FLUSH_BT_INFO: | ||
1240 | value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; | ||
1241 | mci->need_flush_btinfo = false; | ||
1242 | break; | ||
1238 | default: | 1243 | default: |
1239 | break; | 1244 | break; |
1240 | } | 1245 | } |
@@ -1284,7 +1289,7 @@ void ar9003_mci_set_power_awake(struct ath_hw *ah) | |||
1284 | } | 1289 | } |
1285 | REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); | 1290 | REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); |
1286 | lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; | 1291 | lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; |
1287 | bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP; | 1292 | bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP); |
1288 | 1293 | ||
1289 | REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); | 1294 | REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); |
1290 | REG_WRITE(ah, AR_DIAG_SW, diag_sw); | 1295 | REG_WRITE(ah, AR_DIAG_SW, diag_sw); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index f3bef8d69edd..30acf2869aa4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h | |||
@@ -200,6 +200,7 @@ enum mci_state_type { | |||
200 | MCI_STATE_RECOVER_RX, | 200 | MCI_STATE_RECOVER_RX, |
201 | MCI_STATE_NEED_FTP_STOMP, | 201 | MCI_STATE_NEED_FTP_STOMP, |
202 | MCI_STATE_DEBUG, | 202 | MCI_STATE_DEBUG, |
203 | MCI_STATE_NEED_FLUSH_BT_INFO, | ||
203 | MCI_STATE_MAX | 204 | MCI_STATE_MAX |
204 | }; | 205 | }; |
205 | 206 | ||
@@ -211,7 +212,8 @@ enum mci_gpm_coex_opcode { | |||
211 | MCI_GPM_COEX_WLAN_CHANNELS, | 212 | MCI_GPM_COEX_WLAN_CHANNELS, |
212 | MCI_GPM_COEX_BT_PROFILE_INFO, | 213 | MCI_GPM_COEX_BT_PROFILE_INFO, |
213 | MCI_GPM_COEX_BT_STATUS_UPDATE, | 214 | MCI_GPM_COEX_BT_STATUS_UPDATE, |
214 | MCI_GPM_COEX_BT_UPDATE_FLAGS | 215 | MCI_GPM_COEX_BT_UPDATE_FLAGS, |
216 | MCI_GPM_COEX_NOOP, | ||
215 | }; | 217 | }; |
216 | 218 | ||
217 | #define MCI_GPM_NOMORE 0 | 219 | #define MCI_GPM_NOMORE 0 |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 0d800c62e227..fc67844a1430 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
@@ -605,9 +605,6 @@ static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) | |||
605 | 605 | ||
606 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) | 606 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) |
607 | REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); | 607 | REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); |
608 | else if (AR_SREV_9462(ah)) | ||
609 | /* xxx only when MCI support is enabled */ | ||
610 | REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); | ||
611 | else | 608 | else |
612 | REG_WRITE(ah, AR_SELFGEN_MASK, tx); | 609 | REG_WRITE(ah, AR_SELFGEN_MASK, tx); |
613 | 610 | ||
@@ -1294,6 +1291,9 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah, | |||
1294 | } else if (AR_SREV_9485(ah)) { | 1291 | } else if (AR_SREV_9485(ah)) { |
1295 | antconf->lna1_lna2_delta = -9; | 1292 | antconf->lna1_lna2_delta = -9; |
1296 | antconf->div_group = 2; | 1293 | antconf->div_group = 2; |
1294 | } else if (AR_SREV_9565(ah)) { | ||
1295 | antconf->lna1_lna2_delta = -3; | ||
1296 | antconf->div_group = 3; | ||
1297 | } else { | 1297 | } else { |
1298 | antconf->lna1_lna2_delta = -3; | 1298 | antconf->lna1_lna2_delta = -3; |
1299 | antconf->div_group = 0; | 1299 | antconf->div_group = 0; |
@@ -1325,6 +1325,65 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, | |||
1325 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); | 1325 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); |
1326 | } | 1326 | } |
1327 | 1327 | ||
1328 | static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, | ||
1329 | bool enable) | ||
1330 | { | ||
1331 | u8 ant_div_ctl1; | ||
1332 | u32 regval; | ||
1333 | |||
1334 | if (!AR_SREV_9565(ah)) | ||
1335 | return; | ||
1336 | |||
1337 | ah->shared_chain_lnadiv = enable; | ||
1338 | ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); | ||
1339 | |||
1340 | regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); | ||
1341 | regval &= (~AR_ANT_DIV_CTRL_ALL); | ||
1342 | regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; | ||
1343 | regval &= ~AR_PHY_ANT_DIV_LNADIV; | ||
1344 | regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; | ||
1345 | |||
1346 | if (enable) | ||
1347 | regval |= AR_ANT_DIV_ENABLE; | ||
1348 | |||
1349 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); | ||
1350 | |||
1351 | regval = REG_READ(ah, AR_PHY_CCK_DETECT); | ||
1352 | regval &= ~AR_FAST_DIV_ENABLE; | ||
1353 | regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; | ||
1354 | |||
1355 | if (enable) | ||
1356 | regval |= AR_FAST_DIV_ENABLE; | ||
1357 | |||
1358 | REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); | ||
1359 | |||
1360 | if (enable) { | ||
1361 | REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, | ||
1362 | (1 << AR_PHY_ANT_SW_RX_PROT_S)); | ||
1363 | if (IS_CHAN_2GHZ(ah->curchan)) | ||
1364 | REG_SET_BIT(ah, AR_PHY_RESTART, | ||
1365 | AR_PHY_RESTART_ENABLE_DIV_M2FLAG); | ||
1366 | REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, | ||
1367 | AR_BTCOEX_WL_LNADIV_FORCE_ON); | ||
1368 | } else { | ||
1369 | REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE); | ||
1370 | REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, | ||
1371 | (1 << AR_PHY_ANT_SW_RX_PROT_S)); | ||
1372 | REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE); | ||
1373 | REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, | ||
1374 | AR_BTCOEX_WL_LNADIV_FORCE_ON); | ||
1375 | |||
1376 | regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); | ||
1377 | regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | | ||
1378 | AR_PHY_ANT_DIV_ALT_LNACONF | | ||
1379 | AR_PHY_ANT_DIV_MAIN_GAINTB | | ||
1380 | AR_PHY_ANT_DIV_ALT_GAINTB); | ||
1381 | regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); | ||
1382 | regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); | ||
1383 | REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1328 | static int ar9003_hw_fast_chan_change(struct ath_hw *ah, | 1387 | static int ar9003_hw_fast_chan_change(struct ath_hw *ah, |
1329 | struct ath9k_channel *chan, | 1388 | struct ath9k_channel *chan, |
1330 | u8 *ini_reloaded) | 1389 | u8 *ini_reloaded) |
@@ -1423,6 +1482,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) | |||
1423 | 1482 | ||
1424 | ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; | 1483 | ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; |
1425 | ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; | 1484 | ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; |
1485 | ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv; | ||
1426 | 1486 | ||
1427 | ar9003_hw_set_nf_limits(ah); | 1487 | ar9003_hw_set_nf_limits(ah); |
1428 | ar9003_hw_set_radar_conf(ah); | 1488 | ar9003_hw_set_radar_conf(ah); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fdabc9a28a96..9a48e3d2f231 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h | |||
@@ -282,6 +282,8 @@ | |||
282 | 282 | ||
283 | #define AR_PHY_ANT_FAST_DIV_BIAS 0x00007e00 | 283 | #define AR_PHY_ANT_FAST_DIV_BIAS 0x00007e00 |
284 | #define AR_PHY_ANT_FAST_DIV_BIAS_S 9 | 284 | #define AR_PHY_ANT_FAST_DIV_BIAS_S 9 |
285 | #define AR_PHY_ANT_SW_RX_PROT 0x00800000 | ||
286 | #define AR_PHY_ANT_SW_RX_PROT_S 23 | ||
285 | #define AR_PHY_ANT_DIV_LNADIV 0x01000000 | 287 | #define AR_PHY_ANT_DIV_LNADIV 0x01000000 |
286 | #define AR_PHY_ANT_DIV_LNADIV_S 24 | 288 | #define AR_PHY_ANT_DIV_LNADIV_S 24 |
287 | #define AR_PHY_ANT_DIV_ALT_LNACONF 0x06000000 | 289 | #define AR_PHY_ANT_DIV_ALT_LNACONF 0x06000000 |
@@ -422,6 +424,8 @@ | |||
422 | #define AR_PHY_FIND_SIG_RELSTEP 0x1f | 424 | #define AR_PHY_FIND_SIG_RELSTEP 0x1f |
423 | #define AR_PHY_FIND_SIG_RELSTEP_S 0 | 425 | #define AR_PHY_FIND_SIG_RELSTEP_S 0 |
424 | #define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT 5 | 426 | #define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT 5 |
427 | #define AR_PHY_RESTART_ENABLE_DIV_M2FLAG 0x00200000 | ||
428 | #define AR_PHY_RESTART_ENABLE_DIV_M2FLAG_S 21 | ||
425 | #define AR_PHY_RESTART_DIV_GC 0x001C0000 | 429 | #define AR_PHY_RESTART_DIV_GC 0x001C0000 |
426 | #define AR_PHY_RESTART_DIV_GC_S 18 | 430 | #define AR_PHY_RESTART_DIV_GC_S 18 |
427 | #define AR_PHY_RESTART_ENA 0x01 | 431 | #define AR_PHY_RESTART_ENA 0x01 |
@@ -1261,4 +1265,24 @@ | |||
1261 | #define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f | 1265 | #define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f |
1262 | #define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0 | 1266 | #define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0 |
1263 | 1267 | ||
1268 | #define AR_BTCOEX_WL_LNADIV 0x1a64 | ||
1269 | #define AR_BTCOEX_WL_LNADIV_PREDICTED_PERIOD 0x00003FFF | ||
1270 | #define AR_BTCOEX_WL_LNADIV_PREDICTED_PERIOD_S 0 | ||
1271 | #define AR_BTCOEX_WL_LNADIV_DPDT_IGNORE_PRIORITY 0x00004000 | ||
1272 | #define AR_BTCOEX_WL_LNADIV_DPDT_IGNORE_PRIORITY_S 14 | ||
1273 | #define AR_BTCOEX_WL_LNADIV_FORCE_ON 0x00008000 | ||
1274 | #define AR_BTCOEX_WL_LNADIV_FORCE_ON_S 15 | ||
1275 | #define AR_BTCOEX_WL_LNADIV_MODE_OPTION 0x00030000 | ||
1276 | #define AR_BTCOEX_WL_LNADIV_MODE_OPTION_S 16 | ||
1277 | #define AR_BTCOEX_WL_LNADIV_MODE 0x007c0000 | ||
1278 | #define AR_BTCOEX_WL_LNADIV_MODE_S 18 | ||
1279 | #define AR_BTCOEX_WL_LNADIV_ALLOWED_TX_ANTDIV_WL_TX_REQ 0x00800000 | ||
1280 | #define AR_BTCOEX_WL_LNADIV_ALLOWED_TX_ANTDIV_WL_TX_REQ_S 23 | ||
1281 | #define AR_BTCOEX_WL_LNADIV_DISABLE_TX_ANTDIV_ENABLE 0x01000000 | ||
1282 | #define AR_BTCOEX_WL_LNADIV_DISABLE_TX_ANTDIV_ENABLE_S 24 | ||
1283 | #define AR_BTCOEX_WL_LNADIV_CONTINUOUS_BT_ACTIVE_PROTECT 0x02000000 | ||
1284 | #define AR_BTCOEX_WL_LNADIV_CONTINUOUS_BT_ACTIVE_PROTECT_S 25 | ||
1285 | #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD 0xFC000000 | ||
1286 | #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S 26 | ||
1287 | |||
1264 | #endif /* AR9003_PHY_H */ | 1288 | #endif /* AR9003_PHY_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index fa9e0932769c..843e79f67ff2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h | |||
@@ -58,8 +58,6 @@ static const u32 ar9565_1p0_mac_core[][2] = { | |||
58 | {0x00008040, 0x00000000}, | 58 | {0x00008040, 0x00000000}, |
59 | {0x00008044, 0x00000000}, | 59 | {0x00008044, 0x00000000}, |
60 | {0x00008048, 0x00000000}, | 60 | {0x00008048, 0x00000000}, |
61 | {0x0000804c, 0xffffffff}, | ||
62 | {0x00008050, 0xffffffff}, | ||
63 | {0x00008054, 0x00000000}, | 61 | {0x00008054, 0x00000000}, |
64 | {0x00008058, 0x00000000}, | 62 | {0x00008058, 0x00000000}, |
65 | {0x0000805c, 0x000fc78f}, | 63 | {0x0000805c, 0x000fc78f}, |
@@ -246,7 +244,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = { | |||
246 | {0x00009e50, 0x00ff03f1}, | 244 | {0x00009e50, 0x00ff03f1}, |
247 | {0x00009e54, 0xe4c355c7}, | 245 | {0x00009e54, 0xe4c355c7}, |
248 | {0x00009e5c, 0xe9198724}, | 246 | {0x00009e5c, 0xe9198724}, |
249 | {0x00009fc0, 0x823e4788}, | 247 | {0x00009fc0, 0x823e4fc8}, |
250 | {0x00009fc4, 0x0001efb5}, | 248 | {0x00009fc4, 0x0001efb5}, |
251 | {0x00009fcc, 0x40000014}, | 249 | {0x00009fcc, 0x40000014}, |
252 | {0x0000a20c, 0x00000000}, | 250 | {0x0000a20c, 0x00000000}, |
@@ -291,7 +289,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = { | |||
291 | {0x0000a3ec, 0x20202020}, | 289 | {0x0000a3ec, 0x20202020}, |
292 | {0x0000a3f0, 0x00000000}, | 290 | {0x0000a3f0, 0x00000000}, |
293 | {0x0000a3f4, 0x00000006}, | 291 | {0x0000a3f4, 0x00000006}, |
294 | {0x0000a3f8, 0x0cdbd380}, | 292 | {0x0000a3f8, 0x0c9bd380}, |
295 | {0x0000a3fc, 0x000f0f01}, | 293 | {0x0000a3fc, 0x000f0f01}, |
296 | {0x0000a400, 0x8fa91f01}, | 294 | {0x0000a400, 0x8fa91f01}, |
297 | {0x0000a404, 0x00000000}, | 295 | {0x0000a404, 0x00000000}, |
@@ -355,11 +353,11 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = { | |||
355 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, | 353 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, |
356 | {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, | 354 | {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, |
357 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, | 355 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, |
358 | {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, | 356 | {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, |
359 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | 357 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, |
360 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, | 358 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, |
361 | {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, | 359 | {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, |
362 | {0x0000a204, 0x033187c0, 0x033187c4, 0x033187c4, 0x033187c0}, | 360 | {0x0000a204, 0x07318fc0, 0x07318fc4, 0x07318fc4, 0x07318fc0}, |
363 | {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, | 361 | {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, |
364 | {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, | 362 | {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, |
365 | {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, | 363 | {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, |
@@ -375,9 +373,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = { | |||
375 | {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, | 373 | {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, |
376 | {0x0000a288, 0x00100510, 0x00100510, 0x00100510, 0x00100510}, | 374 | {0x0000a288, 0x00100510, 0x00100510, 0x00100510, 0x00100510}, |
377 | {0x0000a28c, 0x00021551, 0x00021551, 0x00021551, 0x00021551}, | 375 | {0x0000a28c, 0x00021551, 0x00021551, 0x00021551, 0x00021551}, |
378 | {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, | 376 | {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, |
379 | {0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982}, | 377 | {0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982}, |
380 | {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, | 378 | {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, |
381 | {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 379 | {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
382 | {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, | 380 | {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, |
383 | {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 381 | {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
@@ -417,7 +415,7 @@ static const u32 ar9565_1p0_radio_core[][2] = { | |||
417 | {0x00016144, 0x02084080}, | 415 | {0x00016144, 0x02084080}, |
418 | {0x00016148, 0x000080c0}, | 416 | {0x00016148, 0x000080c0}, |
419 | {0x00016280, 0x050a0001}, | 417 | {0x00016280, 0x050a0001}, |
420 | {0x00016284, 0x3d841400}, | 418 | {0x00016284, 0x3d841440}, |
421 | {0x00016288, 0x00000000}, | 419 | {0x00016288, 0x00000000}, |
422 | {0x0001628c, 0xe3000000}, | 420 | {0x0001628c, 0xe3000000}, |
423 | {0x00016290, 0xa1004080}, | 421 | {0x00016290, 0xa1004080}, |
@@ -840,27 +838,27 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = { | |||
840 | {0x0000a0b4, 0x00000000}, | 838 | {0x0000a0b4, 0x00000000}, |
841 | {0x0000a0b8, 0x00000000}, | 839 | {0x0000a0b8, 0x00000000}, |
842 | {0x0000a0bc, 0x00000000}, | 840 | {0x0000a0bc, 0x00000000}, |
843 | {0x0000a0c0, 0x301f3000}, | 841 | {0x0000a0c0, 0x00bf00a0}, |
844 | {0x0000a0c4, 0x41004101}, | 842 | {0x0000a0c4, 0x11a011a1}, |
845 | {0x0000a0c8, 0x411e411f}, | 843 | {0x0000a0c8, 0x11be11bf}, |
846 | {0x0000a0cc, 0x411c411d}, | 844 | {0x0000a0cc, 0x11bc11bd}, |
847 | {0x0000a0d0, 0x42434244}, | 845 | {0x0000a0d0, 0x22632264}, |
848 | {0x0000a0d4, 0x42414242}, | 846 | {0x0000a0d4, 0x22612262}, |
849 | {0x0000a0d8, 0x425f4240}, | 847 | {0x0000a0d8, 0x227f2260}, |
850 | {0x0000a0dc, 0x5342425e}, | 848 | {0x0000a0dc, 0x4322227e}, |
851 | {0x0000a0e0, 0x53405341}, | 849 | {0x0000a0e0, 0x43204321}, |
852 | {0x0000a0e4, 0x535e535f}, | 850 | {0x0000a0e4, 0x433e433f}, |
853 | {0x0000a0e8, 0x7402535d}, | 851 | {0x0000a0e8, 0x4462433d}, |
854 | {0x0000a0ec, 0x74007401}, | 852 | {0x0000a0ec, 0x44604461}, |
855 | {0x0000a0f0, 0x741e741f}, | 853 | {0x0000a0f0, 0x447e447f}, |
856 | {0x0000a0f4, 0x7522741d}, | 854 | {0x0000a0f4, 0x5582447d}, |
857 | {0x0000a0f8, 0x75207521}, | 855 | {0x0000a0f8, 0x55805581}, |
858 | {0x0000a0fc, 0x753e753f}, | 856 | {0x0000a0fc, 0x559e559f}, |
859 | {0x0000a100, 0x76617662}, | 857 | {0x0000a100, 0x66816682}, |
860 | {0x0000a104, 0x767f7660}, | 858 | {0x0000a104, 0x669f6680}, |
861 | {0x0000a108, 0x767d767e}, | 859 | {0x0000a108, 0x669d669e}, |
862 | {0x0000a10c, 0x77e277e3}, | 860 | {0x0000a10c, 0x77627763}, |
863 | {0x0000a110, 0x77e077e1}, | 861 | {0x0000a110, 0x77607761}, |
864 | {0x0000a114, 0x00000000}, | 862 | {0x0000a114, 0x00000000}, |
865 | {0x0000a118, 0x00000000}, | 863 | {0x0000a118, 0x00000000}, |
866 | {0x0000a11c, 0x00000000}, | 864 | {0x0000a11c, 0x00000000}, |
@@ -872,27 +870,27 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = { | |||
872 | {0x0000a134, 0x00000000}, | 870 | {0x0000a134, 0x00000000}, |
873 | {0x0000a138, 0x00000000}, | 871 | {0x0000a138, 0x00000000}, |
874 | {0x0000a13c, 0x00000000}, | 872 | {0x0000a13c, 0x00000000}, |
875 | {0x0000a140, 0x301f3000}, | 873 | {0x0000a140, 0x00bf00a0}, |
876 | {0x0000a144, 0x41004101}, | 874 | {0x0000a144, 0x11a011a1}, |
877 | {0x0000a148, 0x411e411f}, | 875 | {0x0000a148, 0x11be11bf}, |
878 | {0x0000a14c, 0x411c411d}, | 876 | {0x0000a14c, 0x11bc11bd}, |
879 | {0x0000a150, 0x42434244}, | 877 | {0x0000a150, 0x22632264}, |
880 | {0x0000a154, 0x42414242}, | 878 | {0x0000a154, 0x22612262}, |
881 | {0x0000a158, 0x425f4240}, | 879 | {0x0000a158, 0x227f2260}, |
882 | {0x0000a15c, 0x5342425e}, | 880 | {0x0000a15c, 0x4322227e}, |
883 | {0x0000a160, 0x53405341}, | 881 | {0x0000a160, 0x43204321}, |
884 | {0x0000a164, 0x535e535f}, | 882 | {0x0000a164, 0x433e433f}, |
885 | {0x0000a168, 0x7402535d}, | 883 | {0x0000a168, 0x4462433d}, |
886 | {0x0000a16c, 0x74007401}, | 884 | {0x0000a16c, 0x44604461}, |
887 | {0x0000a170, 0x741e741f}, | 885 | {0x0000a170, 0x447e447f}, |
888 | {0x0000a174, 0x7522741d}, | 886 | {0x0000a174, 0x5582447d}, |
889 | {0x0000a178, 0x75207521}, | 887 | {0x0000a178, 0x55805581}, |
890 | {0x0000a17c, 0x753e753f}, | 888 | {0x0000a17c, 0x559e559f}, |
891 | {0x0000a180, 0x76617662}, | 889 | {0x0000a180, 0x66816682}, |
892 | {0x0000a184, 0x767f7660}, | 890 | {0x0000a184, 0x669f6680}, |
893 | {0x0000a188, 0x767d767e}, | 891 | {0x0000a188, 0x669d669e}, |
894 | {0x0000a18c, 0x77e277e3}, | 892 | {0x0000a18c, 0x77627763}, |
895 | {0x0000a190, 0x77e077e1}, | 893 | {0x0000a190, 0x77607761}, |
896 | {0x0000a194, 0x00000000}, | 894 | {0x0000a194, 0x00000000}, |
897 | {0x0000a198, 0x00000000}, | 895 | {0x0000a198, 0x00000000}, |
898 | {0x0000a19c, 0x00000000}, | 896 | {0x0000a19c, 0x00000000}, |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 96b8331ef9e7..8e27f4fb21fe 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -537,6 +537,7 @@ struct ath9k_wow_pattern { | |||
537 | #ifdef CONFIG_MAC80211_LEDS | 537 | #ifdef CONFIG_MAC80211_LEDS |
538 | void ath_init_leds(struct ath_softc *sc); | 538 | void ath_init_leds(struct ath_softc *sc); |
539 | void ath_deinit_leds(struct ath_softc *sc); | 539 | void ath_deinit_leds(struct ath_softc *sc); |
540 | void ath_fill_led_pin(struct ath_softc *sc); | ||
540 | #else | 541 | #else |
541 | static inline void ath_init_leds(struct ath_softc *sc) | 542 | static inline void ath_init_leds(struct ath_softc *sc) |
542 | { | 543 | { |
@@ -545,6 +546,9 @@ static inline void ath_init_leds(struct ath_softc *sc) | |||
545 | static inline void ath_deinit_leds(struct ath_softc *sc) | 546 | static inline void ath_deinit_leds(struct ath_softc *sc) |
546 | { | 547 | { |
547 | } | 548 | } |
549 | static inline void ath_fill_led_pin(struct ath_softc *sc) | ||
550 | { | ||
551 | } | ||
548 | #endif | 552 | #endif |
549 | 553 | ||
550 | /*******************************/ | 554 | /*******************************/ |
@@ -596,8 +600,6 @@ struct ath_ant_comb { | |||
596 | int main_conf; | 600 | int main_conf; |
597 | enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf; | 601 | enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf; |
598 | enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf; | 602 | enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf; |
599 | int first_bias; | ||
600 | int second_bias; | ||
601 | bool first_ratio; | 603 | bool first_ratio; |
602 | bool second_ratio; | 604 | bool second_ratio; |
603 | unsigned long scan_start_time; | 605 | unsigned long scan_start_time; |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 45f24220b16e..bf7d29ec1a87 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -44,25 +44,6 @@ void ath_init_leds(struct ath_softc *sc) | |||
44 | if (AR_SREV_9100(sc->sc_ah)) | 44 | if (AR_SREV_9100(sc->sc_ah)) |
45 | return; | 45 | return; |
46 | 46 | ||
47 | if (sc->sc_ah->led_pin < 0) { | ||
48 | if (AR_SREV_9287(sc->sc_ah)) | ||
49 | sc->sc_ah->led_pin = ATH_LED_PIN_9287; | ||
50 | else if (AR_SREV_9485(sc->sc_ah)) | ||
51 | sc->sc_ah->led_pin = ATH_LED_PIN_9485; | ||
52 | else if (AR_SREV_9300(sc->sc_ah)) | ||
53 | sc->sc_ah->led_pin = ATH_LED_PIN_9300; | ||
54 | else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) | ||
55 | sc->sc_ah->led_pin = ATH_LED_PIN_9462; | ||
56 | else | ||
57 | sc->sc_ah->led_pin = ATH_LED_PIN_DEF; | ||
58 | } | ||
59 | |||
60 | /* Configure gpio 1 for output */ | ||
61 | ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, | ||
62 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
63 | /* LED off, active low */ | ||
64 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | ||
65 | |||
66 | if (!led_blink) | 47 | if (!led_blink) |
67 | sc->led_cdev.default_trigger = | 48 | sc->led_cdev.default_trigger = |
68 | ieee80211_get_radio_led_name(sc->hw); | 49 | ieee80211_get_radio_led_name(sc->hw); |
@@ -78,6 +59,31 @@ void ath_init_leds(struct ath_softc *sc) | |||
78 | 59 | ||
79 | sc->led_registered = true; | 60 | sc->led_registered = true; |
80 | } | 61 | } |
62 | |||
63 | void ath_fill_led_pin(struct ath_softc *sc) | ||
64 | { | ||
65 | struct ath_hw *ah = sc->sc_ah; | ||
66 | |||
67 | if (AR_SREV_9100(ah) || (ah->led_pin >= 0)) | ||
68 | return; | ||
69 | |||
70 | if (AR_SREV_9287(ah)) | ||
71 | ah->led_pin = ATH_LED_PIN_9287; | ||
72 | else if (AR_SREV_9485(sc->sc_ah)) | ||
73 | ah->led_pin = ATH_LED_PIN_9485; | ||
74 | else if (AR_SREV_9300(sc->sc_ah)) | ||
75 | ah->led_pin = ATH_LED_PIN_9300; | ||
76 | else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) | ||
77 | ah->led_pin = ATH_LED_PIN_9462; | ||
78 | else | ||
79 | ah->led_pin = ATH_LED_PIN_DEF; | ||
80 | |||
81 | /* Configure gpio 1 for output */ | ||
82 | ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
83 | |||
84 | /* LED off, active low */ | ||
85 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
86 | } | ||
81 | #endif | 87 | #endif |
82 | 88 | ||
83 | /*******************/ | 89 | /*******************/ |
@@ -314,8 +320,10 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) | |||
314 | ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); | 320 | ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); |
315 | 321 | ||
316 | /* make sure duty cycle timer is also stopped when resuming */ | 322 | /* make sure duty cycle timer is also stopped when resuming */ |
317 | if (btcoex->hw_timer_enabled) | 323 | if (btcoex->hw_timer_enabled) { |
318 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | 324 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); |
325 | btcoex->hw_timer_enabled = false; | ||
326 | } | ||
319 | 327 | ||
320 | btcoex->bt_priority_cnt = 0; | 328 | btcoex->bt_priority_cnt = 0; |
321 | btcoex->bt_priority_time = jiffies; | 329 | btcoex->bt_priority_time = jiffies; |
@@ -336,18 +344,20 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) | |||
336 | 344 | ||
337 | del_timer_sync(&btcoex->period_timer); | 345 | del_timer_sync(&btcoex->period_timer); |
338 | 346 | ||
339 | if (btcoex->hw_timer_enabled) | 347 | if (btcoex->hw_timer_enabled) { |
340 | ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); | 348 | ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); |
341 | 349 | btcoex->hw_timer_enabled = false; | |
342 | btcoex->hw_timer_enabled = false; | 350 | } |
343 | } | 351 | } |
344 | 352 | ||
345 | void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) | 353 | void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) |
346 | { | 354 | { |
347 | struct ath_btcoex *btcoex = &sc->btcoex; | 355 | struct ath_btcoex *btcoex = &sc->btcoex; |
348 | 356 | ||
349 | if (btcoex->hw_timer_enabled) | 357 | if (btcoex->hw_timer_enabled) { |
350 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | 358 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); |
359 | btcoex->hw_timer_enabled = false; | ||
360 | } | ||
351 | } | 361 | } |
352 | 362 | ||
353 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) | 363 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) |
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index ee6e50aebf8d..924c4616c3d9 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -1072,14 +1072,15 @@ static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) | |||
1072 | */ | 1072 | */ |
1073 | static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) | 1073 | static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) |
1074 | { | 1074 | { |
1075 | struct device *parent = hif_dev->udev->dev.parent; | 1075 | struct device *dev = &hif_dev->udev->dev; |
1076 | struct device *parent = dev->parent; | ||
1076 | 1077 | ||
1077 | complete(&hif_dev->fw_done); | 1078 | complete(&hif_dev->fw_done); |
1078 | 1079 | ||
1079 | if (parent) | 1080 | if (parent) |
1080 | device_lock(parent); | 1081 | device_lock(parent); |
1081 | 1082 | ||
1082 | device_release_driver(&hif_dev->udev->dev); | 1083 | device_release_driver(dev); |
1083 | 1084 | ||
1084 | if (parent) | 1085 | if (parent) |
1085 | device_unlock(parent); | 1086 | device_unlock(parent); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 61d096e3596f..ca78e33ca23e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -1445,7 +1445,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, | |||
1445 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 1445 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
1446 | if (priv->ah->sw_mgmt_crypto && | 1446 | if (priv->ah->sw_mgmt_crypto && |
1447 | key->cipher == WLAN_CIPHER_SUITE_CCMP) | 1447 | key->cipher == WLAN_CIPHER_SUITE_CCMP) |
1448 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | 1448 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
1449 | ret = 0; | 1449 | ret = 0; |
1450 | } | 1450 | } |
1451 | break; | 1451 | break; |
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 265bf77598a2..0f2b97f6b739 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h | |||
@@ -78,6 +78,13 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, | |||
78 | ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); | 78 | ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); |
79 | } | 79 | } |
80 | 80 | ||
81 | static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, | ||
82 | bool enable) | ||
83 | { | ||
84 | if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv) | ||
85 | ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable); | ||
86 | } | ||
87 | |||
81 | /* Private hardware call ops */ | 88 | /* Private hardware call ops */ |
82 | 89 | ||
83 | /* PHY ops */ | 90 | /* PHY ops */ |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 40f57aa2564e..f9a6ec5cf470 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "rc.h" | 24 | #include "rc.h" |
25 | #include "ar9003_mac.h" | 25 | #include "ar9003_mac.h" |
26 | #include "ar9003_mci.h" | 26 | #include "ar9003_mci.h" |
27 | #include "ar9003_phy.h" | ||
27 | #include "debug.h" | 28 | #include "debug.h" |
28 | #include "ath9k.h" | 29 | #include "ath9k.h" |
29 | 30 | ||
@@ -1733,12 +1734,12 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) | |||
1733 | if (!ret) | 1734 | if (!ret) |
1734 | goto fail; | 1735 | goto fail; |
1735 | 1736 | ||
1736 | ath9k_hw_loadnf(ah, ah->curchan); | ||
1737 | ath9k_hw_start_nfcal(ah, true); | ||
1738 | |||
1739 | if (ath9k_hw_mci_is_enabled(ah)) | 1737 | if (ath9k_hw_mci_is_enabled(ah)) |
1740 | ar9003_mci_2g5g_switch(ah, false); | 1738 | ar9003_mci_2g5g_switch(ah, false); |
1741 | 1739 | ||
1740 | ath9k_hw_loadnf(ah, ah->curchan); | ||
1741 | ath9k_hw_start_nfcal(ah, true); | ||
1742 | |||
1742 | if (AR_SREV_9271(ah)) | 1743 | if (AR_SREV_9271(ah)) |
1743 | ar9002_hw_load_ani_reg(ah, chan); | 1744 | ar9002_hw_load_ani_reg(ah, chan); |
1744 | 1745 | ||
@@ -2025,6 +2026,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
2025 | 2026 | ||
2026 | ath9k_hw_apply_gpio_override(ah); | 2027 | ath9k_hw_apply_gpio_override(ah); |
2027 | 2028 | ||
2029 | if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv) | ||
2030 | REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); | ||
2031 | |||
2028 | return 0; | 2032 | return 0; |
2029 | } | 2033 | } |
2030 | EXPORT_SYMBOL(ath9k_hw_reset); | 2034 | EXPORT_SYMBOL(ath9k_hw_reset); |
@@ -2535,7 +2539,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2535 | } | 2539 | } |
2536 | 2540 | ||
2537 | 2541 | ||
2538 | if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) { | 2542 | if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) { |
2539 | ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); | 2543 | ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); |
2540 | /* | 2544 | /* |
2541 | * enable the diversity-combining algorithm only when | 2545 | * enable the diversity-combining algorithm only when |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f0798cc50dc1..566a4ce4f156 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -686,7 +686,7 @@ struct ath_hw_ops { | |||
686 | struct ath_hw_antcomb_conf *antconf); | 686 | struct ath_hw_antcomb_conf *antconf); |
687 | void (*antdiv_comb_conf_set)(struct ath_hw *ah, | 687 | void (*antdiv_comb_conf_set)(struct ath_hw *ah, |
688 | struct ath_hw_antcomb_conf *antconf); | 688 | struct ath_hw_antcomb_conf *antconf); |
689 | 689 | void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable); | |
690 | }; | 690 | }; |
691 | 691 | ||
692 | struct ath_nf_limits { | 692 | struct ath_nf_limits { |
@@ -730,6 +730,7 @@ struct ath_hw { | |||
730 | bool aspm_enabled; | 730 | bool aspm_enabled; |
731 | bool is_monitoring; | 731 | bool is_monitoring; |
732 | bool need_an_top2_fixup; | 732 | bool need_an_top2_fixup; |
733 | bool shared_chain_lnadiv; | ||
733 | u16 tx_trig_level; | 734 | u16 tx_trig_level; |
734 | 735 | ||
735 | u32 nf_regs[6]; | 736 | u32 nf_regs[6]; |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index f3ce5ca2f1d3..fad3ccd5cd91 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -46,6 +46,10 @@ static int ath9k_btcoex_enable; | |||
46 | module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); | 46 | module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); |
47 | MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); | 47 | MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); |
48 | 48 | ||
49 | static int ath9k_enable_diversity; | ||
50 | module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444); | ||
51 | MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565"); | ||
52 | |||
49 | bool is_ath9k_unloaded; | 53 | bool is_ath9k_unloaded; |
50 | /* We use the hw_value as an index into our private channel structure */ | 54 | /* We use the hw_value as an index into our private channel structure */ |
51 | 55 | ||
@@ -546,6 +550,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
546 | common->debug_mask = ath9k_debug; | 550 | common->debug_mask = ath9k_debug; |
547 | common->btcoex_enabled = ath9k_btcoex_enable == 1; | 551 | common->btcoex_enabled = ath9k_btcoex_enable == 1; |
548 | common->disable_ani = false; | 552 | common->disable_ani = false; |
553 | |||
554 | /* | ||
555 | * Enable Antenna diversity only when BTCOEX is disabled | ||
556 | * and the user manually requests the feature. | ||
557 | */ | ||
558 | if (!common->btcoex_enabled && ath9k_enable_diversity) | ||
559 | common->antenna_diversity = 1; | ||
560 | |||
549 | spin_lock_init(&common->cc_lock); | 561 | spin_lock_init(&common->cc_lock); |
550 | 562 | ||
551 | spin_lock_init(&sc->sc_serial_rw); | 563 | spin_lock_init(&sc->sc_serial_rw); |
@@ -597,6 +609,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
597 | 609 | ||
598 | ath9k_cmn_init_crypto(sc->sc_ah); | 610 | ath9k_cmn_init_crypto(sc->sc_ah); |
599 | ath9k_init_misc(sc); | 611 | ath9k_init_misc(sc); |
612 | ath_fill_led_pin(sc); | ||
600 | 613 | ||
601 | if (common->bus_ops->aspm_init) | 614 | if (common->bus_ops->aspm_init) |
602 | common->bus_ops->aspm_init(common); | 615 | common->bus_ops->aspm_init(common); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3923ad933aef..31ab82e3ba85 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1406,7 +1406,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1406 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 1406 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
1407 | if (sc->sc_ah->sw_mgmt_crypto && | 1407 | if (sc->sc_ah->sw_mgmt_crypto && |
1408 | key->cipher == WLAN_CIPHER_SUITE_CCMP) | 1408 | key->cipher == WLAN_CIPHER_SUITE_CCMP) |
1409 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | 1409 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
1410 | ret = 0; | 1410 | ret = 0; |
1411 | } | 1411 | } |
1412 | break; | 1412 | break; |
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 8f0e8d9c2054..8f51e9e358fd 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c | |||
@@ -80,6 +80,7 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci) | |||
80 | struct ath_mci_profile_info *info, *tinfo; | 80 | struct ath_mci_profile_info *info, *tinfo; |
81 | 81 | ||
82 | mci->aggr_limit = 0; | 82 | mci->aggr_limit = 0; |
83 | mci->num_mgmt = 0; | ||
83 | 84 | ||
84 | if (list_empty(&mci->info)) | 85 | if (list_empty(&mci->info)) |
85 | return; | 86 | return; |
@@ -120,7 +121,14 @@ static void ath_mci_update_scheme(struct ath_softc *sc) | |||
120 | if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING) | 121 | if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING) |
121 | goto skip_tuning; | 122 | goto skip_tuning; |
122 | 123 | ||
124 | mci->aggr_limit = 0; | ||
123 | btcoex->duty_cycle = ath_mci_duty_cycle[num_profile]; | 125 | btcoex->duty_cycle = ath_mci_duty_cycle[num_profile]; |
126 | btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; | ||
127 | if (NUM_PROF(mci)) | ||
128 | btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | ||
129 | else | ||
130 | btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL : | ||
131 | ATH_BTCOEX_STOMP_LOW; | ||
124 | 132 | ||
125 | if (num_profile == 1) { | 133 | if (num_profile == 1) { |
126 | info = list_first_entry(&mci->info, | 134 | info = list_first_entry(&mci->info, |
@@ -132,7 +140,8 @@ static void ath_mci_update_scheme(struct ath_softc *sc) | |||
132 | else if (info->T == 6) { | 140 | else if (info->T == 6) { |
133 | mci->aggr_limit = 6; | 141 | mci->aggr_limit = 6; |
134 | btcoex->duty_cycle = 30; | 142 | btcoex->duty_cycle = 30; |
135 | } | 143 | } else |
144 | mci->aggr_limit = 6; | ||
136 | ath_dbg(common, MCI, | 145 | ath_dbg(common, MCI, |
137 | "Single SCO, aggregation limit %d 1/4 ms\n", | 146 | "Single SCO, aggregation limit %d 1/4 ms\n", |
138 | mci->aggr_limit); | 147 | mci->aggr_limit); |
@@ -241,8 +250,8 @@ static void ath9k_mci_work(struct work_struct *work) | |||
241 | ath_mci_update_scheme(sc); | 250 | ath_mci_update_scheme(sc); |
242 | } | 251 | } |
243 | 252 | ||
244 | static void ath_mci_process_profile(struct ath_softc *sc, | 253 | static u8 ath_mci_process_profile(struct ath_softc *sc, |
245 | struct ath_mci_profile_info *info) | 254 | struct ath_mci_profile_info *info) |
246 | { | 255 | { |
247 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 256 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
248 | struct ath_btcoex *btcoex = &sc->btcoex; | 257 | struct ath_btcoex *btcoex = &sc->btcoex; |
@@ -268,25 +277,15 @@ static void ath_mci_process_profile(struct ath_softc *sc, | |||
268 | 277 | ||
269 | if (info->start) { | 278 | if (info->start) { |
270 | if (!entry && !ath_mci_add_profile(common, mci, info)) | 279 | if (!entry && !ath_mci_add_profile(common, mci, info)) |
271 | return; | 280 | return 0; |
272 | } else | 281 | } else |
273 | ath_mci_del_profile(common, mci, entry); | 282 | ath_mci_del_profile(common, mci, entry); |
274 | 283 | ||
275 | btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; | 284 | return 1; |
276 | mci->aggr_limit = mci->num_sco ? 6 : 0; | ||
277 | |||
278 | btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; | ||
279 | if (NUM_PROF(mci)) | ||
280 | btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | ||
281 | else | ||
282 | btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL : | ||
283 | ATH_BTCOEX_STOMP_LOW; | ||
284 | |||
285 | ieee80211_queue_work(sc->hw, &sc->mci_work); | ||
286 | } | 285 | } |
287 | 286 | ||
288 | static void ath_mci_process_status(struct ath_softc *sc, | 287 | static u8 ath_mci_process_status(struct ath_softc *sc, |
289 | struct ath_mci_profile_status *status) | 288 | struct ath_mci_profile_status *status) |
290 | { | 289 | { |
291 | struct ath_btcoex *btcoex = &sc->btcoex; | 290 | struct ath_btcoex *btcoex = &sc->btcoex; |
292 | struct ath_mci_profile *mci = &btcoex->mci; | 291 | struct ath_mci_profile *mci = &btcoex->mci; |
@@ -295,14 +294,14 @@ static void ath_mci_process_status(struct ath_softc *sc, | |||
295 | 294 | ||
296 | /* Link status type are not handled */ | 295 | /* Link status type are not handled */ |
297 | if (status->is_link) | 296 | if (status->is_link) |
298 | return; | 297 | return 0; |
299 | 298 | ||
300 | info.conn_handle = status->conn_handle; | 299 | info.conn_handle = status->conn_handle; |
301 | if (ath_mci_find_profile(mci, &info)) | 300 | if (ath_mci_find_profile(mci, &info)) |
302 | return; | 301 | return 0; |
303 | 302 | ||
304 | if (status->conn_handle >= ATH_MCI_MAX_PROFILE) | 303 | if (status->conn_handle >= ATH_MCI_MAX_PROFILE) |
305 | return; | 304 | return 0; |
306 | 305 | ||
307 | if (status->is_critical) | 306 | if (status->is_critical) |
308 | __set_bit(status->conn_handle, mci->status); | 307 | __set_bit(status->conn_handle, mci->status); |
@@ -316,7 +315,9 @@ static void ath_mci_process_status(struct ath_softc *sc, | |||
316 | } while (++i < ATH_MCI_MAX_PROFILE); | 315 | } while (++i < ATH_MCI_MAX_PROFILE); |
317 | 316 | ||
318 | if (old_num_mgmt != mci->num_mgmt) | 317 | if (old_num_mgmt != mci->num_mgmt) |
319 | ieee80211_queue_work(sc->hw, &sc->mci_work); | 318 | return 1; |
319 | |||
320 | return 0; | ||
320 | } | 321 | } |
321 | 322 | ||
322 | static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) | 323 | static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) |
@@ -325,9 +326,16 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) | |||
325 | struct ath_mci_profile_info profile_info; | 326 | struct ath_mci_profile_info profile_info; |
326 | struct ath_mci_profile_status profile_status; | 327 | struct ath_mci_profile_status profile_status; |
327 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 328 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
328 | u8 major, minor; | 329 | u8 major, minor, update_scheme = 0; |
329 | u32 seq_num; | 330 | u32 seq_num; |
330 | 331 | ||
332 | if (ar9003_mci_state(ah, MCI_STATE_NEED_FLUSH_BT_INFO) && | ||
333 | ar9003_mci_state(ah, MCI_STATE_ENABLE)) { | ||
334 | ath_dbg(common, MCI, "(MCI) Need to flush BT profiles\n"); | ||
335 | ath_mci_flush_profile(&sc->btcoex.mci); | ||
336 | ar9003_mci_state(ah, MCI_STATE_SEND_STATUS_QUERY); | ||
337 | } | ||
338 | |||
331 | switch (opcode) { | 339 | switch (opcode) { |
332 | case MCI_GPM_COEX_VERSION_QUERY: | 340 | case MCI_GPM_COEX_VERSION_QUERY: |
333 | ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION); | 341 | ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION); |
@@ -353,7 +361,7 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) | |||
353 | break; | 361 | break; |
354 | } | 362 | } |
355 | 363 | ||
356 | ath_mci_process_profile(sc, &profile_info); | 364 | update_scheme += ath_mci_process_profile(sc, &profile_info); |
357 | break; | 365 | break; |
358 | case MCI_GPM_COEX_BT_STATUS_UPDATE: | 366 | case MCI_GPM_COEX_BT_STATUS_UPDATE: |
359 | profile_status.is_link = *(rx_payload + | 367 | profile_status.is_link = *(rx_payload + |
@@ -369,12 +377,14 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) | |||
369 | profile_status.is_link, profile_status.conn_handle, | 377 | profile_status.is_link, profile_status.conn_handle, |
370 | profile_status.is_critical, seq_num); | 378 | profile_status.is_critical, seq_num); |
371 | 379 | ||
372 | ath_mci_process_status(sc, &profile_status); | 380 | update_scheme += ath_mci_process_status(sc, &profile_status); |
373 | break; | 381 | break; |
374 | default: | 382 | default: |
375 | ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode); | 383 | ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode); |
376 | break; | 384 | break; |
377 | } | 385 | } |
386 | if (update_scheme) | ||
387 | ieee80211_queue_work(sc->hw, &sc->mci_work); | ||
378 | } | 388 | } |
379 | 389 | ||
380 | int ath_mci_setup(struct ath_softc *sc) | 390 | int ath_mci_setup(struct ath_softc *sc) |
@@ -568,9 +578,11 @@ void ath_mci_intr(struct ath_softc *sc) | |||
568 | } | 578 | } |
569 | 579 | ||
570 | if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || | 580 | if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || |
571 | (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) | 581 | (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { |
572 | mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | | 582 | mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | |
573 | AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); | 583 | AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); |
584 | ath_mci_msg(sc, MCI_GPM_COEX_NOOP, NULL); | ||
585 | } | ||
574 | } | 586 | } |
575 | 587 | ||
576 | void ath_mci_enable(struct ath_softc *sc) | 588 | void ath_mci_enable(struct ath_softc *sc) |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index a8f6126f6b2d..c0c599673eeb 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -128,8 +128,9 @@ static void ath_pci_aspm_init(struct ath_common *common) | |||
128 | if (!parent) | 128 | if (!parent) |
129 | return; | 129 | return; |
130 | 130 | ||
131 | if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { | 131 | if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && |
132 | /* Bluetooth coexistance requires disabling ASPM. */ | 132 | (AR_SREV_9285(ah))) { |
133 | /* Bluetooth coexistance requires disabling ASPM for AR9285. */ | ||
133 | pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); | 134 | pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); |
134 | aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); | 135 | aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); |
135 | pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); | 136 | pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 4b12c347d188..27ed80b54881 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1222,11 +1222,14 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
1222 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; | 1222 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; |
1223 | else if (sta->ht_cap.mcs.rx_mask[1]) | 1223 | else if (sta->ht_cap.mcs.rx_mask[1]) |
1224 | caps |= WLAN_RC_DS_FLAG; | 1224 | caps |= WLAN_RC_DS_FLAG; |
1225 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1225 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { |
1226 | caps |= WLAN_RC_40_FLAG; | 1226 | caps |= WLAN_RC_40_FLAG; |
1227 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40 || | 1227 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) |
1228 | sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) | 1228 | caps |= WLAN_RC_SGI_FLAG; |
1229 | caps |= WLAN_RC_SGI_FLAG; | 1229 | } else { |
1230 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) | ||
1231 | caps |= WLAN_RC_SGI_FLAG; | ||
1232 | } | ||
1230 | } | 1233 | } |
1231 | 1234 | ||
1232 | return caps; | 1235 | return caps; |
diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index f8676280dc36..e3b1b6e87760 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c | |||
@@ -304,7 +304,8 @@ int carl9170_set_operating_mode(struct ar9170 *ar) | |||
304 | struct ath_common *common = &ar->common; | 304 | struct ath_common *common = &ar->common; |
305 | u8 *mac_addr, *bssid; | 305 | u8 *mac_addr, *bssid; |
306 | u32 cam_mode = AR9170_MAC_CAM_DEFAULTS; | 306 | u32 cam_mode = AR9170_MAC_CAM_DEFAULTS; |
307 | u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS; | 307 | u32 enc_mode = AR9170_MAC_ENCRYPTION_DEFAULTS | |
308 | AR9170_MAC_ENCRYPTION_MGMT_RX_SOFTWARE; | ||
308 | u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG | | 309 | u32 rx_ctrl = AR9170_MAC_RX_CTRL_DEAGG | |
309 | AR9170_MAC_RX_CTRL_SHORT_FILTER; | 310 | AR9170_MAC_RX_CTRL_SHORT_FILTER; |
310 | u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS; | 311 | u32 sniffer = AR9170_MAC_SNIFFER_DEFAULTS; |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 18554ab76733..67997b39aba7 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1149,6 +1149,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
1149 | break; | 1149 | break; |
1150 | case WLAN_CIPHER_SUITE_CCMP: | 1150 | case WLAN_CIPHER_SUITE_CCMP: |
1151 | ktype = AR9170_ENC_ALG_AESCCMP; | 1151 | ktype = AR9170_ENC_ALG_AESCCMP; |
1152 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; | ||
1152 | break; | 1153 | break; |
1153 | default: | 1154 | default: |
1154 | return -EOPNOTSUPP; | 1155 | return -EOPNOTSUPP; |
@@ -1780,6 +1781,7 @@ void *carl9170_alloc(size_t priv_size) | |||
1780 | hw->wiphy->interface_modes = 0; | 1781 | hw->wiphy->interface_modes = 0; |
1781 | 1782 | ||
1782 | hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | | 1783 | hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | |
1784 | IEEE80211_HW_MFP_CAPABLE | | ||
1783 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 1785 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
1784 | IEEE80211_HW_SUPPORTS_PS | | 1786 | IEEE80211_HW_SUPPORTS_PS | |
1785 | IEEE80211_HW_PS_NULLFUNC_STACK | | 1787 | IEEE80211_HW_PS_NULLFUNC_STACK | |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 8e7e6928c936..3b2c4c20e7fc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | |||
@@ -185,7 +185,7 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) | |||
185 | return err; | 185 | return err; |
186 | } | 186 | } |
187 | 187 | ||
188 | static int | 188 | int |
189 | brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, | 189 | brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, |
190 | void *data, bool write) | 190 | void *data, bool write) |
191 | { | 191 | { |
@@ -249,7 +249,9 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) | |||
249 | int retval; | 249 | int retval; |
250 | 250 | ||
251 | brcmf_dbg(INFO, "addr:0x%08x\n", addr); | 251 | brcmf_dbg(INFO, "addr:0x%08x\n", addr); |
252 | sdio_claim_host(sdiodev->func[1]); | ||
252 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); | 253 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); |
254 | sdio_release_host(sdiodev->func[1]); | ||
253 | brcmf_dbg(INFO, "data:0x%02x\n", data); | 255 | brcmf_dbg(INFO, "data:0x%02x\n", data); |
254 | 256 | ||
255 | if (ret) | 257 | if (ret) |
@@ -264,7 +266,9 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) | |||
264 | int retval; | 266 | int retval; |
265 | 267 | ||
266 | brcmf_dbg(INFO, "addr:0x%08x\n", addr); | 268 | brcmf_dbg(INFO, "addr:0x%08x\n", addr); |
269 | sdio_claim_host(sdiodev->func[1]); | ||
267 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); | 270 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); |
271 | sdio_release_host(sdiodev->func[1]); | ||
268 | brcmf_dbg(INFO, "data:0x%08x\n", data); | 272 | brcmf_dbg(INFO, "data:0x%08x\n", data); |
269 | 273 | ||
270 | if (ret) | 274 | if (ret) |
@@ -279,7 +283,9 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, | |||
279 | int retval; | 283 | int retval; |
280 | 284 | ||
281 | brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data); | 285 | brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data); |
286 | sdio_claim_host(sdiodev->func[1]); | ||
282 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); | 287 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); |
288 | sdio_release_host(sdiodev->func[1]); | ||
283 | 289 | ||
284 | if (ret) | 290 | if (ret) |
285 | *ret = retval; | 291 | *ret = retval; |
@@ -291,7 +297,9 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, | |||
291 | int retval; | 297 | int retval; |
292 | 298 | ||
293 | brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data); | 299 | brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data); |
300 | sdio_claim_host(sdiodev->func[1]); | ||
294 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); | 301 | retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); |
302 | sdio_release_host(sdiodev->func[1]); | ||
295 | 303 | ||
296 | if (ret) | 304 | if (ret) |
297 | *ret = retval; | 305 | *ret = retval; |
@@ -356,15 +364,20 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
356 | brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", | 364 | brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", |
357 | fn, addr, pkt->len); | 365 | fn, addr, pkt->len); |
358 | 366 | ||
367 | sdio_claim_host(sdiodev->func[1]); | ||
368 | |||
359 | width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; | 369 | width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; |
360 | err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); | 370 | err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); |
361 | if (err) | 371 | if (err) |
362 | return err; | 372 | goto done; |
363 | 373 | ||
364 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; | 374 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; |
365 | err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, | 375 | err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, |
366 | fn, addr, pkt); | 376 | fn, addr, pkt); |
367 | 377 | ||
378 | done: | ||
379 | sdio_release_host(sdiodev->func[1]); | ||
380 | |||
368 | return err; | 381 | return err; |
369 | } | 382 | } |
370 | 383 | ||
@@ -378,15 +391,20 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
378 | brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", | 391 | brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", |
379 | fn, addr, pktq->qlen); | 392 | fn, addr, pktq->qlen); |
380 | 393 | ||
394 | sdio_claim_host(sdiodev->func[1]); | ||
395 | |||
381 | width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; | 396 | width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; |
382 | err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); | 397 | err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr); |
383 | if (err) | 398 | if (err) |
384 | return err; | 399 | goto done; |
385 | 400 | ||
386 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; | 401 | incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; |
387 | err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr, | 402 | err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr, |
388 | pktq); | 403 | pktq); |
389 | 404 | ||
405 | done: | ||
406 | sdio_release_host(sdiodev->func[1]); | ||
407 | |||
390 | return err; | 408 | return err; |
391 | } | 409 | } |
392 | 410 | ||
@@ -428,10 +446,12 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
428 | if (flags & SDIO_REQ_ASYNC) | 446 | if (flags & SDIO_REQ_ASYNC) |
429 | return -ENOTSUPP; | 447 | return -ENOTSUPP; |
430 | 448 | ||
449 | sdio_claim_host(sdiodev->func[1]); | ||
450 | |||
431 | if (bar0 != sdiodev->sbwad) { | 451 | if (bar0 != sdiodev->sbwad) { |
432 | err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); | 452 | err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); |
433 | if (err) | 453 | if (err) |
434 | return err; | 454 | goto done; |
435 | 455 | ||
436 | sdiodev->sbwad = bar0; | 456 | sdiodev->sbwad = bar0; |
437 | } | 457 | } |
@@ -443,8 +463,13 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, | |||
443 | if (width == 4) | 463 | if (width == 4) |
444 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; | 464 | addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; |
445 | 465 | ||
446 | return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, | 466 | err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, |
447 | addr, pkt); | 467 | addr, pkt); |
468 | |||
469 | done: | ||
470 | sdio_release_host(sdiodev->func[1]); | ||
471 | |||
472 | return err; | ||
448 | } | 473 | } |
449 | 474 | ||
450 | int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, | 475 | int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, |
@@ -485,8 +510,10 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) | |||
485 | brcmf_dbg(TRACE, "Enter\n"); | 510 | brcmf_dbg(TRACE, "Enter\n"); |
486 | 511 | ||
487 | /* issue abort cmd52 command through F0 */ | 512 | /* issue abort cmd52 command through F0 */ |
513 | sdio_claim_host(sdiodev->func[1]); | ||
488 | brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, | 514 | brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, |
489 | SDIO_CCCR_ABORT, &t_func); | 515 | SDIO_CCCR_ABORT, &t_func); |
516 | sdio_release_host(sdiodev->func[1]); | ||
490 | 517 | ||
491 | brcmf_dbg(TRACE, "Exit\n"); | 518 | brcmf_dbg(TRACE, "Exit\n"); |
492 | return 0; | 519 | return 0; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 372f74eac1e7..c3247d5b3c22 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | |||
@@ -103,7 +103,6 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, | |||
103 | if (regaddr == SDIO_CCCR_IOEx) { | 103 | if (regaddr == SDIO_CCCR_IOEx) { |
104 | sdfunc = sdiodev->func[2]; | 104 | sdfunc = sdiodev->func[2]; |
105 | if (sdfunc) { | 105 | if (sdfunc) { |
106 | sdio_claim_host(sdfunc); | ||
107 | if (*byte & SDIO_FUNC_ENABLE_2) { | 106 | if (*byte & SDIO_FUNC_ENABLE_2) { |
108 | /* Enable Function 2 */ | 107 | /* Enable Function 2 */ |
109 | err_ret = sdio_enable_func(sdfunc); | 108 | err_ret = sdio_enable_func(sdfunc); |
@@ -119,7 +118,6 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, | |||
119 | "Disable F2 failed:%d\n", | 118 | "Disable F2 failed:%d\n", |
120 | err_ret); | 119 | err_ret); |
121 | } | 120 | } |
122 | sdio_release_host(sdfunc); | ||
123 | } | 121 | } |
124 | } else if ((regaddr == SDIO_CCCR_ABORT) || | 122 | } else if ((regaddr == SDIO_CCCR_ABORT) || |
125 | (regaddr == SDIO_CCCR_IENx)) { | 123 | (regaddr == SDIO_CCCR_IENx)) { |
@@ -128,17 +126,13 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, | |||
128 | if (!sdfunc) | 126 | if (!sdfunc) |
129 | return -ENOMEM; | 127 | return -ENOMEM; |
130 | sdfunc->num = 0; | 128 | sdfunc->num = 0; |
131 | sdio_claim_host(sdfunc); | ||
132 | sdio_writeb(sdfunc, *byte, regaddr, &err_ret); | 129 | sdio_writeb(sdfunc, *byte, regaddr, &err_ret); |
133 | sdio_release_host(sdfunc); | ||
134 | kfree(sdfunc); | 130 | kfree(sdfunc); |
135 | } else if (regaddr < 0xF0) { | 131 | } else if (regaddr < 0xF0) { |
136 | brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); | 132 | brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); |
137 | err_ret = -EPERM; | 133 | err_ret = -EPERM; |
138 | } else { | 134 | } else { |
139 | sdio_claim_host(sdfunc); | ||
140 | sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); | 135 | sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); |
141 | sdio_release_host(sdfunc); | ||
142 | } | 136 | } |
143 | 137 | ||
144 | return err_ret; | 138 | return err_ret; |
@@ -159,7 +153,6 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, | |||
159 | /* handle F0 separately */ | 153 | /* handle F0 separately */ |
160 | err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); | 154 | err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); |
161 | } else { | 155 | } else { |
162 | sdio_claim_host(sdiodev->func[func]); | ||
163 | if (rw) /* CMD52 Write */ | 156 | if (rw) /* CMD52 Write */ |
164 | sdio_writeb(sdiodev->func[func], *byte, regaddr, | 157 | sdio_writeb(sdiodev->func[func], *byte, regaddr, |
165 | &err_ret); | 158 | &err_ret); |
@@ -170,7 +163,6 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, | |||
170 | *byte = sdio_readb(sdiodev->func[func], regaddr, | 163 | *byte = sdio_readb(sdiodev->func[func], regaddr, |
171 | &err_ret); | 164 | &err_ret); |
172 | } | 165 | } |
173 | sdio_release_host(sdiodev->func[func]); | ||
174 | } | 166 | } |
175 | 167 | ||
176 | if (err_ret) | 168 | if (err_ret) |
@@ -197,8 +189,6 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, | |||
197 | brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); | 189 | brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); |
198 | if (brcmf_pm_resume_error(sdiodev)) | 190 | if (brcmf_pm_resume_error(sdiodev)) |
199 | return -EIO; | 191 | return -EIO; |
200 | /* Claim host controller */ | ||
201 | sdio_claim_host(sdiodev->func[func]); | ||
202 | 192 | ||
203 | if (rw) { /* CMD52 Write */ | 193 | if (rw) { /* CMD52 Write */ |
204 | if (nbytes == 4) | 194 | if (nbytes == 4) |
@@ -219,9 +209,6 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, | |||
219 | brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); | 209 | brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); |
220 | } | 210 | } |
221 | 211 | ||
222 | /* Release host controller */ | ||
223 | sdio_release_host(sdiodev->func[func]); | ||
224 | |||
225 | if (err_ret) | 212 | if (err_ret) |
226 | brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", | 213 | brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", |
227 | rw ? "write" : "read", err_ret); | 214 | rw ? "write" : "read", err_ret); |
@@ -275,9 +262,6 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, | |||
275 | if (brcmf_pm_resume_error(sdiodev)) | 262 | if (brcmf_pm_resume_error(sdiodev)) |
276 | return -EIO; | 263 | return -EIO; |
277 | 264 | ||
278 | /* Claim host controller */ | ||
279 | sdio_claim_host(sdiodev->func[func]); | ||
280 | |||
281 | skb_queue_walk(pktq, pkt) { | 265 | skb_queue_walk(pktq, pkt) { |
282 | uint pkt_len = pkt->len; | 266 | uint pkt_len = pkt->len; |
283 | pkt_len += 3; | 267 | pkt_len += 3; |
@@ -300,9 +284,6 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, | |||
300 | SGCount++; | 284 | SGCount++; |
301 | } | 285 | } |
302 | 286 | ||
303 | /* Release host controller */ | ||
304 | sdio_release_host(sdiodev->func[func]); | ||
305 | |||
306 | brcmf_dbg(TRACE, "Exit\n"); | 287 | brcmf_dbg(TRACE, "Exit\n"); |
307 | return err_ret; | 288 | return err_ret; |
308 | } | 289 | } |
@@ -328,9 +309,6 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, | |||
328 | if (brcmf_pm_resume_error(sdiodev)) | 309 | if (brcmf_pm_resume_error(sdiodev)) |
329 | return -EIO; | 310 | return -EIO; |
330 | 311 | ||
331 | /* Claim host controller */ | ||
332 | sdio_claim_host(sdiodev->func[func]); | ||
333 | |||
334 | pkt_len += 3; | 312 | pkt_len += 3; |
335 | pkt_len &= (uint)~3; | 313 | pkt_len &= (uint)~3; |
336 | 314 | ||
@@ -344,9 +322,6 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, | |||
344 | write ? "TX" : "RX", pkt, addr, pkt_len); | 322 | write ? "TX" : "RX", pkt, addr, pkt_len); |
345 | } | 323 | } |
346 | 324 | ||
347 | /* Release host controller */ | ||
348 | sdio_release_host(sdiodev->func[func]); | ||
349 | |||
350 | return status; | 325 | return status; |
351 | } | 326 | } |
352 | 327 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 4766d9f35696..55e489d2147d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h | |||
@@ -682,10 +682,6 @@ extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx, | |||
682 | 682 | ||
683 | extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); | 683 | extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); |
684 | 684 | ||
685 | /* Send packet to dongle via data channel */ | ||
686 | extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\ | ||
687 | struct sk_buff *pkt); | ||
688 | |||
689 | extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); | 685 | extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); |
690 | extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, | 686 | extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, |
691 | int enable, int master_mode); | 687 | int enable, int master_mode); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 8121dbabbff6..aa4f719a51a9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | |||
@@ -80,8 +80,10 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) | |||
80 | strncpy(buf, name, buflen); | 80 | strncpy(buf, name, buflen); |
81 | 81 | ||
82 | /* append data onto the end of the name string */ | 82 | /* append data onto the end of the name string */ |
83 | memcpy(&buf[len], data, datalen); | 83 | if (data && datalen) { |
84 | len += datalen; | 84 | memcpy(&buf[len], data, datalen); |
85 | len += datalen; | ||
86 | } | ||
85 | 87 | ||
86 | return len; | 88 | return len; |
87 | } | 89 | } |
@@ -431,13 +433,7 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) | |||
431 | } | 433 | } |
432 | 434 | ||
433 | /* show any appended data */ | 435 | /* show any appended data */ |
434 | if (datalen) { | 436 | brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data"); |
435 | buf = (unsigned char *) event_data; | ||
436 | brcmf_dbg(EVENT, " data (%d) : ", datalen); | ||
437 | for (i = 0; i < datalen; i++) | ||
438 | brcmf_dbg(EVENT, " 0x%02x ", *buf++); | ||
439 | brcmf_dbg(EVENT, "\n"); | ||
440 | } | ||
441 | } | 437 | } |
442 | #endif /* DEBUG */ | 438 | #endif /* DEBUG */ |
443 | 439 | ||
@@ -528,8 +524,9 @@ brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata, | |||
528 | } | 524 | } |
529 | 525 | ||
530 | #ifdef DEBUG | 526 | #ifdef DEBUG |
531 | brcmf_c_show_host_event(event, event_data); | 527 | if (BRCMF_EVENT_ON()) |
532 | #endif /* DEBUG */ | 528 | brcmf_c_show_host_event(event, event_data); |
529 | #endif /* DEBUG */ | ||
533 | 530 | ||
534 | return 0; | 531 | return 0; |
535 | } | 532 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index b784920532d3..fb508c2256dd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | |||
@@ -55,6 +55,7 @@ do { \ | |||
55 | #define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) | 55 | #define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) |
56 | #define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) | 56 | #define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) |
57 | #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) | 57 | #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) |
58 | #define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL) | ||
58 | 59 | ||
59 | #else /* (defined DEBUG) || (defined DEBUG) */ | 60 | #else /* (defined DEBUG) || (defined DEBUG) */ |
60 | 61 | ||
@@ -65,6 +66,7 @@ do { \ | |||
65 | #define BRCMF_HDRS_ON() 0 | 66 | #define BRCMF_HDRS_ON() 0 |
66 | #define BRCMF_BYTES_ON() 0 | 67 | #define BRCMF_BYTES_ON() 0 |
67 | #define BRCMF_GLOM_ON() 0 | 68 | #define BRCMF_GLOM_ON() 0 |
69 | #define BRCMF_EVENT_ON() 0 | ||
68 | 70 | ||
69 | #endif /* defined(DEBUG) */ | 71 | #endif /* defined(DEBUG) */ |
70 | 72 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index b08f3474d8e7..d7c76ce9d8cb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -272,30 +272,6 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev) | |||
272 | schedule_work(&drvr->multicast_work); | 272 | schedule_work(&drvr->multicast_work); |
273 | } | 273 | } |
274 | 274 | ||
275 | int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) | ||
276 | { | ||
277 | /* Reject if down */ | ||
278 | if (!drvr->bus_if->drvr_up || (drvr->bus_if->state == BRCMF_BUS_DOWN)) | ||
279 | return -ENODEV; | ||
280 | |||
281 | /* Update multicast statistic */ | ||
282 | if (pktbuf->len >= ETH_ALEN) { | ||
283 | u8 *pktdata = (u8 *) (pktbuf->data); | ||
284 | struct ethhdr *eh = (struct ethhdr *)pktdata; | ||
285 | |||
286 | if (is_multicast_ether_addr(eh->h_dest)) | ||
287 | drvr->tx_multicast++; | ||
288 | if (ntohs(eh->h_proto) == ETH_P_PAE) | ||
289 | atomic_inc(&drvr->pend_8021x_cnt); | ||
290 | } | ||
291 | |||
292 | /* If the protocol uses a data header, apply it */ | ||
293 | brcmf_proto_hdrpush(drvr, ifidx, pktbuf); | ||
294 | |||
295 | /* Use bus module to send data frame */ | ||
296 | return drvr->bus_if->brcmf_bus_txdata(drvr->dev, pktbuf); | ||
297 | } | ||
298 | |||
299 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | 275 | static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
300 | { | 276 | { |
301 | int ret; | 277 | int ret; |
@@ -338,7 +314,22 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
338 | } | 314 | } |
339 | } | 315 | } |
340 | 316 | ||
341 | ret = brcmf_sendpkt(drvr, ifp->idx, skb); | 317 | /* Update multicast statistic */ |
318 | if (skb->len >= ETH_ALEN) { | ||
319 | u8 *pktdata = (u8 *)(skb->data); | ||
320 | struct ethhdr *eh = (struct ethhdr *)pktdata; | ||
321 | |||
322 | if (is_multicast_ether_addr(eh->h_dest)) | ||
323 | drvr->tx_multicast++; | ||
324 | if (ntohs(eh->h_proto) == ETH_P_PAE) | ||
325 | atomic_inc(&drvr->pend_8021x_cnt); | ||
326 | } | ||
327 | |||
328 | /* If the protocol uses a data header, apply it */ | ||
329 | brcmf_proto_hdrpush(drvr, ifp->idx, skb); | ||
330 | |||
331 | /* Use bus module to send data frame */ | ||
332 | ret = drvr->bus_if->brcmf_bus_txdata(drvr->dev, skb); | ||
342 | 333 | ||
343 | done: | 334 | done: |
344 | if (ret) | 335 | if (ret) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 4580ff34c2d0..3564686add9a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |||
@@ -482,6 +482,15 @@ struct sdpcm_shared_le { | |||
482 | __le32 brpt_addr; | 482 | __le32 brpt_addr; |
483 | }; | 483 | }; |
484 | 484 | ||
485 | /* SDIO read frame info */ | ||
486 | struct brcmf_sdio_read { | ||
487 | u8 seq_num; | ||
488 | u8 channel; | ||
489 | u16 len; | ||
490 | u16 len_left; | ||
491 | u16 len_nxtfrm; | ||
492 | u8 dat_offset; | ||
493 | }; | ||
485 | 494 | ||
486 | /* misc chip info needed by some of the routines */ | 495 | /* misc chip info needed by some of the routines */ |
487 | /* Private data for SDIO bus interaction */ | 496 | /* Private data for SDIO bus interaction */ |
@@ -494,9 +503,8 @@ struct brcmf_sdio { | |||
494 | u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ | 503 | u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ |
495 | 504 | ||
496 | u32 hostintmask; /* Copy of Host Interrupt Mask */ | 505 | u32 hostintmask; /* Copy of Host Interrupt Mask */ |
497 | u32 intstatus; /* Intstatus bits (events) pending */ | 506 | atomic_t intstatus; /* Intstatus bits (events) pending */ |
498 | bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ | 507 | atomic_t fcstate; /* State of dongle flow-control */ |
499 | bool fcstate; /* State of dongle flow-control */ | ||
500 | 508 | ||
501 | uint blocksize; /* Block size of SDIO transfers */ | 509 | uint blocksize; /* Block size of SDIO transfers */ |
502 | uint roundup; /* Max roundup limit */ | 510 | uint roundup; /* Max roundup limit */ |
@@ -508,9 +516,11 @@ struct brcmf_sdio { | |||
508 | 516 | ||
509 | u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; | 517 | u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; |
510 | u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ | 518 | u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ |
511 | u16 nextlen; /* Next Read Len from last header */ | ||
512 | u8 rx_seq; /* Receive sequence number (expected) */ | 519 | u8 rx_seq; /* Receive sequence number (expected) */ |
520 | struct brcmf_sdio_read cur_read; | ||
521 | /* info of current read frame */ | ||
513 | bool rxskip; /* Skip receive (awaiting NAK ACK) */ | 522 | bool rxskip; /* Skip receive (awaiting NAK ACK) */ |
523 | bool rxpending; /* Data frame pending in dongle */ | ||
514 | 524 | ||
515 | uint rxbound; /* Rx frames to read before resched */ | 525 | uint rxbound; /* Rx frames to read before resched */ |
516 | uint txbound; /* Tx frames to send before resched */ | 526 | uint txbound; /* Tx frames to send before resched */ |
@@ -531,7 +541,7 @@ struct brcmf_sdio { | |||
531 | 541 | ||
532 | bool intr; /* Use interrupts */ | 542 | bool intr; /* Use interrupts */ |
533 | bool poll; /* Use polling */ | 543 | bool poll; /* Use polling */ |
534 | bool ipend; /* Device interrupt is pending */ | 544 | atomic_t ipend; /* Device interrupt is pending */ |
535 | uint spurious; /* Count of spurious interrupts */ | 545 | uint spurious; /* Count of spurious interrupts */ |
536 | uint pollrate; /* Ticks between device polls */ | 546 | uint pollrate; /* Ticks between device polls */ |
537 | uint polltick; /* Tick counter */ | 547 | uint polltick; /* Tick counter */ |
@@ -549,12 +559,9 @@ struct brcmf_sdio { | |||
549 | s32 idleclock; /* How to set bus driver when idle */ | 559 | s32 idleclock; /* How to set bus driver when idle */ |
550 | s32 sd_rxchain; | 560 | s32 sd_rxchain; |
551 | bool use_rxchain; /* If brcmf should use PKT chains */ | 561 | bool use_rxchain; /* If brcmf should use PKT chains */ |
552 | bool sleeping; /* Is SDIO bus sleeping? */ | ||
553 | bool rxflow_mode; /* Rx flow control mode */ | 562 | bool rxflow_mode; /* Rx flow control mode */ |
554 | bool rxflow; /* Is rx flow control on */ | 563 | bool rxflow; /* Is rx flow control on */ |
555 | bool alp_only; /* Don't use HT clock (ALP only) */ | 564 | bool alp_only; /* Don't use HT clock (ALP only) */ |
556 | /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ | ||
557 | bool usebufpool; | ||
558 | 565 | ||
559 | u8 *ctrl_frame_buf; | 566 | u8 *ctrl_frame_buf; |
560 | u32 ctrl_frame_len; | 567 | u32 ctrl_frame_len; |
@@ -570,8 +577,8 @@ struct brcmf_sdio { | |||
570 | bool wd_timer_valid; | 577 | bool wd_timer_valid; |
571 | uint save_ms; | 578 | uint save_ms; |
572 | 579 | ||
573 | struct task_struct *dpc_tsk; | 580 | struct workqueue_struct *brcmf_wq; |
574 | struct completion dpc_wait; | 581 | struct work_struct datawork; |
575 | struct list_head dpc_tsklst; | 582 | struct list_head dpc_tsklst; |
576 | spinlock_t dpc_tl_lock; | 583 | spinlock_t dpc_tl_lock; |
577 | 584 | ||
@@ -657,15 +664,6 @@ w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset) | |||
657 | 664 | ||
658 | #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) | 665 | #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) |
659 | 666 | ||
660 | /* Packet free applicable unconditionally for sdio and sdspi. | ||
661 | * Conditional if bufpool was present for gspi bus. | ||
662 | */ | ||
663 | static void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt) | ||
664 | { | ||
665 | if (bus->usebufpool) | ||
666 | brcmu_pkt_buf_free_skb(pkt); | ||
667 | } | ||
668 | |||
669 | /* Turn backplane clock on or off */ | 667 | /* Turn backplane clock on or off */ |
670 | static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) | 668 | static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) |
671 | { | 669 | { |
@@ -853,81 +851,6 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) | |||
853 | return 0; | 851 | return 0; |
854 | } | 852 | } |
855 | 853 | ||
856 | static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) | ||
857 | { | ||
858 | int ret; | ||
859 | |||
860 | brcmf_dbg(INFO, "request %s (currently %s)\n", | ||
861 | sleep ? "SLEEP" : "WAKE", | ||
862 | bus->sleeping ? "SLEEP" : "WAKE"); | ||
863 | |||
864 | /* Done if we're already in the requested state */ | ||
865 | if (sleep == bus->sleeping) | ||
866 | return 0; | ||
867 | |||
868 | /* Going to sleep: set the alarm and turn off the lights... */ | ||
869 | if (sleep) { | ||
870 | /* Don't sleep if something is pending */ | ||
871 | if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) | ||
872 | return -EBUSY; | ||
873 | |||
874 | /* Make sure the controller has the bus up */ | ||
875 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
876 | |||
877 | /* Tell device to start using OOB wakeup */ | ||
878 | ret = w_sdreg32(bus, SMB_USE_OOB, | ||
879 | offsetof(struct sdpcmd_regs, tosbmailbox)); | ||
880 | if (ret != 0) | ||
881 | brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); | ||
882 | |||
883 | /* Turn off our contribution to the HT clock request */ | ||
884 | brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); | ||
885 | |||
886 | brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, | ||
887 | SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); | ||
888 | |||
889 | /* Isolate the bus */ | ||
890 | brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, | ||
891 | SBSDIO_DEVCTL_PADS_ISO, NULL); | ||
892 | |||
893 | /* Change state */ | ||
894 | bus->sleeping = true; | ||
895 | |||
896 | } else { | ||
897 | /* Waking up: bus power up is ok, set local state */ | ||
898 | |||
899 | brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, | ||
900 | 0, NULL); | ||
901 | |||
902 | /* Make sure the controller has the bus up */ | ||
903 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
904 | |||
905 | /* Send misc interrupt to indicate OOB not needed */ | ||
906 | ret = w_sdreg32(bus, 0, | ||
907 | offsetof(struct sdpcmd_regs, tosbmailboxdata)); | ||
908 | if (ret == 0) | ||
909 | ret = w_sdreg32(bus, SMB_DEV_INT, | ||
910 | offsetof(struct sdpcmd_regs, tosbmailbox)); | ||
911 | |||
912 | if (ret != 0) | ||
913 | brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); | ||
914 | |||
915 | /* Make sure we have SD bus access */ | ||
916 | brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); | ||
917 | |||
918 | /* Change state */ | ||
919 | bus->sleeping = false; | ||
920 | } | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static void bus_wake(struct brcmf_sdio *bus) | ||
926 | { | ||
927 | if (bus->sleeping) | ||
928 | brcmf_sdbrcm_bussleep(bus, false); | ||
929 | } | ||
930 | |||
931 | static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) | 854 | static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) |
932 | { | 855 | { |
933 | u32 intstatus = 0; | 856 | u32 intstatus = 0; |
@@ -1056,7 +979,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) | |||
1056 | } | 979 | } |
1057 | 980 | ||
1058 | /* Clear partial in any case */ | 981 | /* Clear partial in any case */ |
1059 | bus->nextlen = 0; | 982 | bus->cur_read.len = 0; |
1060 | 983 | ||
1061 | /* If we can't reach the device, signal failure */ | 984 | /* If we can't reach the device, signal failure */ |
1062 | if (err) | 985 | if (err) |
@@ -1108,6 +1031,96 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) | |||
1108 | } | 1031 | } |
1109 | } | 1032 | } |
1110 | 1033 | ||
1034 | static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, | ||
1035 | struct brcmf_sdio_read *rd) | ||
1036 | { | ||
1037 | u16 len, checksum; | ||
1038 | u8 rx_seq, fc, tx_seq_max; | ||
1039 | |||
1040 | /* | ||
1041 | * 4 bytes hardware header (frame tag) | ||
1042 | * Byte 0~1: Frame length | ||
1043 | * Byte 2~3: Checksum, bit-wise inverse of frame length | ||
1044 | */ | ||
1045 | len = get_unaligned_le16(header); | ||
1046 | checksum = get_unaligned_le16(header + sizeof(u16)); | ||
1047 | /* All zero means no more to read */ | ||
1048 | if (!(len | checksum)) { | ||
1049 | bus->rxpending = false; | ||
1050 | return false; | ||
1051 | } | ||
1052 | if ((u16)(~(len ^ checksum))) { | ||
1053 | brcmf_dbg(ERROR, "HW header checksum error\n"); | ||
1054 | bus->sdcnt.rx_badhdr++; | ||
1055 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1056 | return false; | ||
1057 | } | ||
1058 | if (len < SDPCM_HDRLEN) { | ||
1059 | brcmf_dbg(ERROR, "HW header length error\n"); | ||
1060 | return false; | ||
1061 | } | ||
1062 | rd->len = len; | ||
1063 | |||
1064 | /* | ||
1065 | * 8 bytes hardware header | ||
1066 | * Byte 0: Rx sequence number | ||
1067 | * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag | ||
1068 | * Byte 2: Length of next data frame | ||
1069 | * Byte 3: Data offset | ||
1070 | * Byte 4: Flow control bits | ||
1071 | * Byte 5: Maximum Sequence number allow for Tx | ||
1072 | * Byte 6~7: Reserved | ||
1073 | */ | ||
1074 | rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]); | ||
1075 | rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); | ||
1076 | if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL) { | ||
1077 | brcmf_dbg(ERROR, "HW header length too long\n"); | ||
1078 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1079 | bus->sdcnt.rx_toolong++; | ||
1080 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1081 | rd->len = 0; | ||
1082 | return false; | ||
1083 | } | ||
1084 | rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]); | ||
1085 | if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { | ||
1086 | brcmf_dbg(ERROR, "seq %d: bad data offset\n", rx_seq); | ||
1087 | bus->sdcnt.rx_badhdr++; | ||
1088 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1089 | rd->len = 0; | ||
1090 | return false; | ||
1091 | } | ||
1092 | if (rd->seq_num != rx_seq) { | ||
1093 | brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n", | ||
1094 | rx_seq, rd->seq_num); | ||
1095 | bus->sdcnt.rx_badseq++; | ||
1096 | rd->seq_num = rx_seq; | ||
1097 | } | ||
1098 | rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; | ||
1099 | if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) { | ||
1100 | /* only warm for NON glom packet */ | ||
1101 | if (rd->channel != SDPCM_GLOM_CHANNEL) | ||
1102 | brcmf_dbg(ERROR, "seq %d: next length error\n", rx_seq); | ||
1103 | rd->len_nxtfrm = 0; | ||
1104 | } | ||
1105 | fc = SDPCM_FCMASK_VALUE(&header[SDPCM_FRAMETAG_LEN]); | ||
1106 | if (bus->flowcontrol != fc) { | ||
1107 | if (~bus->flowcontrol & fc) | ||
1108 | bus->sdcnt.fc_xoff++; | ||
1109 | if (bus->flowcontrol & ~fc) | ||
1110 | bus->sdcnt.fc_xon++; | ||
1111 | bus->sdcnt.fc_rcvd++; | ||
1112 | bus->flowcontrol = fc; | ||
1113 | } | ||
1114 | tx_seq_max = SDPCM_WINDOW_VALUE(&header[SDPCM_FRAMETAG_LEN]); | ||
1115 | if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) { | ||
1116 | brcmf_dbg(ERROR, "seq %d: max tx seq number error\n", rx_seq); | ||
1117 | tx_seq_max = bus->tx_seq + 2; | ||
1118 | } | ||
1119 | bus->tx_max = tx_seq_max; | ||
1120 | |||
1121 | return true; | ||
1122 | } | ||
1123 | |||
1111 | static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | 1124 | static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) |
1112 | { | 1125 | { |
1113 | u16 dlen, totlen; | 1126 | u16 dlen, totlen; |
@@ -1122,6 +1135,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1122 | 1135 | ||
1123 | int ifidx = 0; | 1136 | int ifidx = 0; |
1124 | bool usechain = bus->use_rxchain; | 1137 | bool usechain = bus->use_rxchain; |
1138 | u16 next_len; | ||
1125 | 1139 | ||
1126 | /* If packets, issue read(s) and send up packet chain */ | 1140 | /* If packets, issue read(s) and send up packet chain */ |
1127 | /* Return sequence numbers consumed? */ | 1141 | /* Return sequence numbers consumed? */ |
@@ -1185,10 +1199,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1185 | if (pnext) { | 1199 | if (pnext) { |
1186 | brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", | 1200 | brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", |
1187 | totlen, num); | 1201 | totlen, num); |
1188 | if (BRCMF_GLOM_ON() && bus->nextlen && | 1202 | if (BRCMF_GLOM_ON() && bus->cur_read.len && |
1189 | totlen != bus->nextlen) { | 1203 | totlen != bus->cur_read.len) { |
1190 | brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", | 1204 | brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", |
1191 | bus->nextlen, totlen, rxseq); | 1205 | bus->cur_read.len, totlen, rxseq); |
1192 | } | 1206 | } |
1193 | pfirst = pnext = NULL; | 1207 | pfirst = pnext = NULL; |
1194 | } else { | 1208 | } else { |
@@ -1199,7 +1213,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1199 | /* Done with descriptor packet */ | 1213 | /* Done with descriptor packet */ |
1200 | brcmu_pkt_buf_free_skb(bus->glomd); | 1214 | brcmu_pkt_buf_free_skb(bus->glomd); |
1201 | bus->glomd = NULL; | 1215 | bus->glomd = NULL; |
1202 | bus->nextlen = 0; | 1216 | bus->cur_read.len = 0; |
1203 | } | 1217 | } |
1204 | 1218 | ||
1205 | /* Ok -- either we just generated a packet chain, | 1219 | /* Ok -- either we just generated a packet chain, |
@@ -1272,12 +1286,13 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1272 | 1286 | ||
1273 | chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); | 1287 | chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); |
1274 | seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); | 1288 | seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); |
1275 | bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; | 1289 | next_len = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; |
1276 | if ((bus->nextlen << 4) > MAX_RX_DATASZ) { | 1290 | if ((next_len << 4) > MAX_RX_DATASZ) { |
1277 | brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", | 1291 | brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", |
1278 | bus->nextlen, seq); | 1292 | next_len, seq); |
1279 | bus->nextlen = 0; | 1293 | next_len = 0; |
1280 | } | 1294 | } |
1295 | bus->cur_read.len = next_len << 4; | ||
1281 | doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); | 1296 | doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); |
1282 | txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); | 1297 | txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); |
1283 | 1298 | ||
@@ -1378,7 +1393,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1378 | bus->sdcnt.rxglomfail++; | 1393 | bus->sdcnt.rxglomfail++; |
1379 | brcmf_sdbrcm_free_glom(bus); | 1394 | brcmf_sdbrcm_free_glom(bus); |
1380 | } | 1395 | } |
1381 | bus->nextlen = 0; | 1396 | bus->cur_read.len = 0; |
1382 | return 0; | 1397 | return 0; |
1383 | } | 1398 | } |
1384 | 1399 | ||
@@ -1573,422 +1588,166 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) | |||
1573 | } | 1588 | } |
1574 | } | 1589 | } |
1575 | 1590 | ||
1576 | static void | 1591 | static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) |
1577 | brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen, | ||
1578 | struct sk_buff **pkt, u8 **rxbuf) | ||
1579 | { | 1592 | { |
1580 | int sdret; /* Return code from calls */ | ||
1581 | |||
1582 | *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); | ||
1583 | if (*pkt == NULL) | ||
1584 | return; | ||
1585 | |||
1586 | pkt_align(*pkt, rdlen, BRCMF_SDALIGN); | ||
1587 | *rxbuf = (u8 *) ((*pkt)->data); | ||
1588 | /* Read the entire frame */ | ||
1589 | sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, | ||
1590 | SDIO_FUNC_2, F2SYNC, *pkt); | ||
1591 | bus->sdcnt.f2rxdata++; | ||
1592 | |||
1593 | if (sdret < 0) { | ||
1594 | brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", | ||
1595 | rdlen, sdret); | ||
1596 | brcmu_pkt_buf_free_skb(*pkt); | ||
1597 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1598 | /* Force retry w/normal header read. | ||
1599 | * Don't attempt NAK for | ||
1600 | * gSPI | ||
1601 | */ | ||
1602 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
1603 | *pkt = NULL; | ||
1604 | } | ||
1605 | } | ||
1606 | |||
1607 | /* Checks the header */ | ||
1608 | static int | ||
1609 | brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf, | ||
1610 | u8 rxseq, u16 nextlen, u16 *len) | ||
1611 | { | ||
1612 | u16 check; | ||
1613 | bool len_consistent; /* Result of comparing readahead len and | ||
1614 | len from hw-hdr */ | ||
1615 | |||
1616 | memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); | ||
1617 | |||
1618 | /* Extract hardware header fields */ | ||
1619 | *len = get_unaligned_le16(bus->rxhdr); | ||
1620 | check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); | ||
1621 | |||
1622 | /* All zeros means readahead info was bad */ | ||
1623 | if (!(*len | check)) { | ||
1624 | brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n"); | ||
1625 | goto fail; | ||
1626 | } | ||
1627 | |||
1628 | /* Validate check bytes */ | ||
1629 | if ((u16)~(*len ^ check)) { | ||
1630 | brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", | ||
1631 | nextlen, *len, check); | ||
1632 | bus->sdcnt.rx_badhdr++; | ||
1633 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1634 | goto fail; | ||
1635 | } | ||
1636 | |||
1637 | /* Validate frame length */ | ||
1638 | if (*len < SDPCM_HDRLEN) { | ||
1639 | brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n", | ||
1640 | *len); | ||
1641 | goto fail; | ||
1642 | } | ||
1643 | |||
1644 | /* Check for consistency with readahead info */ | ||
1645 | len_consistent = (nextlen != (roundup(*len, 16) >> 4)); | ||
1646 | if (len_consistent) { | ||
1647 | /* Mismatch, force retry w/normal | ||
1648 | header (may be >4K) */ | ||
1649 | brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n", | ||
1650 | nextlen, *len, roundup(*len, 16), | ||
1651 | rxseq); | ||
1652 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
1653 | goto fail; | ||
1654 | } | ||
1655 | |||
1656 | return 0; | ||
1657 | |||
1658 | fail: | ||
1659 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
1660 | return -EINVAL; | ||
1661 | } | ||
1662 | |||
1663 | /* Return true if there may be more frames to read */ | ||
1664 | static uint | ||
1665 | brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) | ||
1666 | { | ||
1667 | u16 len, check; /* Extracted hardware header fields */ | ||
1668 | u8 chan, seq, doff; /* Extracted software header fields */ | ||
1669 | u8 fcbits; /* Extracted fcbits from software header */ | ||
1670 | |||
1671 | struct sk_buff *pkt; /* Packet for event or data frames */ | 1593 | struct sk_buff *pkt; /* Packet for event or data frames */ |
1672 | u16 pad; /* Number of pad bytes to read */ | 1594 | u16 pad; /* Number of pad bytes to read */ |
1673 | u16 rdlen; /* Total number of bytes to read */ | ||
1674 | u8 rxseq; /* Next sequence number to expect */ | ||
1675 | uint rxleft = 0; /* Remaining number of frames allowed */ | 1595 | uint rxleft = 0; /* Remaining number of frames allowed */ |
1676 | int sdret; /* Return code from calls */ | 1596 | int sdret; /* Return code from calls */ |
1677 | u8 txmax; /* Maximum tx sequence offered */ | ||
1678 | u8 *rxbuf; | ||
1679 | int ifidx = 0; | 1597 | int ifidx = 0; |
1680 | uint rxcount = 0; /* Total frames read */ | 1598 | uint rxcount = 0; /* Total frames read */ |
1599 | struct brcmf_sdio_read *rd = &bus->cur_read, rd_new; | ||
1600 | u8 head_read = 0; | ||
1681 | 1601 | ||
1682 | brcmf_dbg(TRACE, "Enter\n"); | 1602 | brcmf_dbg(TRACE, "Enter\n"); |
1683 | 1603 | ||
1684 | /* Not finished unless we encounter no more frames indication */ | 1604 | /* Not finished unless we encounter no more frames indication */ |
1685 | *finished = false; | 1605 | bus->rxpending = true; |
1686 | 1606 | ||
1687 | for (rxseq = bus->rx_seq, rxleft = maxframes; | 1607 | for (rd->seq_num = bus->rx_seq, rxleft = maxframes; |
1688 | !bus->rxskip && rxleft && | 1608 | !bus->rxskip && rxleft && |
1689 | bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN; | 1609 | bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN; |
1690 | rxseq++, rxleft--) { | 1610 | rd->seq_num++, rxleft--) { |
1691 | 1611 | ||
1692 | /* Handle glomming separately */ | 1612 | /* Handle glomming separately */ |
1693 | if (bus->glomd || !skb_queue_empty(&bus->glom)) { | 1613 | if (bus->glomd || !skb_queue_empty(&bus->glom)) { |
1694 | u8 cnt; | 1614 | u8 cnt; |
1695 | brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", | 1615 | brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", |
1696 | bus->glomd, skb_peek(&bus->glom)); | 1616 | bus->glomd, skb_peek(&bus->glom)); |
1697 | cnt = brcmf_sdbrcm_rxglom(bus, rxseq); | 1617 | cnt = brcmf_sdbrcm_rxglom(bus, rd->seq_num); |
1698 | brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); | 1618 | brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); |
1699 | rxseq += cnt - 1; | 1619 | rd->seq_num += cnt - 1; |
1700 | rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; | 1620 | rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; |
1701 | continue; | 1621 | continue; |
1702 | } | 1622 | } |
1703 | 1623 | ||
1704 | /* Try doing single read if we can */ | 1624 | rd->len_left = rd->len; |
1705 | if (bus->nextlen) { | 1625 | /* read header first for unknow frame length */ |
1706 | u16 nextlen = bus->nextlen; | 1626 | if (!rd->len) { |
1707 | bus->nextlen = 0; | 1627 | sdret = brcmf_sdcard_recv_buf(bus->sdiodev, |
1708 | 1628 | bus->sdiodev->sbwad, | |
1709 | rdlen = len = nextlen << 4; | 1629 | SDIO_FUNC_2, F2SYNC, |
1710 | brcmf_pad(bus, &pad, &rdlen); | 1630 | bus->rxhdr, |
1711 | 1631 | BRCMF_FIRSTREAD); | |
1712 | /* | 1632 | bus->sdcnt.f2rxhdrs++; |
1713 | * After the frame is received we have to | 1633 | if (sdret < 0) { |
1714 | * distinguish whether it is data | 1634 | brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", |
1715 | * or non-data frame. | 1635 | sdret); |
1716 | */ | 1636 | bus->sdcnt.rx_hdrfail++; |
1717 | brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf); | 1637 | brcmf_sdbrcm_rxfail(bus, true, true); |
1718 | if (pkt == NULL) { | ||
1719 | /* Give up on data, request rtx of events */ | ||
1720 | brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n", | ||
1721 | len, rdlen, rxseq); | ||
1722 | continue; | ||
1723 | } | ||
1724 | |||
1725 | if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen, | ||
1726 | &len) < 0) | ||
1727 | continue; | 1638 | continue; |
1728 | |||
1729 | /* Extract software header fields */ | ||
1730 | chan = SDPCM_PACKET_CHANNEL( | ||
1731 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1732 | seq = SDPCM_PACKET_SEQUENCE( | ||
1733 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1734 | doff = SDPCM_DOFFSET_VALUE( | ||
1735 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1736 | txmax = SDPCM_WINDOW_VALUE( | ||
1737 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1738 | |||
1739 | bus->nextlen = | ||
1740 | bus->rxhdr[SDPCM_FRAMETAG_LEN + | ||
1741 | SDPCM_NEXTLEN_OFFSET]; | ||
1742 | if ((bus->nextlen << 4) > MAX_RX_DATASZ) { | ||
1743 | brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", | ||
1744 | bus->nextlen, seq); | ||
1745 | bus->nextlen = 0; | ||
1746 | } | 1639 | } |
1747 | 1640 | ||
1748 | bus->sdcnt.rx_readahead_cnt++; | 1641 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(), |
1749 | |||
1750 | /* Handle Flow Control */ | ||
1751 | fcbits = SDPCM_FCMASK_VALUE( | ||
1752 | &bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1753 | |||
1754 | if (bus->flowcontrol != fcbits) { | ||
1755 | if (~bus->flowcontrol & fcbits) | ||
1756 | bus->sdcnt.fc_xoff++; | ||
1757 | |||
1758 | if (bus->flowcontrol & ~fcbits) | ||
1759 | bus->sdcnt.fc_xon++; | ||
1760 | |||
1761 | bus->sdcnt.fc_rcvd++; | ||
1762 | bus->flowcontrol = fcbits; | ||
1763 | } | ||
1764 | |||
1765 | /* Check and update sequence number */ | ||
1766 | if (rxseq != seq) { | ||
1767 | brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", | ||
1768 | seq, rxseq); | ||
1769 | bus->sdcnt.rx_badseq++; | ||
1770 | rxseq = seq; | ||
1771 | } | ||
1772 | |||
1773 | /* Check window for sanity */ | ||
1774 | if ((u8) (txmax - bus->tx_seq) > 0x40) { | ||
1775 | brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n", | ||
1776 | txmax, bus->tx_seq); | ||
1777 | txmax = bus->tx_seq + 2; | ||
1778 | } | ||
1779 | bus->tx_max = txmax; | ||
1780 | |||
1781 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), | ||
1782 | rxbuf, len, "Rx Data:\n"); | ||
1783 | brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && | ||
1784 | BRCMF_DATA_ON()) && | ||
1785 | BRCMF_HDRS_ON(), | ||
1786 | bus->rxhdr, SDPCM_HDRLEN, | 1642 | bus->rxhdr, SDPCM_HDRLEN, |
1787 | "RxHdr:\n"); | 1643 | "RxHdr:\n"); |
1788 | 1644 | ||
1789 | if (chan == SDPCM_CONTROL_CHANNEL) { | 1645 | if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd)) { |
1790 | brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", | 1646 | if (!bus->rxpending) |
1791 | seq); | 1647 | break; |
1792 | /* Force retry w/normal header read */ | 1648 | else |
1793 | bus->nextlen = 0; | 1649 | continue; |
1794 | brcmf_sdbrcm_rxfail(bus, false, true); | ||
1795 | brcmf_sdbrcm_pktfree2(bus, pkt); | ||
1796 | continue; | ||
1797 | } | 1650 | } |
1798 | 1651 | ||
1799 | /* Validate data offset */ | 1652 | if (rd->channel == SDPCM_CONTROL_CHANNEL) { |
1800 | if ((doff < SDPCM_HDRLEN) || (doff > len)) { | 1653 | brcmf_sdbrcm_read_control(bus, bus->rxhdr, |
1801 | brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n", | 1654 | rd->len, |
1802 | doff, len, SDPCM_HDRLEN); | 1655 | rd->dat_offset); |
1803 | brcmf_sdbrcm_rxfail(bus, false, false); | 1656 | /* prepare the descriptor for the next read */ |
1804 | brcmf_sdbrcm_pktfree2(bus, pkt); | 1657 | rd->len = rd->len_nxtfrm << 4; |
1658 | rd->len_nxtfrm = 0; | ||
1659 | /* treat all packet as event if we don't know */ | ||
1660 | rd->channel = SDPCM_EVENT_CHANNEL; | ||
1805 | continue; | 1661 | continue; |
1806 | } | 1662 | } |
1807 | 1663 | rd->len_left = rd->len > BRCMF_FIRSTREAD ? | |
1808 | /* All done with this one -- now deliver the packet */ | 1664 | rd->len - BRCMF_FIRSTREAD : 0; |
1809 | goto deliver; | 1665 | head_read = BRCMF_FIRSTREAD; |
1810 | } | ||
1811 | |||
1812 | /* Read frame header (hardware and software) */ | ||
1813 | sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, | ||
1814 | SDIO_FUNC_2, F2SYNC, bus->rxhdr, | ||
1815 | BRCMF_FIRSTREAD); | ||
1816 | bus->sdcnt.f2rxhdrs++; | ||
1817 | |||
1818 | if (sdret < 0) { | ||
1819 | brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); | ||
1820 | bus->sdcnt.rx_hdrfail++; | ||
1821 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
1822 | continue; | ||
1823 | } | ||
1824 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(), | ||
1825 | bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); | ||
1826 | |||
1827 | |||
1828 | /* Extract hardware header fields */ | ||
1829 | len = get_unaligned_le16(bus->rxhdr); | ||
1830 | check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); | ||
1831 | |||
1832 | /* All zeros means no more frames */ | ||
1833 | if (!(len | check)) { | ||
1834 | *finished = true; | ||
1835 | break; | ||
1836 | } | 1666 | } |
1837 | 1667 | ||
1838 | /* Validate check bytes */ | 1668 | brcmf_pad(bus, &pad, &rd->len_left); |
1839 | if ((u16) ~(len ^ check)) { | ||
1840 | brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", | ||
1841 | len, check); | ||
1842 | bus->sdcnt.rx_badhdr++; | ||
1843 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1844 | continue; | ||
1845 | } | ||
1846 | 1669 | ||
1847 | /* Validate frame length */ | 1670 | pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read + |
1848 | if (len < SDPCM_HDRLEN) { | 1671 | BRCMF_SDALIGN); |
1849 | brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len); | ||
1850 | continue; | ||
1851 | } | ||
1852 | |||
1853 | /* Extract software header fields */ | ||
1854 | chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1855 | seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1856 | doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1857 | txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1858 | |||
1859 | /* Validate data offset */ | ||
1860 | if ((doff < SDPCM_HDRLEN) || (doff > len)) { | ||
1861 | brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", | ||
1862 | doff, len, SDPCM_HDRLEN, seq); | ||
1863 | bus->sdcnt.rx_badhdr++; | ||
1864 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1865 | continue; | ||
1866 | } | ||
1867 | |||
1868 | /* Save the readahead length if there is one */ | ||
1869 | bus->nextlen = | ||
1870 | bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; | ||
1871 | if ((bus->nextlen << 4) > MAX_RX_DATASZ) { | ||
1872 | brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", | ||
1873 | bus->nextlen, seq); | ||
1874 | bus->nextlen = 0; | ||
1875 | } | ||
1876 | |||
1877 | /* Handle Flow Control */ | ||
1878 | fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); | ||
1879 | |||
1880 | if (bus->flowcontrol != fcbits) { | ||
1881 | if (~bus->flowcontrol & fcbits) | ||
1882 | bus->sdcnt.fc_xoff++; | ||
1883 | |||
1884 | if (bus->flowcontrol & ~fcbits) | ||
1885 | bus->sdcnt.fc_xon++; | ||
1886 | |||
1887 | bus->sdcnt.fc_rcvd++; | ||
1888 | bus->flowcontrol = fcbits; | ||
1889 | } | ||
1890 | |||
1891 | /* Check and update sequence number */ | ||
1892 | if (rxseq != seq) { | ||
1893 | brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); | ||
1894 | bus->sdcnt.rx_badseq++; | ||
1895 | rxseq = seq; | ||
1896 | } | ||
1897 | |||
1898 | /* Check window for sanity */ | ||
1899 | if ((u8) (txmax - bus->tx_seq) > 0x40) { | ||
1900 | brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", | ||
1901 | txmax, bus->tx_seq); | ||
1902 | txmax = bus->tx_seq + 2; | ||
1903 | } | ||
1904 | bus->tx_max = txmax; | ||
1905 | |||
1906 | /* Call a separate function for control frames */ | ||
1907 | if (chan == SDPCM_CONTROL_CHANNEL) { | ||
1908 | brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); | ||
1909 | continue; | ||
1910 | } | ||
1911 | |||
1912 | /* precondition: chan is either SDPCM_DATA_CHANNEL, | ||
1913 | SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or | ||
1914 | SDPCM_GLOM_CHANNEL */ | ||
1915 | |||
1916 | /* Length to read */ | ||
1917 | rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0; | ||
1918 | |||
1919 | /* May pad read to blocksize for efficiency */ | ||
1920 | if (bus->roundup && bus->blocksize && | ||
1921 | (rdlen > bus->blocksize)) { | ||
1922 | pad = bus->blocksize - (rdlen % bus->blocksize); | ||
1923 | if ((pad <= bus->roundup) && (pad < bus->blocksize) && | ||
1924 | ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ)) | ||
1925 | rdlen += pad; | ||
1926 | } else if (rdlen % BRCMF_SDALIGN) { | ||
1927 | rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); | ||
1928 | } | ||
1929 | |||
1930 | /* Satisfy length-alignment requirements */ | ||
1931 | if (rdlen & (ALIGNMENT - 1)) | ||
1932 | rdlen = roundup(rdlen, ALIGNMENT); | ||
1933 | |||
1934 | if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) { | ||
1935 | /* Too long -- skip this frame */ | ||
1936 | brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", | ||
1937 | len, rdlen); | ||
1938 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1939 | bus->sdcnt.rx_toolong++; | ||
1940 | brcmf_sdbrcm_rxfail(bus, false, false); | ||
1941 | continue; | ||
1942 | } | ||
1943 | |||
1944 | pkt = brcmu_pkt_buf_get_skb(rdlen + | ||
1945 | BRCMF_FIRSTREAD + BRCMF_SDALIGN); | ||
1946 | if (!pkt) { | 1672 | if (!pkt) { |
1947 | /* Give up on data, request rtx of events */ | 1673 | /* Give up on data, request rtx of events */ |
1948 | brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n", | 1674 | brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed\n"); |
1949 | rdlen, chan); | ||
1950 | bus->sdiodev->bus_if->dstats.rx_dropped++; | 1675 | bus->sdiodev->bus_if->dstats.rx_dropped++; |
1951 | brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); | 1676 | brcmf_sdbrcm_rxfail(bus, false, |
1677 | RETRYCHAN(rd->channel)); | ||
1952 | continue; | 1678 | continue; |
1953 | } | 1679 | } |
1680 | skb_pull(pkt, head_read); | ||
1681 | pkt_align(pkt, rd->len_left, BRCMF_SDALIGN); | ||
1954 | 1682 | ||
1955 | /* Leave room for what we already read, and align remainder */ | ||
1956 | skb_pull(pkt, BRCMF_FIRSTREAD); | ||
1957 | pkt_align(pkt, rdlen, BRCMF_SDALIGN); | ||
1958 | |||
1959 | /* Read the remaining frame data */ | ||
1960 | sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, | 1683 | sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, |
1961 | SDIO_FUNC_2, F2SYNC, pkt); | 1684 | SDIO_FUNC_2, F2SYNC, pkt); |
1962 | bus->sdcnt.f2rxdata++; | 1685 | bus->sdcnt.f2rxdata++; |
1963 | 1686 | ||
1964 | if (sdret < 0) { | 1687 | if (sdret < 0) { |
1965 | brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, | 1688 | brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n", |
1966 | ((chan == SDPCM_EVENT_CHANNEL) ? "event" | 1689 | rd->len, rd->channel, sdret); |
1967 | : ((chan == SDPCM_DATA_CHANNEL) ? "data" | ||
1968 | : "test")), sdret); | ||
1969 | brcmu_pkt_buf_free_skb(pkt); | 1690 | brcmu_pkt_buf_free_skb(pkt); |
1970 | bus->sdiodev->bus_if->dstats.rx_errors++; | 1691 | bus->sdiodev->bus_if->dstats.rx_errors++; |
1971 | brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); | 1692 | brcmf_sdbrcm_rxfail(bus, true, |
1693 | RETRYCHAN(rd->channel)); | ||
1972 | continue; | 1694 | continue; |
1973 | } | 1695 | } |
1974 | 1696 | ||
1975 | /* Copy the already-read portion */ | 1697 | if (head_read) { |
1976 | skb_push(pkt, BRCMF_FIRSTREAD); | 1698 | skb_push(pkt, head_read); |
1977 | memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); | 1699 | memcpy(pkt->data, bus->rxhdr, head_read); |
1700 | head_read = 0; | ||
1701 | } else { | ||
1702 | memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN); | ||
1703 | rd_new.seq_num = rd->seq_num; | ||
1704 | if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new)) { | ||
1705 | rd->len = 0; | ||
1706 | brcmu_pkt_buf_free_skb(pkt); | ||
1707 | } | ||
1708 | bus->sdcnt.rx_readahead_cnt++; | ||
1709 | if (rd->len != roundup(rd_new.len, 16)) { | ||
1710 | brcmf_dbg(ERROR, "frame length mismatch:read %d, should be %d\n", | ||
1711 | rd->len, | ||
1712 | roundup(rd_new.len, 16) >> 4); | ||
1713 | rd->len = 0; | ||
1714 | brcmf_sdbrcm_rxfail(bus, true, true); | ||
1715 | brcmu_pkt_buf_free_skb(pkt); | ||
1716 | continue; | ||
1717 | } | ||
1718 | rd->len_nxtfrm = rd_new.len_nxtfrm; | ||
1719 | rd->channel = rd_new.channel; | ||
1720 | rd->dat_offset = rd_new.dat_offset; | ||
1721 | |||
1722 | brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && | ||
1723 | BRCMF_DATA_ON()) && | ||
1724 | BRCMF_HDRS_ON(), | ||
1725 | bus->rxhdr, SDPCM_HDRLEN, | ||
1726 | "RxHdr:\n"); | ||
1727 | |||
1728 | if (rd_new.channel == SDPCM_CONTROL_CHANNEL) { | ||
1729 | brcmf_dbg(ERROR, "readahead on control packet %d?\n", | ||
1730 | rd_new.seq_num); | ||
1731 | /* Force retry w/normal header read */ | ||
1732 | rd->len = 0; | ||
1733 | brcmf_sdbrcm_rxfail(bus, false, true); | ||
1734 | brcmu_pkt_buf_free_skb(pkt); | ||
1735 | continue; | ||
1736 | } | ||
1737 | } | ||
1978 | 1738 | ||
1979 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), | 1739 | brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), |
1980 | pkt->data, len, "Rx Data:\n"); | 1740 | pkt->data, rd->len, "Rx Data:\n"); |
1981 | 1741 | ||
1982 | deliver: | ||
1983 | /* Save superframe descriptor and allocate packet frame */ | 1742 | /* Save superframe descriptor and allocate packet frame */ |
1984 | if (chan == SDPCM_GLOM_CHANNEL) { | 1743 | if (rd->channel == SDPCM_GLOM_CHANNEL) { |
1985 | if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { | 1744 | if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { |
1986 | brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", | 1745 | brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", |
1987 | len); | 1746 | rd->len); |
1988 | brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), | 1747 | brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), |
1989 | pkt->data, len, | 1748 | pkt->data, rd->len, |
1990 | "Glom Data:\n"); | 1749 | "Glom Data:\n"); |
1991 | __skb_trim(pkt, len); | 1750 | __skb_trim(pkt, rd->len); |
1992 | skb_pull(pkt, SDPCM_HDRLEN); | 1751 | skb_pull(pkt, SDPCM_HDRLEN); |
1993 | bus->glomd = pkt; | 1752 | bus->glomd = pkt; |
1994 | } else { | 1753 | } else { |
@@ -1996,12 +1755,23 @@ deliver: | |||
1996 | "descriptor!\n", __func__); | 1755 | "descriptor!\n", __func__); |
1997 | brcmf_sdbrcm_rxfail(bus, false, false); | 1756 | brcmf_sdbrcm_rxfail(bus, false, false); |
1998 | } | 1757 | } |
1758 | /* prepare the descriptor for the next read */ | ||
1759 | rd->len = rd->len_nxtfrm << 4; | ||
1760 | rd->len_nxtfrm = 0; | ||
1761 | /* treat all packet as event if we don't know */ | ||
1762 | rd->channel = SDPCM_EVENT_CHANNEL; | ||
1999 | continue; | 1763 | continue; |
2000 | } | 1764 | } |
2001 | 1765 | ||
2002 | /* Fill in packet len and prio, deliver upward */ | 1766 | /* Fill in packet len and prio, deliver upward */ |
2003 | __skb_trim(pkt, len); | 1767 | __skb_trim(pkt, rd->len); |
2004 | skb_pull(pkt, doff); | 1768 | skb_pull(pkt, rd->dat_offset); |
1769 | |||
1770 | /* prepare the descriptor for the next read */ | ||
1771 | rd->len = rd->len_nxtfrm << 4; | ||
1772 | rd->len_nxtfrm = 0; | ||
1773 | /* treat all packet as event if we don't know */ | ||
1774 | rd->channel = SDPCM_EVENT_CHANNEL; | ||
2005 | 1775 | ||
2006 | if (pkt->len == 0) { | 1776 | if (pkt->len == 0) { |
2007 | brcmu_pkt_buf_free_skb(pkt); | 1777 | brcmu_pkt_buf_free_skb(pkt); |
@@ -2019,17 +1789,17 @@ deliver: | |||
2019 | brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); | 1789 | brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); |
2020 | down(&bus->sdsem); | 1790 | down(&bus->sdsem); |
2021 | } | 1791 | } |
1792 | |||
2022 | rxcount = maxframes - rxleft; | 1793 | rxcount = maxframes - rxleft; |
2023 | /* Message if we hit the limit */ | 1794 | /* Message if we hit the limit */ |
2024 | if (!rxleft) | 1795 | if (!rxleft) |
2025 | brcmf_dbg(DATA, "hit rx limit of %d frames\n", | 1796 | brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes); |
2026 | maxframes); | ||
2027 | else | 1797 | else |
2028 | brcmf_dbg(DATA, "processed %d frames\n", rxcount); | 1798 | brcmf_dbg(DATA, "processed %d frames\n", rxcount); |
2029 | /* Back off rxseq if awaiting rtx, update rx_seq */ | 1799 | /* Back off rxseq if awaiting rtx, update rx_seq */ |
2030 | if (bus->rxskip) | 1800 | if (bus->rxskip) |
2031 | rxseq--; | 1801 | rd->seq_num--; |
2032 | bus->rx_seq = rxseq; | 1802 | bus->rx_seq = rd->seq_num; |
2033 | 1803 | ||
2034 | return rxcount; | 1804 | return rxcount; |
2035 | } | 1805 | } |
@@ -2227,7 +1997,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
2227 | if (ret != 0) | 1997 | if (ret != 0) |
2228 | break; | 1998 | break; |
2229 | if (intstatus & bus->hostintmask) | 1999 | if (intstatus & bus->hostintmask) |
2230 | bus->ipend = true; | 2000 | atomic_set(&bus->ipend, 1); |
2231 | } | 2001 | } |
2232 | } | 2002 | } |
2233 | 2003 | ||
@@ -2259,16 +2029,8 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) | |||
2259 | bus->watchdog_tsk = NULL; | 2029 | bus->watchdog_tsk = NULL; |
2260 | } | 2030 | } |
2261 | 2031 | ||
2262 | if (bus->dpc_tsk && bus->dpc_tsk != current) { | ||
2263 | send_sig(SIGTERM, bus->dpc_tsk, 1); | ||
2264 | kthread_stop(bus->dpc_tsk); | ||
2265 | bus->dpc_tsk = NULL; | ||
2266 | } | ||
2267 | |||
2268 | down(&bus->sdsem); | 2032 | down(&bus->sdsem); |
2269 | 2033 | ||
2270 | bus_wake(bus); | ||
2271 | |||
2272 | /* Enable clock for device interrupts */ | 2034 | /* Enable clock for device interrupts */ |
2273 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | 2035 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); |
2274 | 2036 | ||
@@ -2327,7 +2089,7 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) | |||
2327 | unsigned long flags; | 2089 | unsigned long flags; |
2328 | 2090 | ||
2329 | spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags); | 2091 | spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags); |
2330 | if (!bus->sdiodev->irq_en && !bus->ipend) { | 2092 | if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) { |
2331 | enable_irq(bus->sdiodev->irq); | 2093 | enable_irq(bus->sdiodev->irq); |
2332 | bus->sdiodev->irq_en = true; | 2094 | bus->sdiodev->irq_en = true; |
2333 | } | 2095 | } |
@@ -2339,21 +2101,69 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) | |||
2339 | } | 2101 | } |
2340 | #endif /* CONFIG_BRCMFMAC_SDIO_OOB */ | 2102 | #endif /* CONFIG_BRCMFMAC_SDIO_OOB */ |
2341 | 2103 | ||
2342 | static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) | 2104 | static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus) |
2105 | { | ||
2106 | struct list_head *new_hd; | ||
2107 | unsigned long flags; | ||
2108 | |||
2109 | if (in_interrupt()) | ||
2110 | new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC); | ||
2111 | else | ||
2112 | new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL); | ||
2113 | if (new_hd == NULL) | ||
2114 | return; | ||
2115 | |||
2116 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
2117 | list_add_tail(new_hd, &bus->dpc_tsklst); | ||
2118 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2119 | } | ||
2120 | |||
2121 | static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) | ||
2343 | { | 2122 | { |
2344 | u32 intstatus, newstatus = 0; | 2123 | u8 idx; |
2124 | u32 addr; | ||
2125 | unsigned long val; | ||
2126 | int n, ret; | ||
2127 | |||
2128 | idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); | ||
2129 | addr = bus->ci->c_inf[idx].base + | ||
2130 | offsetof(struct sdpcmd_regs, intstatus); | ||
2131 | |||
2132 | ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, false); | ||
2133 | bus->sdcnt.f1regdata++; | ||
2134 | if (ret != 0) | ||
2135 | val = 0; | ||
2136 | |||
2137 | val &= bus->hostintmask; | ||
2138 | atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); | ||
2139 | |||
2140 | /* Clear interrupts */ | ||
2141 | if (val) { | ||
2142 | ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, true); | ||
2143 | bus->sdcnt.f1regdata++; | ||
2144 | } | ||
2145 | |||
2146 | if (ret) { | ||
2147 | atomic_set(&bus->intstatus, 0); | ||
2148 | } else if (val) { | ||
2149 | for_each_set_bit(n, &val, 32) | ||
2150 | set_bit(n, (unsigned long *)&bus->intstatus.counter); | ||
2151 | } | ||
2152 | |||
2153 | return ret; | ||
2154 | } | ||
2155 | |||
2156 | static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) | ||
2157 | { | ||
2158 | u32 newstatus = 0; | ||
2159 | unsigned long intstatus; | ||
2345 | uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ | 2160 | uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ |
2346 | uint txlimit = bus->txbound; /* Tx frames to send before resched */ | 2161 | uint txlimit = bus->txbound; /* Tx frames to send before resched */ |
2347 | uint framecnt = 0; /* Temporary counter of tx/rx frames */ | 2162 | uint framecnt = 0; /* Temporary counter of tx/rx frames */ |
2348 | bool rxdone = true; /* Flag for no more read data */ | 2163 | int err = 0, n; |
2349 | bool resched = false; /* Flag indicating resched wanted */ | ||
2350 | int err; | ||
2351 | 2164 | ||
2352 | brcmf_dbg(TRACE, "Enter\n"); | 2165 | brcmf_dbg(TRACE, "Enter\n"); |
2353 | 2166 | ||
2354 | /* Start with leftover status bits */ | ||
2355 | intstatus = bus->intstatus; | ||
2356 | |||
2357 | down(&bus->sdsem); | 2167 | down(&bus->sdsem); |
2358 | 2168 | ||
2359 | /* If waiting for HTAVAIL, check status */ | 2169 | /* If waiting for HTAVAIL, check status */ |
@@ -2399,39 +2209,22 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) | |||
2399 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; | 2209 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; |
2400 | } | 2210 | } |
2401 | bus->clkstate = CLK_AVAIL; | 2211 | bus->clkstate = CLK_AVAIL; |
2402 | } else { | ||
2403 | goto clkwait; | ||
2404 | } | 2212 | } |
2405 | } | 2213 | } |
2406 | 2214 | ||
2407 | bus_wake(bus); | ||
2408 | |||
2409 | /* Make sure backplane clock is on */ | 2215 | /* Make sure backplane clock is on */ |
2410 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); | 2216 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); |
2411 | if (bus->clkstate == CLK_PENDING) | ||
2412 | goto clkwait; | ||
2413 | 2217 | ||
2414 | /* Pending interrupt indicates new device status */ | 2218 | /* Pending interrupt indicates new device status */ |
2415 | if (bus->ipend) { | 2219 | if (atomic_read(&bus->ipend) > 0) { |
2416 | bus->ipend = false; | 2220 | atomic_set(&bus->ipend, 0); |
2417 | err = r_sdreg32(bus, &newstatus, | 2221 | sdio_claim_host(bus->sdiodev->func[1]); |
2418 | offsetof(struct sdpcmd_regs, intstatus)); | 2222 | err = brcmf_sdio_intr_rstatus(bus); |
2419 | bus->sdcnt.f1regdata++; | 2223 | sdio_release_host(bus->sdiodev->func[1]); |
2420 | if (err != 0) | ||
2421 | newstatus = 0; | ||
2422 | newstatus &= bus->hostintmask; | ||
2423 | bus->fcstate = !!(newstatus & I_HMB_FC_STATE); | ||
2424 | if (newstatus) { | ||
2425 | err = w_sdreg32(bus, newstatus, | ||
2426 | offsetof(struct sdpcmd_regs, | ||
2427 | intstatus)); | ||
2428 | bus->sdcnt.f1regdata++; | ||
2429 | } | ||
2430 | } | 2224 | } |
2431 | 2225 | ||
2432 | /* Merge new bits with previous */ | 2226 | /* Start with leftover status bits */ |
2433 | intstatus |= newstatus; | 2227 | intstatus = atomic_xchg(&bus->intstatus, 0); |
2434 | bus->intstatus = 0; | ||
2435 | 2228 | ||
2436 | /* Handle flow-control change: read new state in case our ack | 2229 | /* Handle flow-control change: read new state in case our ack |
2437 | * crossed another change interrupt. If change still set, assume | 2230 | * crossed another change interrupt. If change still set, assume |
@@ -2445,8 +2238,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) | |||
2445 | err = r_sdreg32(bus, &newstatus, | 2238 | err = r_sdreg32(bus, &newstatus, |
2446 | offsetof(struct sdpcmd_regs, intstatus)); | 2239 | offsetof(struct sdpcmd_regs, intstatus)); |
2447 | bus->sdcnt.f1regdata += 2; | 2240 | bus->sdcnt.f1regdata += 2; |
2448 | bus->fcstate = | 2241 | atomic_set(&bus->fcstate, |
2449 | !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); | 2242 | !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE))); |
2450 | intstatus |= (newstatus & bus->hostintmask); | 2243 | intstatus |= (newstatus & bus->hostintmask); |
2451 | } | 2244 | } |
2452 | 2245 | ||
@@ -2483,32 +2276,34 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) | |||
2483 | intstatus &= ~I_HMB_FRAME_IND; | 2276 | intstatus &= ~I_HMB_FRAME_IND; |
2484 | 2277 | ||
2485 | /* On frame indication, read available frames */ | 2278 | /* On frame indication, read available frames */ |
2486 | if (PKT_AVAILABLE()) { | 2279 | if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) { |
2487 | framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); | 2280 | framecnt = brcmf_sdio_readframes(bus, rxlimit); |
2488 | if (rxdone || bus->rxskip) | 2281 | if (!bus->rxpending) |
2489 | intstatus &= ~I_HMB_FRAME_IND; | 2282 | intstatus &= ~I_HMB_FRAME_IND; |
2490 | rxlimit -= min(framecnt, rxlimit); | 2283 | rxlimit -= min(framecnt, rxlimit); |
2491 | } | 2284 | } |
2492 | 2285 | ||
2493 | /* Keep still-pending events for next scheduling */ | 2286 | /* Keep still-pending events for next scheduling */ |
2494 | bus->intstatus = intstatus; | 2287 | if (intstatus) { |
2288 | for_each_set_bit(n, &intstatus, 32) | ||
2289 | set_bit(n, (unsigned long *)&bus->intstatus.counter); | ||
2290 | } | ||
2495 | 2291 | ||
2496 | clkwait: | ||
2497 | brcmf_sdbrcm_clrintr(bus); | 2292 | brcmf_sdbrcm_clrintr(bus); |
2498 | 2293 | ||
2499 | if (data_ok(bus) && bus->ctrl_frame_stat && | 2294 | if (data_ok(bus) && bus->ctrl_frame_stat && |
2500 | (bus->clkstate == CLK_AVAIL)) { | 2295 | (bus->clkstate == CLK_AVAIL)) { |
2501 | int ret, i; | 2296 | int i; |
2502 | 2297 | ||
2503 | ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, | 2298 | err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, |
2504 | SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf, | 2299 | SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf, |
2505 | (u32) bus->ctrl_frame_len); | 2300 | (u32) bus->ctrl_frame_len); |
2506 | 2301 | ||
2507 | if (ret < 0) { | 2302 | if (err < 0) { |
2508 | /* On failure, abort the command and | 2303 | /* On failure, abort the command and |
2509 | terminate the frame */ | 2304 | terminate the frame */ |
2510 | brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", | 2305 | brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", |
2511 | ret); | 2306 | err); |
2512 | bus->sdcnt.tx_sderrs++; | 2307 | bus->sdcnt.tx_sderrs++; |
2513 | 2308 | ||
2514 | brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); | 2309 | brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); |
@@ -2530,42 +2325,34 @@ clkwait: | |||
2530 | break; | 2325 | break; |
2531 | } | 2326 | } |
2532 | 2327 | ||
2533 | } | 2328 | } else { |
2534 | if (ret == 0) | ||
2535 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; | 2329 | bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; |
2536 | 2330 | } | |
2537 | brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret); | ||
2538 | bus->ctrl_frame_stat = false; | 2331 | bus->ctrl_frame_stat = false; |
2539 | brcmf_sdbrcm_wait_event_wakeup(bus); | 2332 | brcmf_sdbrcm_wait_event_wakeup(bus); |
2540 | } | 2333 | } |
2541 | /* Send queued frames (limit 1 if rx may still be pending) */ | 2334 | /* Send queued frames (limit 1 if rx may still be pending) */ |
2542 | else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && | 2335 | else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && |
2543 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit | 2336 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit |
2544 | && data_ok(bus)) { | 2337 | && data_ok(bus)) { |
2545 | framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); | 2338 | framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : |
2339 | txlimit; | ||
2546 | framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); | 2340 | framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); |
2547 | txlimit -= framecnt; | 2341 | txlimit -= framecnt; |
2548 | } | 2342 | } |
2549 | 2343 | ||
2550 | /* Resched if events or tx frames are pending, | ||
2551 | else await next interrupt */ | ||
2552 | /* On failed register access, all bets are off: | ||
2553 | no resched or interrupts */ | ||
2554 | if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { | 2344 | if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { |
2555 | brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n"); | 2345 | brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n"); |
2556 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; | 2346 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; |
2557 | bus->intstatus = 0; | 2347 | atomic_set(&bus->intstatus, 0); |
2558 | } else if (bus->clkstate == CLK_PENDING) { | 2348 | } else if (atomic_read(&bus->intstatus) || |
2559 | brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); | 2349 | atomic_read(&bus->ipend) > 0 || |
2560 | resched = true; | 2350 | (!atomic_read(&bus->fcstate) && |
2561 | } else if (bus->intstatus || bus->ipend || | 2351 | brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && |
2562 | (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) | 2352 | data_ok(bus)) || PKT_AVAILABLE()) { |
2563 | && data_ok(bus)) || PKT_AVAILABLE()) { | 2353 | brcmf_sdbrcm_adddpctsk(bus); |
2564 | resched = true; | ||
2565 | } | 2354 | } |
2566 | 2355 | ||
2567 | bus->dpc_sched = resched; | ||
2568 | |||
2569 | /* If we're done for now, turn off clock request. */ | 2356 | /* If we're done for now, turn off clock request. */ |
2570 | if ((bus->clkstate != CLK_PENDING) | 2357 | if ((bus->clkstate != CLK_PENDING) |
2571 | && bus->idletime == BRCMF_IDLE_IMMEDIATE) { | 2358 | && bus->idletime == BRCMF_IDLE_IMMEDIATE) { |
@@ -2574,65 +2361,6 @@ clkwait: | |||
2574 | } | 2361 | } |
2575 | 2362 | ||
2576 | up(&bus->sdsem); | 2363 | up(&bus->sdsem); |
2577 | |||
2578 | return resched; | ||
2579 | } | ||
2580 | |||
2581 | static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus) | ||
2582 | { | ||
2583 | struct list_head *new_hd; | ||
2584 | unsigned long flags; | ||
2585 | |||
2586 | if (in_interrupt()) | ||
2587 | new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC); | ||
2588 | else | ||
2589 | new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL); | ||
2590 | if (new_hd == NULL) | ||
2591 | return; | ||
2592 | |||
2593 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
2594 | list_add_tail(new_hd, &bus->dpc_tsklst); | ||
2595 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2596 | } | ||
2597 | |||
2598 | static int brcmf_sdbrcm_dpc_thread(void *data) | ||
2599 | { | ||
2600 | struct brcmf_sdio *bus = (struct brcmf_sdio *) data; | ||
2601 | struct list_head *cur_hd, *tmp_hd; | ||
2602 | unsigned long flags; | ||
2603 | |||
2604 | allow_signal(SIGTERM); | ||
2605 | /* Run until signal received */ | ||
2606 | while (1) { | ||
2607 | if (kthread_should_stop()) | ||
2608 | break; | ||
2609 | |||
2610 | if (list_empty(&bus->dpc_tsklst)) | ||
2611 | if (wait_for_completion_interruptible(&bus->dpc_wait)) | ||
2612 | break; | ||
2613 | |||
2614 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
2615 | list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) { | ||
2616 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2617 | |||
2618 | if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { | ||
2619 | /* after stopping the bus, exit thread */ | ||
2620 | brcmf_sdbrcm_bus_stop(bus->sdiodev->dev); | ||
2621 | bus->dpc_tsk = NULL; | ||
2622 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
2623 | break; | ||
2624 | } | ||
2625 | |||
2626 | if (brcmf_sdbrcm_dpc(bus)) | ||
2627 | brcmf_sdbrcm_adddpctsk(bus); | ||
2628 | |||
2629 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
2630 | list_del(cur_hd); | ||
2631 | kfree(cur_hd); | ||
2632 | } | ||
2633 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2634 | } | ||
2635 | return 0; | ||
2636 | } | 2364 | } |
2637 | 2365 | ||
2638 | static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) | 2366 | static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) |
@@ -2642,6 +2370,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) | |||
2642 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 2370 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
2643 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | 2371 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
2644 | struct brcmf_sdio *bus = sdiodev->bus; | 2372 | struct brcmf_sdio *bus = sdiodev->bus; |
2373 | unsigned long flags; | ||
2645 | 2374 | ||
2646 | brcmf_dbg(TRACE, "Enter\n"); | 2375 | brcmf_dbg(TRACE, "Enter\n"); |
2647 | 2376 | ||
@@ -2680,13 +2409,15 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) | |||
2680 | if (pktq_plen(&bus->txq, prec) > qcount[prec]) | 2409 | if (pktq_plen(&bus->txq, prec) > qcount[prec]) |
2681 | qcount[prec] = pktq_plen(&bus->txq, prec); | 2410 | qcount[prec] = pktq_plen(&bus->txq, prec); |
2682 | #endif | 2411 | #endif |
2683 | /* Schedule DPC if needed to send queued packet(s) */ | 2412 | |
2684 | if (!bus->dpc_sched) { | 2413 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); |
2685 | bus->dpc_sched = true; | 2414 | if (list_empty(&bus->dpc_tsklst)) { |
2686 | if (bus->dpc_tsk) { | 2415 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); |
2687 | brcmf_sdbrcm_adddpctsk(bus); | 2416 | |
2688 | complete(&bus->dpc_wait); | 2417 | brcmf_sdbrcm_adddpctsk(bus); |
2689 | } | 2418 | queue_work(bus->brcmf_wq, &bus->datawork); |
2419 | } else { | ||
2420 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2690 | } | 2421 | } |
2691 | 2422 | ||
2692 | return ret; | 2423 | return ret; |
@@ -2707,6 +2438,8 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data, | |||
2707 | else | 2438 | else |
2708 | dsize = size; | 2439 | dsize = size; |
2709 | 2440 | ||
2441 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2442 | |||
2710 | /* Set the backplane window to include the start address */ | 2443 | /* Set the backplane window to include the start address */ |
2711 | bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); | 2444 | bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); |
2712 | if (bcmerror) { | 2445 | if (bcmerror) { |
@@ -2748,6 +2481,8 @@ xfer_done: | |||
2748 | brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", | 2481 | brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", |
2749 | bus->sdiodev->sbwad); | 2482 | bus->sdiodev->sbwad); |
2750 | 2483 | ||
2484 | sdio_release_host(bus->sdiodev->func[1]); | ||
2485 | |||
2751 | return bcmerror; | 2486 | return bcmerror; |
2752 | } | 2487 | } |
2753 | 2488 | ||
@@ -2882,6 +2617,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) | |||
2882 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 2617 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
2883 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | 2618 | struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; |
2884 | struct brcmf_sdio *bus = sdiodev->bus; | 2619 | struct brcmf_sdio *bus = sdiodev->bus; |
2620 | unsigned long flags; | ||
2885 | 2621 | ||
2886 | brcmf_dbg(TRACE, "Enter\n"); | 2622 | brcmf_dbg(TRACE, "Enter\n"); |
2887 | 2623 | ||
@@ -2918,8 +2654,6 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) | |||
2918 | /* Need to lock here to protect txseq and SDIO tx calls */ | 2654 | /* Need to lock here to protect txseq and SDIO tx calls */ |
2919 | down(&bus->sdsem); | 2655 | down(&bus->sdsem); |
2920 | 2656 | ||
2921 | bus_wake(bus); | ||
2922 | |||
2923 | /* Make sure backplane clock is on */ | 2657 | /* Make sure backplane clock is on */ |
2924 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | 2658 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); |
2925 | 2659 | ||
@@ -2967,9 +2701,15 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) | |||
2967 | } while (ret < 0 && retries++ < TXRETRIES); | 2701 | } while (ret < 0 && retries++ < TXRETRIES); |
2968 | } | 2702 | } |
2969 | 2703 | ||
2970 | if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { | 2704 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); |
2705 | if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && | ||
2706 | list_empty(&bus->dpc_tsklst)) { | ||
2707 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2708 | |||
2971 | bus->activity = false; | 2709 | bus->activity = false; |
2972 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); | 2710 | brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); |
2711 | } else { | ||
2712 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
2973 | } | 2713 | } |
2974 | 2714 | ||
2975 | up(&bus->sdsem); | 2715 | up(&bus->sdsem); |
@@ -3774,23 +3514,20 @@ void brcmf_sdbrcm_isr(void *arg) | |||
3774 | } | 3514 | } |
3775 | /* Count the interrupt call */ | 3515 | /* Count the interrupt call */ |
3776 | bus->sdcnt.intrcount++; | 3516 | bus->sdcnt.intrcount++; |
3777 | bus->ipend = true; | 3517 | if (in_interrupt()) |
3778 | 3518 | atomic_set(&bus->ipend, 1); | |
3779 | /* Shouldn't get this interrupt if we're sleeping? */ | 3519 | else |
3780 | if (bus->sleeping) { | 3520 | if (brcmf_sdio_intr_rstatus(bus)) { |
3781 | brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n"); | 3521 | brcmf_dbg(ERROR, "failed backplane access\n"); |
3782 | return; | 3522 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; |
3783 | } | 3523 | } |
3784 | 3524 | ||
3785 | /* Disable additional interrupts (is this needed now)? */ | 3525 | /* Disable additional interrupts (is this needed now)? */ |
3786 | if (!bus->intr) | 3526 | if (!bus->intr) |
3787 | brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); | 3527 | brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); |
3788 | 3528 | ||
3789 | bus->dpc_sched = true; | 3529 | brcmf_sdbrcm_adddpctsk(bus); |
3790 | if (bus->dpc_tsk) { | 3530 | queue_work(bus->brcmf_wq, &bus->datawork); |
3791 | brcmf_sdbrcm_adddpctsk(bus); | ||
3792 | complete(&bus->dpc_wait); | ||
3793 | } | ||
3794 | } | 3531 | } |
3795 | 3532 | ||
3796 | static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) | 3533 | static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) |
@@ -3798,13 +3535,10 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) | |||
3798 | #ifdef DEBUG | 3535 | #ifdef DEBUG |
3799 | struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); | 3536 | struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); |
3800 | #endif /* DEBUG */ | 3537 | #endif /* DEBUG */ |
3538 | unsigned long flags; | ||
3801 | 3539 | ||
3802 | brcmf_dbg(TIMER, "Enter\n"); | 3540 | brcmf_dbg(TIMER, "Enter\n"); |
3803 | 3541 | ||
3804 | /* Ignore the timer if simulating bus down */ | ||
3805 | if (bus->sleeping) | ||
3806 | return false; | ||
3807 | |||
3808 | down(&bus->sdsem); | 3542 | down(&bus->sdsem); |
3809 | 3543 | ||
3810 | /* Poll period: check device if appropriate. */ | 3544 | /* Poll period: check device if appropriate. */ |
@@ -3818,27 +3552,30 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) | |||
3818 | if (!bus->intr || | 3552 | if (!bus->intr || |
3819 | (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) { | 3553 | (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) { |
3820 | 3554 | ||
3821 | if (!bus->dpc_sched) { | 3555 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); |
3556 | if (list_empty(&bus->dpc_tsklst)) { | ||
3822 | u8 devpend; | 3557 | u8 devpend; |
3558 | spin_unlock_irqrestore(&bus->dpc_tl_lock, | ||
3559 | flags); | ||
3823 | devpend = brcmf_sdio_regrb(bus->sdiodev, | 3560 | devpend = brcmf_sdio_regrb(bus->sdiodev, |
3824 | SDIO_CCCR_INTx, | 3561 | SDIO_CCCR_INTx, |
3825 | NULL); | 3562 | NULL); |
3826 | intstatus = | 3563 | intstatus = |
3827 | devpend & (INTR_STATUS_FUNC1 | | 3564 | devpend & (INTR_STATUS_FUNC1 | |
3828 | INTR_STATUS_FUNC2); | 3565 | INTR_STATUS_FUNC2); |
3566 | } else { | ||
3567 | spin_unlock_irqrestore(&bus->dpc_tl_lock, | ||
3568 | flags); | ||
3829 | } | 3569 | } |
3830 | 3570 | ||
3831 | /* If there is something, make like the ISR and | 3571 | /* If there is something, make like the ISR and |
3832 | schedule the DPC */ | 3572 | schedule the DPC */ |
3833 | if (intstatus) { | 3573 | if (intstatus) { |
3834 | bus->sdcnt.pollcnt++; | 3574 | bus->sdcnt.pollcnt++; |
3835 | bus->ipend = true; | 3575 | atomic_set(&bus->ipend, 1); |
3836 | 3576 | ||
3837 | bus->dpc_sched = true; | 3577 | brcmf_sdbrcm_adddpctsk(bus); |
3838 | if (bus->dpc_tsk) { | 3578 | queue_work(bus->brcmf_wq, &bus->datawork); |
3839 | brcmf_sdbrcm_adddpctsk(bus); | ||
3840 | complete(&bus->dpc_wait); | ||
3841 | } | ||
3842 | } | 3579 | } |
3843 | } | 3580 | } |
3844 | 3581 | ||
@@ -3876,7 +3613,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) | |||
3876 | 3613 | ||
3877 | up(&bus->sdsem); | 3614 | up(&bus->sdsem); |
3878 | 3615 | ||
3879 | return bus->ipend; | 3616 | return (atomic_read(&bus->ipend) > 0); |
3880 | } | 3617 | } |
3881 | 3618 | ||
3882 | static bool brcmf_sdbrcm_chipmatch(u16 chipid) | 3619 | static bool brcmf_sdbrcm_chipmatch(u16 chipid) |
@@ -3892,6 +3629,26 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid) | |||
3892 | return false; | 3629 | return false; |
3893 | } | 3630 | } |
3894 | 3631 | ||
3632 | static void brcmf_sdio_dataworker(struct work_struct *work) | ||
3633 | { | ||
3634 | struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio, | ||
3635 | datawork); | ||
3636 | struct list_head *cur_hd, *tmp_hd; | ||
3637 | unsigned long flags; | ||
3638 | |||
3639 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
3640 | list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) { | ||
3641 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
3642 | |||
3643 | brcmf_sdbrcm_dpc(bus); | ||
3644 | |||
3645 | spin_lock_irqsave(&bus->dpc_tl_lock, flags); | ||
3646 | list_del(cur_hd); | ||
3647 | kfree(cur_hd); | ||
3648 | } | ||
3649 | spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); | ||
3650 | } | ||
3651 | |||
3895 | static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus) | 3652 | static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus) |
3896 | { | 3653 | { |
3897 | brcmf_dbg(TRACE, "Enter\n"); | 3654 | brcmf_dbg(TRACE, "Enter\n"); |
@@ -4024,7 +3781,6 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) | |||
4024 | SDIO_FUNC_ENABLE_1, NULL); | 3781 | SDIO_FUNC_ENABLE_1, NULL); |
4025 | 3782 | ||
4026 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; | 3783 | bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; |
4027 | bus->sleeping = false; | ||
4028 | bus->rxflow = false; | 3784 | bus->rxflow = false; |
4029 | 3785 | ||
4030 | /* Done with backplane-dependent accesses, can drop clock... */ | 3786 | /* Done with backplane-dependent accesses, can drop clock... */ |
@@ -4105,6 +3861,9 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) | |||
4105 | /* De-register interrupt handler */ | 3861 | /* De-register interrupt handler */ |
4106 | brcmf_sdio_intr_unregister(bus->sdiodev); | 3862 | brcmf_sdio_intr_unregister(bus->sdiodev); |
4107 | 3863 | ||
3864 | cancel_work_sync(&bus->datawork); | ||
3865 | destroy_workqueue(bus->brcmf_wq); | ||
3866 | |||
4108 | if (bus->sdiodev->bus_if->drvr) { | 3867 | if (bus->sdiodev->bus_if->drvr) { |
4109 | brcmf_detach(bus->sdiodev->dev); | 3868 | brcmf_detach(bus->sdiodev->dev); |
4110 | brcmf_sdbrcm_release_dongle(bus); | 3869 | brcmf_sdbrcm_release_dongle(bus); |
@@ -4144,8 +3903,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) | |||
4144 | bus->rxbound = BRCMF_RXBOUND; | 3903 | bus->rxbound = BRCMF_RXBOUND; |
4145 | bus->txminmax = BRCMF_TXMINMAX; | 3904 | bus->txminmax = BRCMF_TXMINMAX; |
4146 | bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; | 3905 | bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; |
4147 | bus->usebufpool = false; /* Use bufpool if allocated, | ||
4148 | else use locally malloced rxbuf */ | ||
4149 | 3906 | ||
4150 | /* attempt to attach to the dongle */ | 3907 | /* attempt to attach to the dongle */ |
4151 | if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { | 3908 | if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { |
@@ -4157,6 +3914,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) | |||
4157 | init_waitqueue_head(&bus->ctrl_wait); | 3914 | init_waitqueue_head(&bus->ctrl_wait); |
4158 | init_waitqueue_head(&bus->dcmd_resp_wait); | 3915 | init_waitqueue_head(&bus->dcmd_resp_wait); |
4159 | 3916 | ||
3917 | bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); | ||
3918 | if (bus->brcmf_wq == NULL) { | ||
3919 | brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); | ||
3920 | goto fail; | ||
3921 | } | ||
3922 | INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); | ||
3923 | |||
4160 | /* Set up the watchdog timer */ | 3924 | /* Set up the watchdog timer */ |
4161 | init_timer(&bus->timer); | 3925 | init_timer(&bus->timer); |
4162 | bus->timer.data = (unsigned long)bus; | 3926 | bus->timer.data = (unsigned long)bus; |
@@ -4174,15 +3938,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) | |||
4174 | bus->watchdog_tsk = NULL; | 3938 | bus->watchdog_tsk = NULL; |
4175 | } | 3939 | } |
4176 | /* Initialize DPC thread */ | 3940 | /* Initialize DPC thread */ |
4177 | init_completion(&bus->dpc_wait); | ||
4178 | INIT_LIST_HEAD(&bus->dpc_tsklst); | 3941 | INIT_LIST_HEAD(&bus->dpc_tsklst); |
4179 | spin_lock_init(&bus->dpc_tl_lock); | 3942 | spin_lock_init(&bus->dpc_tl_lock); |
4180 | bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, | ||
4181 | bus, "brcmf_dpc"); | ||
4182 | if (IS_ERR(bus->dpc_tsk)) { | ||
4183 | pr_warn("brcmf_dpc thread failed to start\n"); | ||
4184 | bus->dpc_tsk = NULL; | ||
4185 | } | ||
4186 | 3943 | ||
4187 | /* Assign bus interface call back */ | 3944 | /* Assign bus interface call back */ |
4188 | bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop; | 3945 | bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 29bf78d264e0..0d30afd8c672 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h | |||
@@ -174,6 +174,8 @@ extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, | |||
174 | u8 data, int *ret); | 174 | u8 data, int *ret); |
175 | extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, | 175 | extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, |
176 | u32 data, int *ret); | 176 | u32 data, int *ret); |
177 | extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, | ||
178 | void *data, bool write); | ||
177 | 179 | ||
178 | /* Buffer transfer to/from device (client) core via cmd53. | 180 | /* Buffer transfer to/from device (client) core via cmd53. |
179 | * fn: function number | 181 | * fn: function number |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index c6d5aeb27a02..5fe6ec7f838e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c | |||
@@ -81,10 +81,12 @@ enum usbdev_suspend_state { | |||
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct brcmf_usb_image { | 83 | struct brcmf_usb_image { |
84 | void *data; | 84 | struct list_head list; |
85 | u32 len; | 85 | s8 *fwname; |
86 | u8 *image; | ||
87 | int image_len; | ||
86 | }; | 88 | }; |
87 | static struct brcmf_usb_image g_image = { NULL, 0 }; | 89 | static struct list_head fw_image_list; |
88 | 90 | ||
89 | struct intr_transfer_buf { | 91 | struct intr_transfer_buf { |
90 | u32 notification; | 92 | u32 notification; |
@@ -132,8 +134,6 @@ struct brcmf_usbdev_info { | |||
132 | wait_queue_head_t ctrl_wait; | 134 | wait_queue_head_t ctrl_wait; |
133 | ulong ctl_op; | 135 | ulong ctl_op; |
134 | 136 | ||
135 | bool rxctl_deferrespok; | ||
136 | |||
137 | struct urb *bulk_urb; /* used for FW download */ | 137 | struct urb *bulk_urb; /* used for FW download */ |
138 | struct urb *intr_urb; /* URB for interrupt endpoint */ | 138 | struct urb *intr_urb; /* URB for interrupt endpoint */ |
139 | int intr_size; /* Size of interrupt message */ | 139 | int intr_size; /* Size of interrupt message */ |
@@ -299,17 +299,9 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len) | |||
299 | devinfo->ctl_read.wLength = cpu_to_le16p(&size); | 299 | devinfo->ctl_read.wLength = cpu_to_le16p(&size); |
300 | devinfo->ctl_urb->transfer_buffer_length = size; | 300 | devinfo->ctl_urb->transfer_buffer_length = size; |
301 | 301 | ||
302 | if (devinfo->rxctl_deferrespok) { | 302 | devinfo->ctl_read.bRequestType = USB_DIR_IN |
303 | /* BMAC model */ | 303 | | USB_TYPE_CLASS | USB_RECIP_INTERFACE; |
304 | devinfo->ctl_read.bRequestType = USB_DIR_IN | 304 | devinfo->ctl_read.bRequest = 1; |
305 | | USB_TYPE_VENDOR | USB_RECIP_INTERFACE; | ||
306 | devinfo->ctl_read.bRequest = DL_DEFER_RESP_OK; | ||
307 | } else { | ||
308 | /* full dongle model */ | ||
309 | devinfo->ctl_read.bRequestType = USB_DIR_IN | ||
310 | | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
311 | devinfo->ctl_read.bRequest = 1; | ||
312 | } | ||
313 | 305 | ||
314 | usb_fill_control_urb(devinfo->ctl_urb, | 306 | usb_fill_control_urb(devinfo->ctl_urb, |
315 | devinfo->usbdev, | 307 | devinfo->usbdev, |
@@ -345,6 +337,7 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len) | |||
345 | err = brcmf_usb_send_ctl(devinfo, buf, len); | 337 | err = brcmf_usb_send_ctl(devinfo, buf, len); |
346 | if (err) { | 338 | if (err) { |
347 | brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); | 339 | brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); |
340 | clear_bit(0, &devinfo->ctl_op); | ||
348 | return err; | 341 | return err; |
349 | } | 342 | } |
350 | 343 | ||
@@ -375,6 +368,7 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len) | |||
375 | err = brcmf_usb_recv_ctl(devinfo, buf, len); | 368 | err = brcmf_usb_recv_ctl(devinfo, buf, len); |
376 | if (err) { | 369 | if (err) { |
377 | brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); | 370 | brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len); |
371 | clear_bit(0, &devinfo->ctl_op); | ||
378 | return err; | 372 | return err; |
379 | } | 373 | } |
380 | devinfo->ctl_completed = false; | 374 | devinfo->ctl_completed = false; |
@@ -1152,10 +1146,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo) | |||
1152 | { | 1146 | { |
1153 | brcmf_dbg(TRACE, "devinfo %p\n", devinfo); | 1147 | brcmf_dbg(TRACE, "devinfo %p\n", devinfo); |
1154 | 1148 | ||
1155 | /* store the image globally */ | ||
1156 | g_image.data = devinfo->image; | ||
1157 | g_image.len = devinfo->image_len; | ||
1158 | |||
1159 | /* free the URBS */ | 1149 | /* free the URBS */ |
1160 | brcmf_usb_free_q(&devinfo->rx_freeq, false); | 1150 | brcmf_usb_free_q(&devinfo->rx_freeq, false); |
1161 | brcmf_usb_free_q(&devinfo->tx_freeq, false); | 1151 | brcmf_usb_free_q(&devinfo->tx_freeq, false); |
@@ -1207,17 +1197,9 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) | |||
1207 | { | 1197 | { |
1208 | s8 *fwname; | 1198 | s8 *fwname; |
1209 | const struct firmware *fw; | 1199 | const struct firmware *fw; |
1200 | struct brcmf_usb_image *fw_image; | ||
1210 | int err; | 1201 | int err; |
1211 | 1202 | ||
1212 | devinfo->image = g_image.data; | ||
1213 | devinfo->image_len = g_image.len; | ||
1214 | |||
1215 | /* | ||
1216 | * if we have an image we can leave here. | ||
1217 | */ | ||
1218 | if (devinfo->image) | ||
1219 | return 0; | ||
1220 | |||
1221 | switch (devinfo->bus_pub.devid) { | 1203 | switch (devinfo->bus_pub.devid) { |
1222 | case 43143: | 1204 | case 43143: |
1223 | fwname = BRCMF_USB_43143_FW_NAME; | 1205 | fwname = BRCMF_USB_43143_FW_NAME; |
@@ -1235,6 +1217,14 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) | |||
1235 | break; | 1217 | break; |
1236 | } | 1218 | } |
1237 | 1219 | ||
1220 | list_for_each_entry(fw_image, &fw_image_list, list) { | ||
1221 | if (fw_image->fwname == fwname) { | ||
1222 | devinfo->image = fw_image->image; | ||
1223 | devinfo->image_len = fw_image->image_len; | ||
1224 | return 0; | ||
1225 | } | ||
1226 | } | ||
1227 | /* fw image not yet loaded. Load it now and add to list */ | ||
1238 | err = request_firmware(&fw, fwname, devinfo->dev); | 1228 | err = request_firmware(&fw, fwname, devinfo->dev); |
1239 | if (!fw) { | 1229 | if (!fw) { |
1240 | brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname); | 1230 | brcmf_dbg(ERROR, "fail to request firmware %s\n", fwname); |
@@ -1245,14 +1235,24 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) | |||
1245 | return -EINVAL; | 1235 | return -EINVAL; |
1246 | } | 1236 | } |
1247 | 1237 | ||
1248 | devinfo->image = vmalloc(fw->size); /* plus nvram */ | 1238 | fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC); |
1249 | if (!devinfo->image) | 1239 | if (!fw_image) |
1240 | return -ENOMEM; | ||
1241 | INIT_LIST_HEAD(&fw_image->list); | ||
1242 | list_add_tail(&fw_image->list, &fw_image_list); | ||
1243 | fw_image->fwname = fwname; | ||
1244 | fw_image->image = vmalloc(fw->size); | ||
1245 | if (!fw_image->image) | ||
1250 | return -ENOMEM; | 1246 | return -ENOMEM; |
1251 | 1247 | ||
1252 | memcpy(devinfo->image, fw->data, fw->size); | 1248 | memcpy(fw_image->image, fw->data, fw->size); |
1253 | devinfo->image_len = fw->size; | 1249 | fw_image->image_len = fw->size; |
1254 | 1250 | ||
1255 | release_firmware(fw); | 1251 | release_firmware(fw); |
1252 | |||
1253 | devinfo->image = fw_image->image; | ||
1254 | devinfo->image_len = fw_image->image_len; | ||
1255 | |||
1256 | return 0; | 1256 | return 0; |
1257 | } | 1257 | } |
1258 | 1258 | ||
@@ -1304,8 +1304,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo, | |||
1304 | brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n"); | 1304 | brcmf_dbg(ERROR, "usb_alloc_urb (ctl) failed\n"); |
1305 | goto error; | 1305 | goto error; |
1306 | } | 1306 | } |
1307 | devinfo->rxctl_deferrespok = 0; | ||
1308 | |||
1309 | devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC); | 1307 | devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC); |
1310 | if (!devinfo->bulk_urb) { | 1308 | if (!devinfo->bulk_urb) { |
1311 | brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n"); | 1309 | brcmf_dbg(ERROR, "usb_alloc_urb (bulk) failed\n"); |
@@ -1340,10 +1338,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, | |||
1340 | struct device *dev = devinfo->dev; | 1338 | struct device *dev = devinfo->dev; |
1341 | 1339 | ||
1342 | bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ); | 1340 | bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ); |
1343 | if (!bus_pub) { | 1341 | if (!bus_pub) |
1344 | ret = -ENODEV; | 1342 | return -ENODEV; |
1345 | goto fail; | ||
1346 | } | ||
1347 | 1343 | ||
1348 | bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); | 1344 | bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); |
1349 | if (!bus) { | 1345 | if (!bus) { |
@@ -1596,15 +1592,25 @@ static struct usb_driver brcmf_usbdrvr = { | |||
1596 | .disable_hub_initiated_lpm = 1, | 1592 | .disable_hub_initiated_lpm = 1, |
1597 | }; | 1593 | }; |
1598 | 1594 | ||
1595 | static void brcmf_release_fw(struct list_head *q) | ||
1596 | { | ||
1597 | struct brcmf_usb_image *fw_image, *next; | ||
1598 | |||
1599 | list_for_each_entry_safe(fw_image, next, q, list) { | ||
1600 | vfree(fw_image->image); | ||
1601 | list_del_init(&fw_image->list); | ||
1602 | } | ||
1603 | } | ||
1604 | |||
1605 | |||
1599 | void brcmf_usb_exit(void) | 1606 | void brcmf_usb_exit(void) |
1600 | { | 1607 | { |
1601 | usb_deregister(&brcmf_usbdrvr); | 1608 | usb_deregister(&brcmf_usbdrvr); |
1602 | vfree(g_image.data); | 1609 | brcmf_release_fw(&fw_image_list); |
1603 | g_image.data = NULL; | ||
1604 | g_image.len = 0; | ||
1605 | } | 1610 | } |
1606 | 1611 | ||
1607 | void brcmf_usb_init(void) | 1612 | void brcmf_usb_init(void) |
1608 | { | 1613 | { |
1614 | INIT_LIST_HEAD(&fw_image_list); | ||
1609 | usb_register(&brcmf_usbdrvr); | 1615 | usb_register(&brcmf_usbdrvr); |
1610 | } | 1616 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 32ee05297ccf..af396e4ab977 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -36,6 +36,18 @@ | |||
36 | #include "dhd.h" | 36 | #include "dhd.h" |
37 | #include "wl_cfg80211.h" | 37 | #include "wl_cfg80211.h" |
38 | 38 | ||
39 | #define BRCMF_SCAN_IE_LEN_MAX 2048 | ||
40 | #define BRCMF_PNO_VERSION 2 | ||
41 | #define BRCMF_PNO_TIME 30 | ||
42 | #define BRCMF_PNO_REPEAT 4 | ||
43 | #define BRCMF_PNO_FREQ_EXPO_MAX 3 | ||
44 | #define BRCMF_PNO_MAX_PFN_COUNT 16 | ||
45 | #define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6 | ||
46 | #define BRCMF_PNO_HIDDEN_BIT 2 | ||
47 | #define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF | ||
48 | #define BRCMF_PNO_SCAN_COMPLETE 1 | ||
49 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 | ||
50 | |||
39 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ | 51 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ |
40 | (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) | 52 | (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) |
41 | 53 | ||
@@ -700,11 +712,11 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | |||
700 | u32 n_channels; | 712 | u32 n_channels; |
701 | s32 i; | 713 | s32 i; |
702 | s32 offset; | 714 | s32 offset; |
703 | __le16 chanspec; | 715 | u16 chanspec; |
704 | u16 channel; | 716 | u16 channel; |
705 | struct ieee80211_channel *req_channel; | 717 | struct ieee80211_channel *req_channel; |
706 | char *ptr; | 718 | char *ptr; |
707 | struct brcmf_ssid ssid; | 719 | struct brcmf_ssid_le ssid_le; |
708 | 720 | ||
709 | memcpy(params_le->bssid, ether_bcast, ETH_ALEN); | 721 | memcpy(params_le->bssid, ether_bcast, ETH_ALEN); |
710 | params_le->bss_type = DOT11_BSSTYPE_ANY; | 722 | params_le->bss_type = DOT11_BSSTYPE_ANY; |
@@ -747,13 +759,10 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | |||
747 | chanspec |= WL_CHANSPEC_CTL_SB_UPPER; | 759 | chanspec |= WL_CHANSPEC_CTL_SB_UPPER; |
748 | } | 760 | } |
749 | 761 | ||
750 | params_le->channel_list[i] = | 762 | chanspec |= (channel & WL_CHANSPEC_CHAN_MASK); |
751 | (channel & WL_CHANSPEC_CHAN_MASK) | | ||
752 | chanspec; | ||
753 | WL_SCAN("Chan : %d, Channel spec: %x\n", | 763 | WL_SCAN("Chan : %d, Channel spec: %x\n", |
754 | channel, params_le->channel_list[i]); | 764 | channel, chanspec); |
755 | params_le->channel_list[i] = | 765 | params_le->channel_list[i] = cpu_to_le16(chanspec); |
756 | cpu_to_le16(params_le->channel_list[i]); | ||
757 | } | 766 | } |
758 | } else { | 767 | } else { |
759 | WL_SCAN("Scanning all channels\n"); | 768 | WL_SCAN("Scanning all channels\n"); |
@@ -766,17 +775,18 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | |||
766 | offset = roundup(offset, sizeof(u32)); | 775 | offset = roundup(offset, sizeof(u32)); |
767 | ptr = (char *)params_le + offset; | 776 | ptr = (char *)params_le + offset; |
768 | for (i = 0; i < n_ssids; i++) { | 777 | for (i = 0; i < n_ssids; i++) { |
769 | memset(&ssid, 0, sizeof(ssid)); | 778 | memset(&ssid_le, 0, sizeof(ssid_le)); |
770 | ssid.SSID_len = cpu_to_le32(request->ssids[i].ssid_len); | 779 | ssid_le.SSID_len = |
771 | memcpy(ssid.SSID, request->ssids[i].ssid, | 780 | cpu_to_le32(request->ssids[i].ssid_len); |
772 | request->ssids[i].ssid_len); | 781 | memcpy(ssid_le.SSID, request->ssids[i].ssid, |
773 | if (!ssid.SSID_len) | 782 | request->ssids[i].ssid_len); |
783 | if (!ssid_le.SSID_len) | ||
774 | WL_SCAN("%d: Broadcast scan\n", i); | 784 | WL_SCAN("%d: Broadcast scan\n", i); |
775 | else | 785 | else |
776 | WL_SCAN("%d: scan for %s size =%d\n", i, | 786 | WL_SCAN("%d: scan for %s size =%d\n", i, |
777 | ssid.SSID, ssid.SSID_len); | 787 | ssid_le.SSID, ssid_le.SSID_len); |
778 | memcpy(ptr, &ssid, sizeof(ssid)); | 788 | memcpy(ptr, &ssid_le, sizeof(ssid_le)); |
779 | ptr += sizeof(ssid); | 789 | ptr += sizeof(ssid_le); |
780 | } | 790 | } |
781 | } else { | 791 | } else { |
782 | WL_SCAN("Broadcast scan %p\n", request->ssids); | 792 | WL_SCAN("Broadcast scan %p\n", request->ssids); |
@@ -834,7 +844,17 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv, | |||
834 | if (err) | 844 | if (err) |
835 | WL_ERR("Scan abort failed\n"); | 845 | WL_ERR("Scan abort failed\n"); |
836 | } | 846 | } |
837 | if (scan_request) { | 847 | /* |
848 | * e-scan can be initiated by scheduled scan | ||
849 | * which takes precedence. | ||
850 | */ | ||
851 | if (cfg_priv->sched_escan) { | ||
852 | WL_SCAN("scheduled scan completed\n"); | ||
853 | cfg_priv->sched_escan = false; | ||
854 | if (!aborted) | ||
855 | cfg80211_sched_scan_results(cfg_to_wiphy(cfg_priv)); | ||
856 | brcmf_set_mpc(ndev, 1); | ||
857 | } else if (scan_request) { | ||
838 | WL_SCAN("ESCAN Completed scan: %s\n", | 858 | WL_SCAN("ESCAN Completed scan: %s\n", |
839 | aborted ? "Aborted" : "Done"); | 859 | aborted ? "Aborted" : "Done"); |
840 | cfg80211_scan_done(scan_request, aborted); | 860 | cfg80211_scan_done(scan_request, aborted); |
@@ -2593,11 +2613,13 @@ update_bss_info_out: | |||
2593 | return err; | 2613 | return err; |
2594 | } | 2614 | } |
2595 | 2615 | ||
2596 | static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) | 2616 | static void brcmf_abort_scanning(struct brcmf_cfg80211_priv *cfg_priv) |
2597 | { | 2617 | { |
2598 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); | 2618 | struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); |
2619 | struct escan_info *escan = &cfg_priv->escan_info; | ||
2599 | struct brcmf_ssid ssid; | 2620 | struct brcmf_ssid ssid; |
2600 | 2621 | ||
2622 | set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
2601 | if (cfg_priv->iscan_on) { | 2623 | if (cfg_priv->iscan_on) { |
2602 | iscan->state = WL_ISCAN_STATE_IDLE; | 2624 | iscan->state = WL_ISCAN_STATE_IDLE; |
2603 | 2625 | ||
@@ -2611,7 +2633,20 @@ static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) | |||
2611 | /* Abort iscan running in FW */ | 2633 | /* Abort iscan running in FW */ |
2612 | memset(&ssid, 0, sizeof(ssid)); | 2634 | memset(&ssid, 0, sizeof(ssid)); |
2613 | brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); | 2635 | brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); |
2636 | |||
2637 | if (cfg_priv->scan_request) { | ||
2638 | /* Indidate scan abort to cfg80211 layer */ | ||
2639 | WL_INFO("Terminating scan in progress\n"); | ||
2640 | cfg80211_scan_done(cfg_priv->scan_request, true); | ||
2641 | cfg_priv->scan_request = NULL; | ||
2642 | } | ||
2614 | } | 2643 | } |
2644 | if (cfg_priv->escan_on && cfg_priv->scan_request) { | ||
2645 | escan->escan_state = WL_ESCAN_STATE_IDLE; | ||
2646 | brcmf_notify_escan_complete(cfg_priv, escan->ndev, true, true); | ||
2647 | } | ||
2648 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
2649 | clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
2615 | } | 2650 | } |
2616 | 2651 | ||
2617 | static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, | 2652 | static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, |
@@ -2842,10 +2877,13 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss, | |||
2842 | !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) { | 2877 | !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) { |
2843 | if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == | 2878 | if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == |
2844 | (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) { | 2879 | (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) { |
2880 | s16 bss_rssi = le16_to_cpu(bss->RSSI); | ||
2881 | s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI); | ||
2882 | |||
2845 | /* preserve max RSSI if the measurements are | 2883 | /* preserve max RSSI if the measurements are |
2846 | * both on-channel or both off-channel | 2884 | * both on-channel or both off-channel |
2847 | */ | 2885 | */ |
2848 | if (bss_info_le->RSSI > bss->RSSI) | 2886 | if (bss_info_rssi > bss_rssi) |
2849 | bss->RSSI = bss_info_le->RSSI; | 2887 | bss->RSSI = bss_info_le->RSSI; |
2850 | } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && | 2888 | } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && |
2851 | (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { | 2889 | (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { |
@@ -2873,6 +2911,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, | |||
2873 | u32 bi_length; | 2911 | u32 bi_length; |
2874 | struct brcmf_scan_results *list; | 2912 | struct brcmf_scan_results *list; |
2875 | u32 i; | 2913 | u32 i; |
2914 | bool aborted; | ||
2876 | 2915 | ||
2877 | status = be32_to_cpu(e->status); | 2916 | status = be32_to_cpu(e->status); |
2878 | 2917 | ||
@@ -2945,16 +2984,9 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv, | |||
2945 | cfg_priv->bss_list = (struct brcmf_scan_results *) | 2984 | cfg_priv->bss_list = (struct brcmf_scan_results *) |
2946 | cfg_priv->escan_info.escan_buf; | 2985 | cfg_priv->escan_info.escan_buf; |
2947 | brcmf_inform_bss(cfg_priv); | 2986 | brcmf_inform_bss(cfg_priv); |
2948 | if (status == BRCMF_E_STATUS_SUCCESS) { | 2987 | aborted = status != BRCMF_E_STATUS_SUCCESS; |
2949 | WL_SCAN("ESCAN Completed\n"); | 2988 | brcmf_notify_escan_complete(cfg_priv, ndev, aborted, |
2950 | brcmf_notify_escan_complete(cfg_priv, ndev, | 2989 | false); |
2951 | false, false); | ||
2952 | } else { | ||
2953 | WL_ERR("ESCAN Aborted, Event 0x%x\n", status); | ||
2954 | brcmf_notify_escan_complete(cfg_priv, ndev, | ||
2955 | true, false); | ||
2956 | } | ||
2957 | brcmf_set_mpc(ndev, 1); | ||
2958 | } else | 2990 | } else |
2959 | WL_ERR("Unexpected scan result 0x%x\n", status); | 2991 | WL_ERR("Unexpected scan result 0x%x\n", status); |
2960 | } | 2992 | } |
@@ -3039,18 +3071,10 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, | |||
3039 | brcmf_delay(500); | 3071 | brcmf_delay(500); |
3040 | } | 3072 | } |
3041 | 3073 | ||
3042 | set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
3043 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) | 3074 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) |
3044 | brcmf_term_iscan(cfg_priv); | 3075 | brcmf_abort_scanning(cfg_priv); |
3045 | 3076 | else | |
3046 | if (cfg_priv->scan_request) { | 3077 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); |
3047 | /* Indidate scan abort to cfg80211 layer */ | ||
3048 | WL_INFO("Terminating scan in progress\n"); | ||
3049 | cfg80211_scan_done(cfg_priv->scan_request, true); | ||
3050 | cfg_priv->scan_request = NULL; | ||
3051 | } | ||
3052 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
3053 | clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
3054 | 3078 | ||
3055 | /* Turn off watchdog timer */ | 3079 | /* Turn off watchdog timer */ |
3056 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) | 3080 | if (test_bit(WL_STATUS_READY, &cfg_priv->status)) |
@@ -3229,6 +3253,269 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) | |||
3229 | 3253 | ||
3230 | } | 3254 | } |
3231 | 3255 | ||
3256 | /* | ||
3257 | * PFN result doesn't have all the info which are | ||
3258 | * required by the supplicant | ||
3259 | * (For e.g IEs) Do a target Escan so that sched scan results are reported | ||
3260 | * via wl_inform_single_bss in the required format. Escan does require the | ||
3261 | * scan request in the form of cfg80211_scan_request. For timebeing, create | ||
3262 | * cfg80211_scan_request one out of the received PNO event. | ||
3263 | */ | ||
3264 | static s32 | ||
3265 | brcmf_notify_sched_scan_results(struct brcmf_cfg80211_priv *cfg_priv, | ||
3266 | struct net_device *ndev, | ||
3267 | const struct brcmf_event_msg *e, void *data) | ||
3268 | { | ||
3269 | struct brcmf_pno_net_info_le *netinfo, *netinfo_start; | ||
3270 | struct cfg80211_scan_request *request = NULL; | ||
3271 | struct cfg80211_ssid *ssid = NULL; | ||
3272 | struct ieee80211_channel *channel = NULL; | ||
3273 | struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); | ||
3274 | int err = 0; | ||
3275 | int channel_req = 0; | ||
3276 | int band = 0; | ||
3277 | struct brcmf_pno_scanresults_le *pfn_result; | ||
3278 | u32 result_count; | ||
3279 | u32 status; | ||
3280 | |||
3281 | WL_SCAN("Enter\n"); | ||
3282 | |||
3283 | if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) { | ||
3284 | WL_SCAN("PFN NET LOST event. Do Nothing\n"); | ||
3285 | return 0; | ||
3286 | } | ||
3287 | |||
3288 | pfn_result = (struct brcmf_pno_scanresults_le *)data; | ||
3289 | result_count = le32_to_cpu(pfn_result->count); | ||
3290 | status = le32_to_cpu(pfn_result->status); | ||
3291 | |||
3292 | /* | ||
3293 | * PFN event is limited to fit 512 bytes so we may get | ||
3294 | * multiple NET_FOUND events. For now place a warning here. | ||
3295 | */ | ||
3296 | WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); | ||
3297 | WL_SCAN("PFN NET FOUND event. count: %d\n", result_count); | ||
3298 | if (result_count > 0) { | ||
3299 | int i; | ||
3300 | |||
3301 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
3302 | ssid = kzalloc(sizeof(*ssid) * result_count, GFP_KERNEL); | ||
3303 | channel = kzalloc(sizeof(*channel) * result_count, GFP_KERNEL); | ||
3304 | if (!request || !ssid || !channel) { | ||
3305 | err = -ENOMEM; | ||
3306 | goto out_err; | ||
3307 | } | ||
3308 | |||
3309 | request->wiphy = wiphy; | ||
3310 | data += sizeof(struct brcmf_pno_scanresults_le); | ||
3311 | netinfo_start = (struct brcmf_pno_net_info_le *)data; | ||
3312 | |||
3313 | for (i = 0; i < result_count; i++) { | ||
3314 | netinfo = &netinfo_start[i]; | ||
3315 | if (!netinfo) { | ||
3316 | WL_ERR("Invalid netinfo ptr. index: %d\n", i); | ||
3317 | err = -EINVAL; | ||
3318 | goto out_err; | ||
3319 | } | ||
3320 | |||
3321 | WL_SCAN("SSID:%s Channel:%d\n", | ||
3322 | netinfo->SSID, netinfo->channel); | ||
3323 | memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len); | ||
3324 | ssid[i].ssid_len = netinfo->SSID_len; | ||
3325 | request->n_ssids++; | ||
3326 | |||
3327 | channel_req = netinfo->channel; | ||
3328 | if (channel_req <= CH_MAX_2G_CHANNEL) | ||
3329 | band = NL80211_BAND_2GHZ; | ||
3330 | else | ||
3331 | band = NL80211_BAND_5GHZ; | ||
3332 | channel[i].center_freq = | ||
3333 | ieee80211_channel_to_frequency(channel_req, | ||
3334 | band); | ||
3335 | channel[i].band = band; | ||
3336 | channel[i].flags |= IEEE80211_CHAN_NO_HT40; | ||
3337 | request->channels[i] = &channel[i]; | ||
3338 | request->n_channels++; | ||
3339 | } | ||
3340 | |||
3341 | /* assign parsed ssid array */ | ||
3342 | if (request->n_ssids) | ||
3343 | request->ssids = &ssid[0]; | ||
3344 | |||
3345 | if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { | ||
3346 | /* Abort any on-going scan */ | ||
3347 | brcmf_abort_scanning(cfg_priv); | ||
3348 | } | ||
3349 | |||
3350 | set_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
3351 | err = brcmf_do_escan(cfg_priv, wiphy, ndev, request); | ||
3352 | if (err) { | ||
3353 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
3354 | goto out_err; | ||
3355 | } | ||
3356 | cfg_priv->sched_escan = true; | ||
3357 | cfg_priv->scan_request = request; | ||
3358 | } else { | ||
3359 | WL_ERR("FALSE PNO Event. (pfn_count == 0)\n"); | ||
3360 | goto out_err; | ||
3361 | } | ||
3362 | |||
3363 | kfree(ssid); | ||
3364 | kfree(channel); | ||
3365 | kfree(request); | ||
3366 | return 0; | ||
3367 | |||
3368 | out_err: | ||
3369 | kfree(ssid); | ||
3370 | kfree(channel); | ||
3371 | kfree(request); | ||
3372 | cfg80211_sched_scan_stopped(wiphy); | ||
3373 | return err; | ||
3374 | } | ||
3375 | |||
3376 | #ifndef CONFIG_BRCMISCAN | ||
3377 | static int brcmf_dev_pno_clean(struct net_device *ndev) | ||
3378 | { | ||
3379 | char iovbuf[128]; | ||
3380 | int ret; | ||
3381 | |||
3382 | /* Disable pfn */ | ||
3383 | ret = brcmf_dev_intvar_set(ndev, "pfn", 0); | ||
3384 | if (ret == 0) { | ||
3385 | /* clear pfn */ | ||
3386 | ret = brcmf_dev_iovar_setbuf(ndev, "pfnclear", NULL, 0, | ||
3387 | iovbuf, sizeof(iovbuf)); | ||
3388 | } | ||
3389 | if (ret < 0) | ||
3390 | WL_ERR("failed code %d\n", ret); | ||
3391 | |||
3392 | return ret; | ||
3393 | } | ||
3394 | |||
3395 | static int brcmf_dev_pno_config(struct net_device *ndev) | ||
3396 | { | ||
3397 | struct brcmf_pno_param_le pfn_param; | ||
3398 | char iovbuf[128]; | ||
3399 | |||
3400 | memset(&pfn_param, 0, sizeof(pfn_param)); | ||
3401 | pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); | ||
3402 | |||
3403 | /* set extra pno params */ | ||
3404 | pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); | ||
3405 | pfn_param.repeat = BRCMF_PNO_REPEAT; | ||
3406 | pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; | ||
3407 | |||
3408 | /* set up pno scan fr */ | ||
3409 | pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); | ||
3410 | |||
3411 | return brcmf_dev_iovar_setbuf(ndev, "pfn_set", | ||
3412 | &pfn_param, sizeof(pfn_param), | ||
3413 | iovbuf, sizeof(iovbuf)); | ||
3414 | } | ||
3415 | |||
3416 | static int | ||
3417 | brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, | ||
3418 | struct net_device *ndev, | ||
3419 | struct cfg80211_sched_scan_request *request) | ||
3420 | { | ||
3421 | char iovbuf[128]; | ||
3422 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_priv(wiphy); | ||
3423 | struct brcmf_pno_net_param_le pfn; | ||
3424 | int i; | ||
3425 | int ret = 0; | ||
3426 | |||
3427 | WL_SCAN("Enter n_match_sets:%d n_ssids:%d\n", | ||
3428 | request->n_match_sets, request->n_ssids); | ||
3429 | if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { | ||
3430 | WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); | ||
3431 | return -EAGAIN; | ||
3432 | } | ||
3433 | |||
3434 | if (!request || !request->n_ssids || !request->n_match_sets) { | ||
3435 | WL_ERR("Invalid sched scan req!! n_ssids:%d\n", | ||
3436 | request->n_ssids); | ||
3437 | return -EINVAL; | ||
3438 | } | ||
3439 | |||
3440 | if (request->n_ssids > 0) { | ||
3441 | for (i = 0; i < request->n_ssids; i++) { | ||
3442 | /* Active scan req for ssids */ | ||
3443 | WL_SCAN(">>> Active scan req for ssid (%s)\n", | ||
3444 | request->ssids[i].ssid); | ||
3445 | |||
3446 | /* | ||
3447 | * match_set ssids is a supert set of n_ssid list, | ||
3448 | * so we need not add these set seperately. | ||
3449 | */ | ||
3450 | } | ||
3451 | } | ||
3452 | |||
3453 | if (request->n_match_sets > 0) { | ||
3454 | /* clean up everything */ | ||
3455 | ret = brcmf_dev_pno_clean(ndev); | ||
3456 | if (ret < 0) { | ||
3457 | WL_ERR("failed error=%d\n", ret); | ||
3458 | return ret; | ||
3459 | } | ||
3460 | |||
3461 | /* configure pno */ | ||
3462 | ret = brcmf_dev_pno_config(ndev); | ||
3463 | if (ret < 0) { | ||
3464 | WL_ERR("PNO setup failed!! ret=%d\n", ret); | ||
3465 | return -EINVAL; | ||
3466 | } | ||
3467 | |||
3468 | /* configure each match set */ | ||
3469 | for (i = 0; i < request->n_match_sets; i++) { | ||
3470 | struct cfg80211_ssid *ssid; | ||
3471 | u32 ssid_len; | ||
3472 | |||
3473 | ssid = &request->match_sets[i].ssid; | ||
3474 | ssid_len = ssid->ssid_len; | ||
3475 | |||
3476 | if (!ssid_len) { | ||
3477 | WL_ERR("skip broadcast ssid\n"); | ||
3478 | continue; | ||
3479 | } | ||
3480 | pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); | ||
3481 | pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); | ||
3482 | pfn.wsec = cpu_to_le32(0); | ||
3483 | pfn.infra = cpu_to_le32(1); | ||
3484 | pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); | ||
3485 | pfn.ssid.SSID_len = cpu_to_le32(ssid_len); | ||
3486 | memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len); | ||
3487 | ret = brcmf_dev_iovar_setbuf(ndev, "pfn_add", | ||
3488 | &pfn, sizeof(pfn), | ||
3489 | iovbuf, sizeof(iovbuf)); | ||
3490 | WL_SCAN(">>> PNO filter %s for ssid (%s)\n", | ||
3491 | ret == 0 ? "set" : "failed", | ||
3492 | ssid->ssid); | ||
3493 | } | ||
3494 | /* Enable the PNO */ | ||
3495 | if (brcmf_dev_intvar_set(ndev, "pfn", 1) < 0) { | ||
3496 | WL_ERR("PNO enable failed!! ret=%d\n", ret); | ||
3497 | return -EINVAL; | ||
3498 | } | ||
3499 | } else { | ||
3500 | return -EINVAL; | ||
3501 | } | ||
3502 | |||
3503 | return 0; | ||
3504 | } | ||
3505 | |||
3506 | static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, | ||
3507 | struct net_device *ndev) | ||
3508 | { | ||
3509 | struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); | ||
3510 | |||
3511 | WL_SCAN("enter\n"); | ||
3512 | brcmf_dev_pno_clean(ndev); | ||
3513 | if (cfg_priv->sched_escan) | ||
3514 | brcmf_notify_escan_complete(cfg_priv, ndev, true, true); | ||
3515 | return 0; | ||
3516 | } | ||
3517 | #endif /* CONFIG_BRCMISCAN */ | ||
3518 | |||
3232 | #ifdef CONFIG_NL80211_TESTMODE | 3519 | #ifdef CONFIG_NL80211_TESTMODE |
3233 | static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) | 3520 | static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) |
3234 | { | 3521 | { |
@@ -3271,6 +3558,11 @@ static struct cfg80211_ops wl_cfg80211_ops = { | |||
3271 | .set_pmksa = brcmf_cfg80211_set_pmksa, | 3558 | .set_pmksa = brcmf_cfg80211_set_pmksa, |
3272 | .del_pmksa = brcmf_cfg80211_del_pmksa, | 3559 | .del_pmksa = brcmf_cfg80211_del_pmksa, |
3273 | .flush_pmksa = brcmf_cfg80211_flush_pmksa, | 3560 | .flush_pmksa = brcmf_cfg80211_flush_pmksa, |
3561 | #ifndef CONFIG_BRCMISCAN | ||
3562 | /* scheduled scan need e-scan, which is mutual exclusive with i-scan */ | ||
3563 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, | ||
3564 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, | ||
3565 | #endif | ||
3274 | #ifdef CONFIG_NL80211_TESTMODE | 3566 | #ifdef CONFIG_NL80211_TESTMODE |
3275 | .testmode_cmd = brcmf_cfg80211_testmode | 3567 | .testmode_cmd = brcmf_cfg80211_testmode |
3276 | #endif | 3568 | #endif |
@@ -3292,6 +3584,17 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode) | |||
3292 | return err; | 3584 | return err; |
3293 | } | 3585 | } |
3294 | 3586 | ||
3587 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | ||
3588 | { | ||
3589 | #ifndef CONFIG_BRCMFISCAN | ||
3590 | /* scheduled scan settings */ | ||
3591 | wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; | ||
3592 | wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; | ||
3593 | wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; | ||
3594 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
3595 | #endif | ||
3596 | } | ||
3597 | |||
3295 | static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, | 3598 | static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, |
3296 | struct device *ndev) | 3599 | struct device *ndev) |
3297 | { | 3600 | { |
@@ -3330,6 +3633,7 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, | |||
3330 | * save mode | 3633 | * save mode |
3331 | * by default | 3634 | * by default |
3332 | */ | 3635 | */ |
3636 | brcmf_wiphy_pno_params(wdev->wiphy); | ||
3333 | err = wiphy_register(wdev->wiphy); | 3637 | err = wiphy_register(wdev->wiphy); |
3334 | if (err < 0) { | 3638 | if (err < 0) { |
3335 | WL_ERR("Could not register wiphy device (%d)\n", err); | 3639 | WL_ERR("Could not register wiphy device (%d)\n", err); |
@@ -3732,6 +4036,7 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) | |||
3732 | el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; | 4036 | el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; |
3733 | el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; | 4037 | el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; |
3734 | el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; | 4038 | el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; |
4039 | el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results; | ||
3735 | } | 4040 | } |
3736 | 4041 | ||
3737 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) | 4042 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) |
@@ -3957,13 +4262,13 @@ static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) | |||
3957 | cfg_priv->dongle_up = false; /* dongle down */ | 4262 | cfg_priv->dongle_up = false; /* dongle down */ |
3958 | brcmf_flush_eq(cfg_priv); | 4263 | brcmf_flush_eq(cfg_priv); |
3959 | brcmf_link_down(cfg_priv); | 4264 | brcmf_link_down(cfg_priv); |
3960 | brcmf_term_iscan(cfg_priv); | 4265 | brcmf_abort_scanning(cfg_priv); |
3961 | brcmf_deinit_priv_mem(cfg_priv); | 4266 | brcmf_deinit_priv_mem(cfg_priv); |
3962 | } | 4267 | } |
3963 | 4268 | ||
3964 | struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, | 4269 | struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, |
3965 | struct device *busdev, | 4270 | struct device *busdev, |
3966 | void *data) | 4271 | struct brcmf_pub *drvr) |
3967 | { | 4272 | { |
3968 | struct wireless_dev *wdev; | 4273 | struct wireless_dev *wdev; |
3969 | struct brcmf_cfg80211_priv *cfg_priv; | 4274 | struct brcmf_cfg80211_priv *cfg_priv; |
@@ -3988,7 +4293,7 @@ struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, | |||
3988 | wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); | 4293 | wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); |
3989 | cfg_priv = wdev_to_cfg(wdev); | 4294 | cfg_priv = wdev_to_cfg(wdev); |
3990 | cfg_priv->wdev = wdev; | 4295 | cfg_priv->wdev = wdev; |
3991 | cfg_priv->pub = data; | 4296 | cfg_priv->pub = drvr; |
3992 | ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; | 4297 | ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; |
3993 | ci->cfg_priv = cfg_priv; | 4298 | ci->cfg_priv = cfg_priv; |
3994 | ndev->ieee80211_ptr = wdev; | 4299 | ndev->ieee80211_ptr = wdev; |
@@ -4103,6 +4408,7 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev) | |||
4103 | setbit(eventmask, BRCMF_E_JOIN_START); | 4408 | setbit(eventmask, BRCMF_E_JOIN_START); |
4104 | setbit(eventmask, BRCMF_E_SCAN_COMPLETE); | 4409 | setbit(eventmask, BRCMF_E_SCAN_COMPLETE); |
4105 | setbit(eventmask, BRCMF_E_ESCAN_RESULT); | 4410 | setbit(eventmask, BRCMF_E_ESCAN_RESULT); |
4411 | setbit(eventmask, BRCMF_E_PFN_NET_FOUND); | ||
4106 | 4412 | ||
4107 | brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, | 4413 | brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, |
4108 | iovbuf, sizeof(iovbuf)); | 4414 | iovbuf, sizeof(iovbuf)); |
@@ -4235,7 +4541,7 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) | |||
4235 | return err; | 4541 | return err; |
4236 | } | 4542 | } |
4237 | 4543 | ||
4238 | phy = ((char *)&phy_list)[1]; | 4544 | phy = ((char *)&phy_list)[0]; |
4239 | WL_INFO("%c phy\n", phy); | 4545 | WL_INFO("%c phy\n", phy); |
4240 | if (phy == 'n' || phy == 'a') { | 4546 | if (phy == 'n' || phy == 'a') { |
4241 | wiphy = cfg_to_wiphy(cfg_priv); | 4547 | wiphy = cfg_to_wiphy(cfg_priv); |
@@ -4368,17 +4674,8 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) | |||
4368 | brcmf_delay(500); | 4674 | brcmf_delay(500); |
4369 | } | 4675 | } |
4370 | 4676 | ||
4371 | set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | 4677 | brcmf_abort_scanning(cfg_priv); |
4372 | brcmf_term_iscan(cfg_priv); | ||
4373 | if (cfg_priv->scan_request) { | ||
4374 | cfg80211_scan_done(cfg_priv->scan_request, true); | ||
4375 | /* May need to perform this to cover rmmod */ | ||
4376 | /* wl_set_mpc(cfg_to_ndev(wl), 1); */ | ||
4377 | cfg_priv->scan_request = NULL; | ||
4378 | } | ||
4379 | clear_bit(WL_STATUS_READY, &cfg_priv->status); | 4678 | clear_bit(WL_STATUS_READY, &cfg_priv->status); |
4380 | clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); | ||
4381 | clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); | ||
4382 | 4679 | ||
4383 | brcmf_debugfs_remove_netdev(cfg_priv); | 4680 | brcmf_debugfs_remove_netdev(cfg_priv); |
4384 | 4681 | ||
@@ -4411,20 +4708,3 @@ s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) | |||
4411 | return err; | 4708 | return err; |
4412 | } | 4709 | } |
4413 | 4710 | ||
4414 | static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, | ||
4415 | u8 t, u8 l, u8 *v) | ||
4416 | { | ||
4417 | struct brcmf_cfg80211_ie *ie = &cfg_priv->ie; | ||
4418 | s32 err = 0; | ||
4419 | |||
4420 | if (ie->offset + l + 2 > WL_TLV_INFO_MAX) { | ||
4421 | WL_ERR("ei crosses buffer boundary\n"); | ||
4422 | return -ENOSPC; | ||
4423 | } | ||
4424 | ie->buf[ie->offset] = t; | ||
4425 | ie->buf[ie->offset + 1] = l; | ||
4426 | memcpy(&ie->buf[ie->offset + 2], v, l); | ||
4427 | ie->offset += l + 2; | ||
4428 | |||
4429 | return err; | ||
4430 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 3b2129738d30..52e408ed6f41 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -295,50 +295,168 @@ struct escan_info { | |||
295 | struct net_device *ndev; | 295 | struct net_device *ndev; |
296 | }; | 296 | }; |
297 | 297 | ||
298 | /* dongle private data of cfg80211 interface */ | 298 | /** |
299 | * struct brcmf_pno_param_le - PNO scan configuration parameters | ||
300 | * | ||
301 | * @version: PNO parameters version. | ||
302 | * @scan_freq: scan frequency. | ||
303 | * @lost_network_timeout: #sec. to declare discovered network as lost. | ||
304 | * @flags: Bit field to control features of PFN such as sort criteria auto | ||
305 | * enable switch and background scan. | ||
306 | * @rssi_margin: Margin to avoid jitter for choosing a PFN based on RSSI sort | ||
307 | * criteria. | ||
308 | * @bestn: number of best networks in each scan. | ||
309 | * @mscan: number of scans recorded. | ||
310 | * @repeat: minimum number of scan intervals before scan frequency changes | ||
311 | * in adaptive scan. | ||
312 | * @exp: exponent of 2 for maximum scan interval. | ||
313 | * @slow_freq: slow scan period. | ||
314 | */ | ||
315 | struct brcmf_pno_param_le { | ||
316 | __le32 version; | ||
317 | __le32 scan_freq; | ||
318 | __le32 lost_network_timeout; | ||
319 | __le16 flags; | ||
320 | __le16 rssi_margin; | ||
321 | u8 bestn; | ||
322 | u8 mscan; | ||
323 | u8 repeat; | ||
324 | u8 exp; | ||
325 | __le32 slow_freq; | ||
326 | }; | ||
327 | |||
328 | /** | ||
329 | * struct brcmf_pno_net_param_le - scan parameters per preferred network. | ||
330 | * | ||
331 | * @ssid: ssid name and its length. | ||
332 | * @flags: bit2: hidden. | ||
333 | * @infra: BSS vs IBSS. | ||
334 | * @auth: Open vs Closed. | ||
335 | * @wpa_auth: WPA type. | ||
336 | * @wsec: wsec value. | ||
337 | */ | ||
338 | struct brcmf_pno_net_param_le { | ||
339 | struct brcmf_ssid_le ssid; | ||
340 | __le32 flags; | ||
341 | __le32 infra; | ||
342 | __le32 auth; | ||
343 | __le32 wpa_auth; | ||
344 | __le32 wsec; | ||
345 | }; | ||
346 | |||
347 | /** | ||
348 | * struct brcmf_pno_net_info_le - information per found network. | ||
349 | * | ||
350 | * @bssid: BSS network identifier. | ||
351 | * @channel: channel number only. | ||
352 | * @SSID_len: length of ssid. | ||
353 | * @SSID: ssid characters. | ||
354 | * @RSSI: receive signal strength (in dBm). | ||
355 | * @timestamp: age in seconds. | ||
356 | */ | ||
357 | struct brcmf_pno_net_info_le { | ||
358 | u8 bssid[ETH_ALEN]; | ||
359 | u8 channel; | ||
360 | u8 SSID_len; | ||
361 | u8 SSID[32]; | ||
362 | __le16 RSSI; | ||
363 | __le16 timestamp; | ||
364 | }; | ||
365 | |||
366 | /** | ||
367 | * struct brcmf_pno_scanresults_le - result returned in PNO NET FOUND event. | ||
368 | * | ||
369 | * @version: PNO version identifier. | ||
370 | * @status: indicates completion status of PNO scan. | ||
371 | * @count: amount of brcmf_pno_net_info_le entries appended. | ||
372 | */ | ||
373 | struct brcmf_pno_scanresults_le { | ||
374 | __le32 version; | ||
375 | __le32 status; | ||
376 | __le32 count; | ||
377 | }; | ||
378 | |||
379 | /** | ||
380 | * struct brcmf_cfg80211_priv - dongle private data of cfg80211 interface | ||
381 | * | ||
382 | * @wdev: representing wl cfg80211 device. | ||
383 | * @conf: dongle configuration. | ||
384 | * @scan_request: cfg80211 scan request object. | ||
385 | * @el: main event loop. | ||
386 | * @evt_q_list: used for event queue. | ||
387 | * @evt_q_lock: for event queue synchronization. | ||
388 | * @usr_sync: mainly for dongle up/down synchronization. | ||
389 | * @bss_list: bss_list holding scanned ap information. | ||
390 | * @scan_results: results of the last scan. | ||
391 | * @scan_req_int: internal scan request object. | ||
392 | * @bss_info: bss information for cfg80211 layer. | ||
393 | * @ie: information element object for internal purpose. | ||
394 | * @profile: holding dongle profile. | ||
395 | * @iscan: iscan controller information. | ||
396 | * @conn_info: association info. | ||
397 | * @pmk_list: wpa2 pmk list. | ||
398 | * @event_work: event handler work struct. | ||
399 | * @status: current dongle status. | ||
400 | * @pub: common driver information. | ||
401 | * @channel: current channel. | ||
402 | * @iscan_on: iscan on/off switch. | ||
403 | * @iscan_kickstart: indicate iscan already started. | ||
404 | * @active_scan: current scan mode. | ||
405 | * @sched_escan: e-scan for scheduled scan support running. | ||
406 | * @ibss_starter: indicates this sta is ibss starter. | ||
407 | * @link_up: link/connection up flag. | ||
408 | * @pwr_save: indicate whether dongle to support power save mode. | ||
409 | * @dongle_up: indicate whether dongle up or not. | ||
410 | * @roam_on: on/off switch for dongle self-roaming. | ||
411 | * @scan_tried: indicates if first scan attempted. | ||
412 | * @dcmd_buf: dcmd buffer. | ||
413 | * @extra_buf: mainly to grab assoc information. | ||
414 | * @debugfsdir: debugfs folder for this device. | ||
415 | * @escan_on: escan on/off switch. | ||
416 | * @escan_info: escan information. | ||
417 | * @escan_timeout: Timer for catch scan timeout. | ||
418 | * @escan_timeout_work: scan timeout worker. | ||
419 | * @escan_ioctl_buf: dongle command buffer for escan commands. | ||
420 | * @ci: used to link this structure to netdev private data. | ||
421 | */ | ||
299 | struct brcmf_cfg80211_priv { | 422 | struct brcmf_cfg80211_priv { |
300 | struct wireless_dev *wdev; /* representing wl cfg80211 device */ | 423 | struct wireless_dev *wdev; |
301 | struct brcmf_cfg80211_conf *conf; /* dongle configuration */ | 424 | struct brcmf_cfg80211_conf *conf; |
302 | struct cfg80211_scan_request *scan_request; /* scan request | 425 | struct cfg80211_scan_request *scan_request; |
303 | object */ | 426 | struct brcmf_cfg80211_event_loop el; |
304 | struct brcmf_cfg80211_event_loop el; /* main event loop */ | 427 | struct list_head evt_q_list; |
305 | struct list_head evt_q_list; /* used for event queue */ | 428 | spinlock_t evt_q_lock; |
306 | spinlock_t evt_q_lock; /* for event queue synchronization */ | 429 | struct mutex usr_sync; |
307 | struct mutex usr_sync; /* maily for dongle up/down synchronization */ | 430 | struct brcmf_scan_results *bss_list; |
308 | struct brcmf_scan_results *bss_list; /* bss_list holding scanned | ||
309 | ap information */ | ||
310 | struct brcmf_scan_results *scan_results; | 431 | struct brcmf_scan_results *scan_results; |
311 | struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object | 432 | struct brcmf_cfg80211_scan_req *scan_req_int; |
312 | for internal purpose */ | 433 | struct wl_cfg80211_bss_info *bss_info; |
313 | struct wl_cfg80211_bss_info *bss_info; /* bss information for | 434 | struct brcmf_cfg80211_ie ie; |
314 | cfg80211 layer */ | 435 | struct brcmf_cfg80211_profile *profile; |
315 | struct brcmf_cfg80211_ie ie; /* information element object for | 436 | struct brcmf_cfg80211_iscan_ctrl *iscan; |
316 | internal purpose */ | 437 | struct brcmf_cfg80211_connect_info conn_info; |
317 | struct brcmf_cfg80211_profile *profile; /* holding dongle profile */ | 438 | struct brcmf_cfg80211_pmk_list *pmk_list; |
318 | struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */ | 439 | struct work_struct event_work; |
319 | struct brcmf_cfg80211_connect_info conn_info; /* association info */ | 440 | unsigned long status; |
320 | struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */ | 441 | struct brcmf_pub *pub; |
321 | struct work_struct event_work; /* event handler work struct */ | 442 | u32 channel; |
322 | unsigned long status; /* current dongle status */ | 443 | bool iscan_on; |
323 | void *pub; | 444 | bool iscan_kickstart; |
324 | u32 channel; /* current channel */ | 445 | bool active_scan; |
325 | bool iscan_on; /* iscan on/off switch */ | 446 | bool sched_escan; |
326 | bool iscan_kickstart; /* indicate iscan already started */ | 447 | bool ibss_starter; |
327 | bool active_scan; /* current scan mode */ | 448 | bool link_up; |
328 | bool ibss_starter; /* indicates this sta is ibss starter */ | 449 | bool pwr_save; |
329 | bool link_up; /* link/connection up flag */ | 450 | bool dongle_up; |
330 | bool pwr_save; /* indicate whether dongle to support | 451 | bool roam_on; |
331 | power save mode */ | 452 | bool scan_tried; |
332 | bool dongle_up; /* indicate whether dongle up or not */ | 453 | u8 *dcmd_buf; |
333 | bool roam_on; /* on/off switch for dongle self-roaming */ | 454 | u8 *extra_buf; |
334 | bool scan_tried; /* indicates if first scan attempted */ | ||
335 | u8 *dcmd_buf; /* dcmd buffer */ | ||
336 | u8 *extra_buf; /* maily to grab assoc information */ | ||
337 | struct dentry *debugfsdir; | 455 | struct dentry *debugfsdir; |
338 | bool escan_on; /* escan on/off switch */ | 456 | bool escan_on; |
339 | struct escan_info escan_info; /* escan information */ | 457 | struct escan_info escan_info; |
340 | struct timer_list escan_timeout; /* Timer for catch scan timeout */ | 458 | struct timer_list escan_timeout; |
341 | struct work_struct escan_timeout_work; /* scan timeout worker */ | 459 | struct work_struct escan_timeout_work; |
342 | u8 *escan_ioctl_buf; | 460 | u8 *escan_ioctl_buf; |
343 | u8 ci[0] __aligned(NETDEV_ALIGN); | 461 | u8 ci[0] __aligned(NETDEV_ALIGN); |
344 | }; | 462 | }; |
@@ -379,7 +497,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg) | |||
379 | 497 | ||
380 | extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, | 498 | extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, |
381 | struct device *busdev, | 499 | struct device *busdev, |
382 | void *data); | 500 | struct brcmf_pub *drvr); |
383 | extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); | 501 | extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); |
384 | 502 | ||
385 | /* event handler from dongle */ | 503 | /* event handler from dongle */ |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 718da8d6d658..a744ea5a9559 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -304,7 +304,10 @@ static int brcms_ops_start(struct ieee80211_hw *hw) | |||
304 | wl->mute_tx = true; | 304 | wl->mute_tx = true; |
305 | 305 | ||
306 | if (!wl->pub->up) | 306 | if (!wl->pub->up) |
307 | err = brcms_up(wl); | 307 | if (!blocked) |
308 | err = brcms_up(wl); | ||
309 | else | ||
310 | err = -ERFKILL; | ||
308 | else | 311 | else |
309 | err = -ENODEV; | 312 | err = -ENODEV; |
310 | spin_unlock_bh(&wl->lock); | 313 | spin_unlock_bh(&wl->lock); |
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index 1571505b1a38..54aba4744438 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c | |||
@@ -675,7 +675,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, | |||
675 | } | 675 | } |
676 | done: | 676 | done: |
677 | if (ieee->set_security) | 677 | if (ieee->set_security) |
678 | ieee->set_security(ieee->dev, &sec); | 678 | ieee->set_security(dev, &sec); |
679 | 679 | ||
680 | return ret; | 680 | return ret; |
681 | } | 681 | } |
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index eb9987520d61..318ed3c9fe74 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
@@ -1586,9 +1586,9 @@ il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, | |||
1586 | return 0; | 1586 | return 0; |
1587 | 1587 | ||
1588 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | 1588 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); |
1589 | memcpy(frame->da, il_bcast_addr, ETH_ALEN); | 1589 | eth_broadcast_addr(frame->da); |
1590 | memcpy(frame->sa, ta, ETH_ALEN); | 1590 | memcpy(frame->sa, ta, ETH_ALEN); |
1591 | memcpy(frame->bssid, il_bcast_addr, ETH_ALEN); | 1591 | eth_broadcast_addr(frame->bssid); |
1592 | frame->seq_ctrl = 0; | 1592 | frame->seq_ctrl = 0; |
1593 | 1593 | ||
1594 | len += 24; | 1594 | len += 24; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index e3467fa86899..bb9f6252d28f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c | |||
@@ -612,9 +612,9 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, | |||
612 | return 0; | 612 | return 0; |
613 | 613 | ||
614 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | 614 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); |
615 | memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); | 615 | eth_broadcast_addr(frame->da); |
616 | memcpy(frame->sa, ta, ETH_ALEN); | 616 | memcpy(frame->sa, ta, ETH_ALEN); |
617 | memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); | 617 | eth_broadcast_addr(frame->bssid); |
618 | frame->seq_ctrl = 0; | 618 | frame->seq_ctrl = 0; |
619 | 619 | ||
620 | len += 24; | 620 | len += 24; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index fe36a38f3505..cd9b6de4273e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -128,10 +128,11 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
128 | struct iwl_device_cmd *cmd) | 128 | struct iwl_device_cmd *cmd) |
129 | { | 129 | { |
130 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 130 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
131 | struct iwl_addsta_cmd *addsta = | ||
132 | (struct iwl_addsta_cmd *) cmd->payload; | ||
133 | 131 | ||
134 | return iwl_process_add_sta_resp(priv, addsta, pkt); | 132 | if (!cmd) |
133 | return 0; | ||
134 | |||
135 | return iwl_process_add_sta_resp(priv, (void *)cmd->payload, pkt); | ||
135 | } | 136 | } |
136 | 137 | ||
137 | int iwl_send_add_sta(struct iwl_priv *priv, | 138 | int iwl_send_add_sta(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 6d8d6dd7943f..2cb1efbc5ed1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c | |||
@@ -295,7 +295,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) | |||
295 | static int iwl_verify_sec_sparse(struct iwl_priv *priv, | 295 | static int iwl_verify_sec_sparse(struct iwl_priv *priv, |
296 | const struct fw_desc *fw_desc) | 296 | const struct fw_desc *fw_desc) |
297 | { | 297 | { |
298 | __le32 *image = (__le32 *)fw_desc->v_addr; | 298 | __le32 *image = (__le32 *)fw_desc->data; |
299 | u32 len = fw_desc->len; | 299 | u32 len = fw_desc->len; |
300 | u32 val; | 300 | u32 val; |
301 | u32 i; | 301 | u32 i; |
@@ -319,7 +319,7 @@ static int iwl_verify_sec_sparse(struct iwl_priv *priv, | |||
319 | static void iwl_print_mismatch_sec(struct iwl_priv *priv, | 319 | static void iwl_print_mismatch_sec(struct iwl_priv *priv, |
320 | const struct fw_desc *fw_desc) | 320 | const struct fw_desc *fw_desc) |
321 | { | 321 | { |
322 | __le32 *image = (__le32 *)fw_desc->v_addr; | 322 | __le32 *image = (__le32 *)fw_desc->data; |
323 | u32 len = fw_desc->len; | 323 | u32 len = fw_desc->len; |
324 | u32 val; | 324 | u32 val; |
325 | u32 offs; | 325 | u32 offs; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 48d6d44c16d0..198634b75ed0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/dma-mapping.h> | 64 | #include <linux/dma-mapping.h> |
65 | #include <linux/firmware.h> | 65 | #include <linux/firmware.h> |
66 | #include <linux/module.h> | 66 | #include <linux/module.h> |
67 | #include <linux/vmalloc.h> | ||
67 | 68 | ||
68 | #include "iwl-drv.h" | 69 | #include "iwl-drv.h" |
69 | #include "iwl-debug.h" | 70 | #include "iwl-debug.h" |
@@ -164,10 +165,8 @@ struct fw_sec { | |||
164 | 165 | ||
165 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) | 166 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) |
166 | { | 167 | { |
167 | if (desc->v_addr) | 168 | vfree(desc->data); |
168 | dma_free_coherent(drv->trans->dev, desc->len, | 169 | desc->data = NULL; |
169 | desc->v_addr, desc->p_addr); | ||
170 | desc->v_addr = NULL; | ||
171 | desc->len = 0; | 170 | desc->len = 0; |
172 | } | 171 | } |
173 | 172 | ||
@@ -186,21 +185,24 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) | |||
186 | } | 185 | } |
187 | 186 | ||
188 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, | 187 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, |
189 | struct fw_sec *sec) | 188 | struct fw_sec *sec) |
190 | { | 189 | { |
191 | if (!sec || !sec->size) { | 190 | void *data; |
192 | desc->v_addr = NULL; | 191 | |
192 | desc->data = NULL; | ||
193 | |||
194 | if (!sec || !sec->size) | ||
193 | return -EINVAL; | 195 | return -EINVAL; |
194 | } | ||
195 | 196 | ||
196 | desc->v_addr = dma_alloc_coherent(drv->trans->dev, sec->size, | 197 | data = vmalloc(sec->size); |
197 | &desc->p_addr, GFP_KERNEL); | 198 | if (!data) |
198 | if (!desc->v_addr) | ||
199 | return -ENOMEM; | 199 | return -ENOMEM; |
200 | 200 | ||
201 | desc->len = sec->size; | 201 | desc->len = sec->size; |
202 | desc->offset = sec->offset; | 202 | desc->offset = sec->offset; |
203 | memcpy(desc->v_addr, sec->data, sec->size); | 203 | memcpy(data, sec->data, desc->len); |
204 | desc->data = data; | ||
205 | |||
204 | return 0; | 206 | return 0; |
205 | } | 207 | } |
206 | 208 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 2153e4cc5572..d1a86b66bc51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -124,8 +124,7 @@ struct iwl_ucode_capabilities { | |||
124 | 124 | ||
125 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ | 125 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ |
126 | struct fw_desc { | 126 | struct fw_desc { |
127 | dma_addr_t p_addr; /* hardware address */ | 127 | const void *data; /* vmalloc'ed data */ |
128 | void *v_addr; /* software address */ | ||
129 | u32 len; /* size in bytes */ | 128 | u32 len; /* size in bytes */ |
130 | u32 offset; /* offset in the device */ | 129 | u32 offset; /* offset in the device */ |
131 | }; | 130 | }; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 89bfb43f4946..2a4675396707 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -263,8 +263,6 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); | |||
263 | /* PCI registers */ | 263 | /* PCI registers */ |
264 | #define PCI_CFG_RETRY_TIMEOUT 0x041 | 264 | #define PCI_CFG_RETRY_TIMEOUT 0x041 |
265 | 265 | ||
266 | #ifndef CONFIG_IWLWIFI_IDI | ||
267 | |||
268 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 266 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
269 | { | 267 | { |
270 | const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | 268 | const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); |
@@ -307,8 +305,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
307 | pci_set_drvdata(pdev, NULL); | 305 | pci_set_drvdata(pdev, NULL); |
308 | } | 306 | } |
309 | 307 | ||
310 | #endif /* CONFIG_IWLWIFI_IDI */ | ||
311 | |||
312 | #ifdef CONFIG_PM_SLEEP | 308 | #ifdef CONFIG_PM_SLEEP |
313 | 309 | ||
314 | static int iwl_pci_suspend(struct device *device) | 310 | static int iwl_pci_suspend(struct device *device) |
@@ -353,15 +349,6 @@ static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); | |||
353 | 349 | ||
354 | #endif | 350 | #endif |
355 | 351 | ||
356 | #ifdef CONFIG_IWLWIFI_IDI | ||
357 | /* | ||
358 | * Defined externally in iwl-idi.c | ||
359 | */ | ||
360 | int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | ||
361 | void __devexit iwl_pci_remove(struct pci_dev *pdev); | ||
362 | |||
363 | #endif /* CONFIG_IWLWIFI_IDI */ | ||
364 | |||
365 | static struct pci_driver iwl_pci_driver = { | 352 | static struct pci_driver iwl_pci_driver = { |
366 | .name = DRV_NAME, | 353 | .name = DRV_NAME, |
367 | .id_table = iwl_hw_card_ids, | 354 | .id_table = iwl_hw_card_ids, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 71c79943e633..401178f44a3b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -311,7 +311,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); | |||
311 | ******************************************************/ | 311 | ******************************************************/ |
312 | void iwl_bg_rx_replenish(struct work_struct *data); | 312 | void iwl_bg_rx_replenish(struct work_struct *data); |
313 | void iwl_irq_tasklet(struct iwl_trans *trans); | 313 | void iwl_irq_tasklet(struct iwl_trans *trans); |
314 | void iwlagn_rx_replenish(struct iwl_trans *trans); | 314 | void iwl_rx_replenish(struct iwl_trans *trans); |
315 | void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, | 315 | void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, |
316 | struct iwl_rx_queue *q); | 316 | struct iwl_rx_queue *q); |
317 | 317 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 498372008810..17c8e5d82681 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -35,10 +35,6 @@ | |||
35 | #include "internal.h" | 35 | #include "internal.h" |
36 | #include "iwl-op-mode.h" | 36 | #include "iwl-op-mode.h" |
37 | 37 | ||
38 | #ifdef CONFIG_IWLWIFI_IDI | ||
39 | #include "iwl-amfh.h" | ||
40 | #endif | ||
41 | |||
42 | /****************************************************************************** | 38 | /****************************************************************************** |
43 | * | 39 | * |
44 | * RX path functions | 40 | * RX path functions |
@@ -181,15 +177,15 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, | |||
181 | } | 177 | } |
182 | 178 | ||
183 | /** | 179 | /** |
184 | * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr | 180 | * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr |
185 | */ | 181 | */ |
186 | static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) | 182 | static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr) |
187 | { | 183 | { |
188 | return cpu_to_le32((u32)(dma_addr >> 8)); | 184 | return cpu_to_le32((u32)(dma_addr >> 8)); |
189 | } | 185 | } |
190 | 186 | ||
191 | /** | 187 | /** |
192 | * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool | 188 | * iwl_rx_queue_restock - refill RX queue from pre-allocated pool |
193 | * | 189 | * |
194 | * If there are slots in the RX queue that need to be restocked, | 190 | * If there are slots in the RX queue that need to be restocked, |
195 | * and we have free pre-allocated buffers, fill the ranks as much | 191 | * and we have free pre-allocated buffers, fill the ranks as much |
@@ -199,7 +195,7 @@ static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) | |||
199 | * also updates the memory address in the firmware to reference the new | 195 | * also updates the memory address in the firmware to reference the new |
200 | * target buffer. | 196 | * target buffer. |
201 | */ | 197 | */ |
202 | static void iwlagn_rx_queue_restock(struct iwl_trans *trans) | 198 | static void iwl_rx_queue_restock(struct iwl_trans *trans) |
203 | { | 199 | { |
204 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 200 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
205 | struct iwl_rx_queue *rxq = &trans_pcie->rxq; | 201 | struct iwl_rx_queue *rxq = &trans_pcie->rxq; |
@@ -207,6 +203,17 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) | |||
207 | struct iwl_rx_mem_buffer *rxb; | 203 | struct iwl_rx_mem_buffer *rxb; |
208 | unsigned long flags; | 204 | unsigned long flags; |
209 | 205 | ||
206 | /* | ||
207 | * If the device isn't enabled - not need to try to add buffers... | ||
208 | * This can happen when we stop the device and still have an interrupt | ||
209 | * pending. We stop the APM before we sync the interrupts / tasklets | ||
210 | * because we have to (see comment there). On the other hand, since | ||
211 | * the APM is stopped, we cannot access the HW (in particular not prph). | ||
212 | * So don't try to restock if the APM has been already stopped. | ||
213 | */ | ||
214 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) | ||
215 | return; | ||
216 | |||
210 | spin_lock_irqsave(&rxq->lock, flags); | 217 | spin_lock_irqsave(&rxq->lock, flags); |
211 | while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { | 218 | while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { |
212 | /* The overwritten rxb must be a used one */ | 219 | /* The overwritten rxb must be a used one */ |
@@ -219,7 +226,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) | |||
219 | list_del(element); | 226 | list_del(element); |
220 | 227 | ||
221 | /* Point to Rx buffer via next RBD in circular buffer */ | 228 | /* Point to Rx buffer via next RBD in circular buffer */ |
222 | rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma); | 229 | rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma); |
223 | rxq->queue[rxq->write] = rxb; | 230 | rxq->queue[rxq->write] = rxb; |
224 | rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; | 231 | rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; |
225 | rxq->free_count--; | 232 | rxq->free_count--; |
@@ -230,7 +237,6 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) | |||
230 | if (rxq->free_count <= RX_LOW_WATERMARK) | 237 | if (rxq->free_count <= RX_LOW_WATERMARK) |
231 | schedule_work(&trans_pcie->rx_replenish); | 238 | schedule_work(&trans_pcie->rx_replenish); |
232 | 239 | ||
233 | |||
234 | /* If we've added more space for the firmware to place data, tell it. | 240 | /* If we've added more space for the firmware to place data, tell it. |
235 | * Increment device's write pointer in multiples of 8. */ | 241 | * Increment device's write pointer in multiples of 8. */ |
236 | if (rxq->write_actual != (rxq->write & ~0x7)) { | 242 | if (rxq->write_actual != (rxq->write & ~0x7)) { |
@@ -241,15 +247,16 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans) | |||
241 | } | 247 | } |
242 | } | 248 | } |
243 | 249 | ||
244 | /** | 250 | /* |
245 | * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free | 251 | * iwl_rx_allocate - allocate a page for each used RBD |
246 | * | ||
247 | * When moving to rx_free an SKB is allocated for the slot. | ||
248 | * | 252 | * |
249 | * Also restock the Rx queue via iwl_rx_queue_restock. | 253 | * A used RBD is an Rx buffer that has been given to the stack. To use it again |
250 | * This is called as a scheduled work item (except for during initialization) | 254 | * a page must be allocated and the RBD must point to the page. This function |
255 | * doesn't change the HW pointer but handles the list of pages that is used by | ||
256 | * iwl_rx_queue_restock. The latter function will update the HW to use the newly | ||
257 | * allocated buffers. | ||
251 | */ | 258 | */ |
252 | static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) | 259 | static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority) |
253 | { | 260 | { |
254 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 261 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
255 | struct iwl_rx_queue *rxq = &trans_pcie->rxq; | 262 | struct iwl_rx_queue *rxq = &trans_pcie->rxq; |
@@ -328,23 +335,31 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) | |||
328 | } | 335 | } |
329 | } | 336 | } |
330 | 337 | ||
331 | void iwlagn_rx_replenish(struct iwl_trans *trans) | 338 | /* |
339 | * iwl_rx_replenish - Move all used buffers from rx_used to rx_free | ||
340 | * | ||
341 | * When moving to rx_free an page is allocated for the slot. | ||
342 | * | ||
343 | * Also restock the Rx queue via iwl_rx_queue_restock. | ||
344 | * This is called as a scheduled work item (except for during initialization) | ||
345 | */ | ||
346 | void iwl_rx_replenish(struct iwl_trans *trans) | ||
332 | { | 347 | { |
333 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 348 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
334 | unsigned long flags; | 349 | unsigned long flags; |
335 | 350 | ||
336 | iwlagn_rx_allocate(trans, GFP_KERNEL); | 351 | iwl_rx_allocate(trans, GFP_KERNEL); |
337 | 352 | ||
338 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); | 353 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); |
339 | iwlagn_rx_queue_restock(trans); | 354 | iwl_rx_queue_restock(trans); |
340 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | 355 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
341 | } | 356 | } |
342 | 357 | ||
343 | static void iwlagn_rx_replenish_now(struct iwl_trans *trans) | 358 | static void iwl_rx_replenish_now(struct iwl_trans *trans) |
344 | { | 359 | { |
345 | iwlagn_rx_allocate(trans, GFP_ATOMIC); | 360 | iwl_rx_allocate(trans, GFP_ATOMIC); |
346 | 361 | ||
347 | iwlagn_rx_queue_restock(trans); | 362 | iwl_rx_queue_restock(trans); |
348 | } | 363 | } |
349 | 364 | ||
350 | void iwl_bg_rx_replenish(struct work_struct *data) | 365 | void iwl_bg_rx_replenish(struct work_struct *data) |
@@ -352,7 +367,7 @@ void iwl_bg_rx_replenish(struct work_struct *data) | |||
352 | struct iwl_trans_pcie *trans_pcie = | 367 | struct iwl_trans_pcie *trans_pcie = |
353 | container_of(data, struct iwl_trans_pcie, rx_replenish); | 368 | container_of(data, struct iwl_trans_pcie, rx_replenish); |
354 | 369 | ||
355 | iwlagn_rx_replenish(trans_pcie->trans); | 370 | iwl_rx_replenish(trans_pcie->trans); |
356 | } | 371 | } |
357 | 372 | ||
358 | static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, | 373 | static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, |
@@ -530,7 +545,7 @@ static void iwl_rx_handle(struct iwl_trans *trans) | |||
530 | count++; | 545 | count++; |
531 | if (count >= 8) { | 546 | if (count >= 8) { |
532 | rxq->read = i; | 547 | rxq->read = i; |
533 | iwlagn_rx_replenish_now(trans); | 548 | iwl_rx_replenish_now(trans); |
534 | count = 0; | 549 | count = 0; |
535 | } | 550 | } |
536 | } | 551 | } |
@@ -539,9 +554,9 @@ static void iwl_rx_handle(struct iwl_trans *trans) | |||
539 | /* Backtrack one entry */ | 554 | /* Backtrack one entry */ |
540 | rxq->read = i; | 555 | rxq->read = i; |
541 | if (fill_rx) | 556 | if (fill_rx) |
542 | iwlagn_rx_replenish_now(trans); | 557 | iwl_rx_replenish_now(trans); |
543 | else | 558 | else |
544 | iwlagn_rx_queue_restock(trans); | 559 | iwl_rx_queue_restock(trans); |
545 | } | 560 | } |
546 | 561 | ||
547 | /** | 562 | /** |
@@ -723,11 +738,9 @@ void iwl_irq_tasklet(struct iwl_trans *trans) | |||
723 | /* Disable periodic interrupt; we use it as just a one-shot. */ | 738 | /* Disable periodic interrupt; we use it as just a one-shot. */ |
724 | iwl_write8(trans, CSR_INT_PERIODIC_REG, | 739 | iwl_write8(trans, CSR_INT_PERIODIC_REG, |
725 | CSR_INT_PERIODIC_DIS); | 740 | CSR_INT_PERIODIC_DIS); |
726 | #ifdef CONFIG_IWLWIFI_IDI | 741 | |
727 | iwl_amfh_rx_handler(); | ||
728 | #else | ||
729 | iwl_rx_handle(trans); | 742 | iwl_rx_handle(trans); |
730 | #endif | 743 | |
731 | /* | 744 | /* |
732 | * Enable periodic interrupt in 8 msec only if we received | 745 | * Enable periodic interrupt in 8 msec only if we received |
733 | * real RX interrupt (instead of just periodic int), to catch | 746 | * real RX interrupt (instead of just periodic int), to catch |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 76aa5031f7ba..34aee0688e0d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -216,7 +216,7 @@ static int iwl_rx_init(struct iwl_trans *trans) | |||
216 | rxq->free_count = 0; | 216 | rxq->free_count = 0; |
217 | spin_unlock_irqrestore(&rxq->lock, flags); | 217 | spin_unlock_irqrestore(&rxq->lock, flags); |
218 | 218 | ||
219 | iwlagn_rx_replenish(trans); | 219 | iwl_rx_replenish(trans); |
220 | 220 | ||
221 | iwl_trans_rx_hw_init(trans, rxq); | 221 | iwl_trans_rx_hw_init(trans, rxq); |
222 | 222 | ||
@@ -855,10 +855,8 @@ static int iwl_nic_init(struct iwl_trans *trans) | |||
855 | 855 | ||
856 | iwl_op_mode_nic_config(trans->op_mode); | 856 | iwl_op_mode_nic_config(trans->op_mode); |
857 | 857 | ||
858 | #ifndef CONFIG_IWLWIFI_IDI | ||
859 | /* Allocate the RX queue, or reset if it is already allocated */ | 858 | /* Allocate the RX queue, or reset if it is already allocated */ |
860 | iwl_rx_init(trans); | 859 | iwl_rx_init(trans); |
861 | #endif | ||
862 | 860 | ||
863 | /* Allocate or reset and init all Tx and Command queues */ | 861 | /* Allocate or reset and init all Tx and Command queues */ |
864 | if (iwl_tx_init(trans)) | 862 | if (iwl_tx_init(trans)) |
@@ -925,13 +923,10 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) | |||
925 | /* | 923 | /* |
926 | * ucode | 924 | * ucode |
927 | */ | 925 | */ |
928 | static int iwl_load_section(struct iwl_trans *trans, u8 section_num, | 926 | static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, |
929 | const struct fw_desc *section) | 927 | dma_addr_t phy_addr, u32 byte_cnt) |
930 | { | 928 | { |
931 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 929 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
932 | dma_addr_t phy_addr = section->p_addr; | ||
933 | u32 byte_cnt = section->len; | ||
934 | u32 dst_addr = section->offset; | ||
935 | int ret; | 930 | int ret; |
936 | 931 | ||
937 | trans_pcie->ucode_write_complete = false; | 932 | trans_pcie->ucode_write_complete = false; |
@@ -945,8 +940,8 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, | |||
945 | dst_addr); | 940 | dst_addr); |
946 | 941 | ||
947 | iwl_write_direct32(trans, | 942 | iwl_write_direct32(trans, |
948 | FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), | 943 | FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), |
949 | phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); | 944 | phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); |
950 | 945 | ||
951 | iwl_write_direct32(trans, | 946 | iwl_write_direct32(trans, |
952 | FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), | 947 | FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), |
@@ -965,33 +960,64 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num, | |||
965 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | | 960 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | |
966 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); | 961 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); |
967 | 962 | ||
968 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", | ||
969 | section_num); | ||
970 | ret = wait_event_timeout(trans_pcie->ucode_write_waitq, | 963 | ret = wait_event_timeout(trans_pcie->ucode_write_waitq, |
971 | trans_pcie->ucode_write_complete, 5 * HZ); | 964 | trans_pcie->ucode_write_complete, 5 * HZ); |
972 | if (!ret) { | 965 | if (!ret) { |
973 | IWL_ERR(trans, "Could not load the [%d] uCode section\n", | 966 | IWL_ERR(trans, "Failed to load firmware chunk!\n"); |
974 | section_num); | ||
975 | return -ETIMEDOUT; | 967 | return -ETIMEDOUT; |
976 | } | 968 | } |
977 | 969 | ||
978 | return 0; | 970 | return 0; |
979 | } | 971 | } |
980 | 972 | ||
981 | static int iwl_load_given_ucode(struct iwl_trans *trans, | 973 | static int iwl_load_section(struct iwl_trans *trans, u8 section_num, |
982 | const struct fw_img *image) | 974 | const struct fw_desc *section) |
983 | { | 975 | { |
976 | u8 *v_addr; | ||
977 | dma_addr_t p_addr; | ||
978 | u32 offset; | ||
984 | int ret = 0; | 979 | int ret = 0; |
985 | int i; | ||
986 | 980 | ||
987 | for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { | 981 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", |
988 | if (!image->sec[i].p_addr) | 982 | section_num); |
989 | break; | ||
990 | 983 | ||
991 | ret = iwl_load_section(trans, i, &image->sec[i]); | 984 | v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL); |
992 | if (ret) | 985 | if (!v_addr) |
993 | return ret; | 986 | return -ENOMEM; |
987 | |||
988 | for (offset = 0; offset < section->len; offset += PAGE_SIZE) { | ||
989 | u32 copy_size; | ||
990 | |||
991 | copy_size = min_t(u32, PAGE_SIZE, section->len - offset); | ||
992 | |||
993 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); | ||
994 | ret = iwl_load_firmware_chunk(trans, section->offset + offset, | ||
995 | p_addr, copy_size); | ||
996 | if (ret) { | ||
997 | IWL_ERR(trans, | ||
998 | "Could not load the [%d] uCode section\n", | ||
999 | section_num); | ||
1000 | break; | ||
994 | } | 1001 | } |
1002 | } | ||
1003 | |||
1004 | dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr); | ||
1005 | return ret; | ||
1006 | } | ||
1007 | |||
1008 | static int iwl_load_given_ucode(struct iwl_trans *trans, | ||
1009 | const struct fw_img *image) | ||
1010 | { | ||
1011 | int i, ret = 0; | ||
1012 | |||
1013 | for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { | ||
1014 | if (!image->sec[i].data) | ||
1015 | break; | ||
1016 | |||
1017 | ret = iwl_load_section(trans, i, &image->sec[i]); | ||
1018 | if (ret) | ||
1019 | return ret; | ||
1020 | } | ||
995 | 1021 | ||
996 | /* Remove all resets to allow NIC to operate */ | 1022 | /* Remove all resets to allow NIC to operate */ |
997 | iwl_write32(trans, CSR_RESET, 0); | 1023 | iwl_write32(trans, CSR_RESET, 0); |
@@ -1184,9 +1210,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
1184 | */ | 1210 | */ |
1185 | if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) { | 1211 | if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) { |
1186 | iwl_trans_tx_stop(trans); | 1212 | iwl_trans_tx_stop(trans); |
1187 | #ifndef CONFIG_IWLWIFI_IDI | ||
1188 | iwl_trans_rx_stop(trans); | 1213 | iwl_trans_rx_stop(trans); |
1189 | #endif | 1214 | |
1190 | /* Power-down device's busmaster DMA clocks */ | 1215 | /* Power-down device's busmaster DMA clocks */ |
1191 | iwl_write_prph(trans, APMG_CLK_DIS_REG, | 1216 | iwl_write_prph(trans, APMG_CLK_DIS_REG, |
1192 | APMG_CLK_VAL_DMA_CLK_RQT); | 1217 | APMG_CLK_VAL_DMA_CLK_RQT); |
@@ -1457,14 +1482,16 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, | |||
1457 | bool hw_rfkill; | 1482 | bool hw_rfkill; |
1458 | unsigned long flags; | 1483 | unsigned long flags; |
1459 | 1484 | ||
1485 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); | ||
1486 | iwl_disable_interrupts(trans); | ||
1487 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | ||
1488 | |||
1460 | iwl_apm_stop(trans); | 1489 | iwl_apm_stop(trans); |
1461 | 1490 | ||
1462 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); | 1491 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); |
1463 | iwl_disable_interrupts(trans); | 1492 | iwl_disable_interrupts(trans); |
1464 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | 1493 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
1465 | 1494 | ||
1466 | iwl_write32(trans, CSR_INT, 0xFFFFFFFF); | ||
1467 | |||
1468 | if (!op_mode_leaving) { | 1495 | if (!op_mode_leaving) { |
1469 | /* | 1496 | /* |
1470 | * Even if we stop the HW, we still want the RF kill | 1497 | * Even if we stop the HW, we still want the RF kill |
@@ -1552,9 +1579,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) | |||
1552 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1579 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1553 | 1580 | ||
1554 | iwl_trans_pcie_tx_free(trans); | 1581 | iwl_trans_pcie_tx_free(trans); |
1555 | #ifndef CONFIG_IWLWIFI_IDI | ||
1556 | iwl_trans_pcie_rx_free(trans); | 1582 | iwl_trans_pcie_rx_free(trans); |
1557 | #endif | 1583 | |
1558 | if (trans_pcie->irq_requested == true) { | 1584 | if (trans_pcie->irq_requested == true) { |
1559 | free_irq(trans_pcie->irq, trans); | 1585 | free_irq(trans_pcie->irq, trans); |
1560 | iwl_free_isr_ict(trans); | 1586 | iwl_free_isr_ict(trans); |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9d45b3bb974c..429ca3215fdb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -2056,7 +2056,7 @@ failed: | |||
2056 | mac80211_hwsim_free(); | 2056 | mac80211_hwsim_free(); |
2057 | return err; | 2057 | return err; |
2058 | } | 2058 | } |
2059 | 2059 | module_init(init_mac80211_hwsim); | |
2060 | 2060 | ||
2061 | static void __exit exit_mac80211_hwsim(void) | 2061 | static void __exit exit_mac80211_hwsim(void) |
2062 | { | 2062 | { |
@@ -2067,7 +2067,4 @@ static void __exit exit_mac80211_hwsim(void) | |||
2067 | mac80211_hwsim_free(); | 2067 | mac80211_hwsim_free(); |
2068 | unregister_netdev(hwsim_mon); | 2068 | unregister_netdev(hwsim_mon); |
2069 | } | 2069 | } |
2070 | |||
2071 | |||
2072 | module_init(init_mac80211_hwsim); | ||
2073 | module_exit(exit_mac80211_hwsim); | 2070 | module_exit(exit_mac80211_hwsim); |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b9f7b3e6912d..c24824f8c8a1 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -1502,6 +1502,12 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, | |||
1502 | 1502 | ||
1503 | wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); | 1503 | wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); |
1504 | 1504 | ||
1505 | if (atomic_read(&priv->wmm.tx_pkts_queued) >= | ||
1506 | MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) { | ||
1507 | dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n"); | ||
1508 | return -EBUSY; | ||
1509 | } | ||
1510 | |||
1505 | priv->scan_request = request; | 1511 | priv->scan_request = request; |
1506 | 1512 | ||
1507 | priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), | 1513 | priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), |
@@ -1630,7 +1636,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, | |||
1630 | * create a new virtual interface with the given name | 1636 | * create a new virtual interface with the given name |
1631 | */ | 1637 | */ |
1632 | struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | 1638 | struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, |
1633 | char *name, | 1639 | const char *name, |
1634 | enum nl80211_iftype type, | 1640 | enum nl80211_iftype type, |
1635 | u32 *flags, | 1641 | u32 *flags, |
1636 | struct vif_params *params) | 1642 | struct vif_params *params) |
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 1d8dd003e396..fa3a80fb8c01 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c | |||
@@ -160,7 +160,7 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, | |||
160 | u16 len; | 160 | u16 len; |
161 | int ret; | 161 | int ret; |
162 | 162 | ||
163 | ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); | 163 | ap_custom_ie = kzalloc(sizeof(*ap_custom_ie), GFP_KERNEL); |
164 | if (!ap_custom_ie) | 164 | if (!ap_custom_ie) |
165 | return -ENOMEM; | 165 | return -ENOMEM; |
166 | 166 | ||
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 9c1549ee4c09..b2ba262f8a13 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -118,6 +118,7 @@ static void scan_delay_timer_fn(unsigned long data) | |||
118 | 118 | ||
119 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, | 119 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, |
120 | true); | 120 | true); |
121 | queue_work(adapter->workqueue, &adapter->main_work); | ||
121 | goto done; | 122 | goto done; |
122 | } | 123 | } |
123 | } else { | 124 | } else { |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 12ceea47b4b4..90b64b015447 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -91,6 +91,8 @@ enum { | |||
91 | #define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10 | 91 | #define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10 |
92 | #define MWIFIEX_SCAN_DELAY_MSEC 20 | 92 | #define MWIFIEX_SCAN_DELAY_MSEC 20 |
93 | 93 | ||
94 | #define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN 2 | ||
95 | |||
94 | #define RSN_GTK_OUI_OFFSET 2 | 96 | #define RSN_GTK_OUI_OFFSET 2 |
95 | 97 | ||
96 | #define MWIFIEX_OUI_NOT_PRESENT 0 | 98 | #define MWIFIEX_OUI_NOT_PRESENT 0 |
@@ -1031,7 +1033,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, | |||
1031 | struct mwifiex_bssdescriptor *bss_desc); | 1033 | struct mwifiex_bssdescriptor *bss_desc); |
1032 | 1034 | ||
1033 | struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, | 1035 | struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, |
1034 | char *name, | 1036 | const char *name, |
1035 | enum nl80211_iftype type, | 1037 | enum nl80211_iftype type, |
1036 | u32 *flags, | 1038 | u32 *flags, |
1037 | struct vif_params *params); | 1039 | struct vif_params *params); |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d7ad2d4a069f..731562f026f5 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -26,6 +26,9 @@ | |||
26 | #include "11n.h" | 26 | #include "11n.h" |
27 | #include "cfg80211.h" | 27 | #include "cfg80211.h" |
28 | 28 | ||
29 | static int disconnect_on_suspend = 1; | ||
30 | module_param(disconnect_on_suspend, int, 0644); | ||
31 | |||
29 | /* | 32 | /* |
30 | * Copies the multicast address list from device to driver. | 33 | * Copies the multicast address list from device to driver. |
31 | * | 34 | * |
@@ -448,6 +451,16 @@ EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); | |||
448 | int mwifiex_enable_hs(struct mwifiex_adapter *adapter) | 451 | int mwifiex_enable_hs(struct mwifiex_adapter *adapter) |
449 | { | 452 | { |
450 | struct mwifiex_ds_hs_cfg hscfg; | 453 | struct mwifiex_ds_hs_cfg hscfg; |
454 | struct mwifiex_private *priv; | ||
455 | int i; | ||
456 | |||
457 | if (disconnect_on_suspend) { | ||
458 | for (i = 0; i < adapter->priv_num; i++) { | ||
459 | priv = adapter->priv[i]; | ||
460 | if (priv) | ||
461 | mwifiex_deauthenticate(priv, NULL); | ||
462 | } | ||
463 | } | ||
451 | 464 | ||
452 | if (adapter->hs_activated) { | 465 | if (adapter->hs_activated) { |
453 | dev_dbg(adapter->dev, "cmd: HS Already actived\n"); | 466 | dev_dbg(adapter->dev, "cmd: HS Already actived\n"); |
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 2969d5321ca6..aadda99989c0 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c | |||
@@ -515,6 +515,17 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | |||
515 | if (modparam_nohwcrypt) | 515 | if (modparam_nohwcrypt) |
516 | return -EOPNOTSUPP; | 516 | return -EOPNOTSUPP; |
517 | 517 | ||
518 | if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { | ||
519 | /* | ||
520 | * Unfortunately most/all firmwares are trying to decrypt | ||
521 | * incoming management frames if a suitable key can be found. | ||
522 | * However, in doing so the data in these frames gets | ||
523 | * corrupted. So, we can't have firmware supported crypto | ||
524 | * offload in this case. | ||
525 | */ | ||
526 | return -EOPNOTSUPP; | ||
527 | } | ||
528 | |||
518 | mutex_lock(&priv->conf_mutex); | 529 | mutex_lock(&priv->conf_mutex); |
519 | if (cmd == SET_KEY) { | 530 | if (cmd == SET_KEY) { |
520 | switch (key->cipher) { | 531 | switch (key->cipher) { |
@@ -738,6 +749,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) | |||
738 | IEEE80211_HW_SIGNAL_DBM | | 749 | IEEE80211_HW_SIGNAL_DBM | |
739 | IEEE80211_HW_SUPPORTS_PS | | 750 | IEEE80211_HW_SUPPORTS_PS | |
740 | IEEE80211_HW_PS_NULLFUNC_STACK | | 751 | IEEE80211_HW_PS_NULLFUNC_STACK | |
752 | IEEE80211_HW_MFP_CAPABLE | | ||
741 | IEEE80211_HW_REPORTS_TX_ACK_STATUS; | 753 | IEEE80211_HW_REPORTS_TX_ACK_STATUS; |
742 | 754 | ||
743 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 755 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 6458ab87717b..e3a2d9070cf6 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1789,7 +1789,6 @@ static const struct data_queue_desc rt2400pci_queue_atim = { | |||
1789 | 1789 | ||
1790 | static const struct rt2x00_ops rt2400pci_ops = { | 1790 | static const struct rt2x00_ops rt2400pci_ops = { |
1791 | .name = KBUILD_MODNAME, | 1791 | .name = KBUILD_MODNAME, |
1792 | .max_sta_intf = 1, | ||
1793 | .max_ap_intf = 1, | 1792 | .max_ap_intf = 1, |
1794 | .eeprom_size = EEPROM_SIZE, | 1793 | .eeprom_size = EEPROM_SIZE, |
1795 | .rf_size = RF_SIZE, | 1794 | .rf_size = RF_SIZE, |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 68bca1456cda..479d756e275b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -2081,7 +2081,6 @@ static const struct data_queue_desc rt2500pci_queue_atim = { | |||
2081 | 2081 | ||
2082 | static const struct rt2x00_ops rt2500pci_ops = { | 2082 | static const struct rt2x00_ops rt2500pci_ops = { |
2083 | .name = KBUILD_MODNAME, | 2083 | .name = KBUILD_MODNAME, |
2084 | .max_sta_intf = 1, | ||
2085 | .max_ap_intf = 1, | 2084 | .max_ap_intf = 1, |
2086 | .eeprom_size = EEPROM_SIZE, | 2085 | .eeprom_size = EEPROM_SIZE, |
2087 | .rf_size = RF_SIZE, | 2086 | .rf_size = RF_SIZE, |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f95b5516c50a..a12e84f892be 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1896,7 +1896,6 @@ static const struct data_queue_desc rt2500usb_queue_atim = { | |||
1896 | 1896 | ||
1897 | static const struct rt2x00_ops rt2500usb_ops = { | 1897 | static const struct rt2x00_ops rt2500usb_ops = { |
1898 | .name = KBUILD_MODNAME, | 1898 | .name = KBUILD_MODNAME, |
1899 | .max_sta_intf = 1, | ||
1900 | .max_ap_intf = 1, | 1899 | .max_ap_intf = 1, |
1901 | .eeprom_size = EEPROM_SIZE, | 1900 | .eeprom_size = EEPROM_SIZE, |
1902 | .rf_size = RF_SIZE, | 1901 | .rf_size = RF_SIZE, |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9e09367c9739..540c94f8505a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -1763,36 +1763,15 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, | |||
1763 | 1763 | ||
1764 | rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); | 1764 | rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); |
1765 | rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); | 1765 | rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); |
1766 | rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, | ||
1767 | rt2x00dev->default_ant.rx_chain_num <= 1); | ||
1768 | rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, | ||
1769 | rt2x00dev->default_ant.rx_chain_num <= 2); | ||
1766 | rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); | 1770 | rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); |
1767 | if (rt2x00_rt(rt2x00dev, RT3390)) { | 1771 | rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, |
1768 | rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, | 1772 | rt2x00dev->default_ant.tx_chain_num <= 1); |
1769 | rt2x00dev->default_ant.rx_chain_num == 1); | 1773 | rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, |
1770 | rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, | 1774 | rt2x00dev->default_ant.tx_chain_num <= 2); |
1771 | rt2x00dev->default_ant.tx_chain_num == 1); | ||
1772 | } else { | ||
1773 | rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); | ||
1774 | rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0); | ||
1775 | rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); | ||
1776 | rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0); | ||
1777 | |||
1778 | switch (rt2x00dev->default_ant.tx_chain_num) { | ||
1779 | case 1: | ||
1780 | rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); | ||
1781 | /* fall through */ | ||
1782 | case 2: | ||
1783 | rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1); | ||
1784 | break; | ||
1785 | } | ||
1786 | |||
1787 | switch (rt2x00dev->default_ant.rx_chain_num) { | ||
1788 | case 1: | ||
1789 | rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); | ||
1790 | /* fall through */ | ||
1791 | case 2: | ||
1792 | rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1); | ||
1793 | break; | ||
1794 | } | ||
1795 | } | ||
1796 | rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); | 1775 | rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
1797 | 1776 | ||
1798 | rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); | 1777 | rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); |
@@ -2896,23 +2875,32 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats); | |||
2896 | 2875 | ||
2897 | static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) | 2876 | static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) |
2898 | { | 2877 | { |
2878 | u8 vgc; | ||
2879 | |||
2899 | if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { | 2880 | if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { |
2900 | if (rt2x00_rt(rt2x00dev, RT3070) || | 2881 | if (rt2x00_rt(rt2x00dev, RT3070) || |
2901 | rt2x00_rt(rt2x00dev, RT3071) || | 2882 | rt2x00_rt(rt2x00dev, RT3071) || |
2902 | rt2x00_rt(rt2x00dev, RT3090) || | 2883 | rt2x00_rt(rt2x00dev, RT3090) || |
2903 | rt2x00_rt(rt2x00dev, RT3290) || | 2884 | rt2x00_rt(rt2x00dev, RT3290) || |
2904 | rt2x00_rt(rt2x00dev, RT3390) || | 2885 | rt2x00_rt(rt2x00dev, RT3390) || |
2886 | rt2x00_rt(rt2x00dev, RT3572) || | ||
2905 | rt2x00_rt(rt2x00dev, RT5390) || | 2887 | rt2x00_rt(rt2x00dev, RT5390) || |
2906 | rt2x00_rt(rt2x00dev, RT5392)) | 2888 | rt2x00_rt(rt2x00dev, RT5392)) |
2907 | return 0x1c + (2 * rt2x00dev->lna_gain); | 2889 | vgc = 0x1c + (2 * rt2x00dev->lna_gain); |
2908 | else | 2890 | else |
2909 | return 0x2e + rt2x00dev->lna_gain; | 2891 | vgc = 0x2e + rt2x00dev->lna_gain; |
2892 | } else { /* 5GHZ band */ | ||
2893 | if (rt2x00_rt(rt2x00dev, RT3572)) | ||
2894 | vgc = 0x22 + (rt2x00dev->lna_gain * 5) / 3; | ||
2895 | else { | ||
2896 | if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) | ||
2897 | vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3; | ||
2898 | else | ||
2899 | vgc = 0x3a + (rt2x00dev->lna_gain * 5) / 3; | ||
2900 | } | ||
2910 | } | 2901 | } |
2911 | 2902 | ||
2912 | if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) | 2903 | return vgc; |
2913 | return 0x32 + (rt2x00dev->lna_gain * 5) / 3; | ||
2914 | else | ||
2915 | return 0x3a + (rt2x00dev->lna_gain * 5) / 3; | ||
2916 | } | 2904 | } |
2917 | 2905 | ||
2918 | static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev, | 2906 | static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev, |
@@ -3081,7 +3069,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | |||
3081 | rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); | 3069 | rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); |
3082 | rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); | 3070 | rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); |
3083 | } else if (rt2x00_rt(rt2x00dev, RT5390) || | 3071 | } else if (rt2x00_rt(rt2x00dev, RT5390) || |
3084 | rt2x00_rt(rt2x00dev, RT5392)) { | 3072 | rt2x00_rt(rt2x00dev, RT5392)) { |
3085 | rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); | 3073 | rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); |
3086 | rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); | 3074 | rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); |
3087 | rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); | 3075 | rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); |
@@ -3526,6 +3514,11 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
3526 | } else if (rt2800_is_305x_soc(rt2x00dev)) { | 3514 | } else if (rt2800_is_305x_soc(rt2x00dev)) { |
3527 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); | 3515 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); |
3528 | rt2800_bbp_write(rt2x00dev, 80, 0x08); | 3516 | rt2800_bbp_write(rt2x00dev, 80, 0x08); |
3517 | } else if (rt2x00_rt(rt2x00dev, RT3290)) { | ||
3518 | rt2800_bbp_write(rt2x00dev, 74, 0x0b); | ||
3519 | rt2800_bbp_write(rt2x00dev, 79, 0x18); | ||
3520 | rt2800_bbp_write(rt2x00dev, 80, 0x09); | ||
3521 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
3529 | } else if (rt2x00_rt(rt2x00dev, RT3352)) { | 3522 | } else if (rt2x00_rt(rt2x00dev, RT3352)) { |
3530 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); | 3523 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); |
3531 | rt2800_bbp_write(rt2x00dev, 80, 0x08); | 3524 | rt2800_bbp_write(rt2x00dev, 80, 0x08); |
@@ -3534,13 +3527,6 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
3534 | rt2800_bbp_write(rt2x00dev, 81, 0x37); | 3527 | rt2800_bbp_write(rt2x00dev, 81, 0x37); |
3535 | } | 3528 | } |
3536 | 3529 | ||
3537 | if (rt2x00_rt(rt2x00dev, RT3290)) { | ||
3538 | rt2800_bbp_write(rt2x00dev, 74, 0x0b); | ||
3539 | rt2800_bbp_write(rt2x00dev, 79, 0x18); | ||
3540 | rt2800_bbp_write(rt2x00dev, 80, 0x09); | ||
3541 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
3542 | } | ||
3543 | |||
3544 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | 3530 | rt2800_bbp_write(rt2x00dev, 82, 0x62); |
3545 | if (rt2x00_rt(rt2x00dev, RT3290) || | 3531 | if (rt2x00_rt(rt2x00dev, RT3290) || |
3546 | rt2x00_rt(rt2x00dev, RT5390) || | 3532 | rt2x00_rt(rt2x00dev, RT5390) || |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 391e08fa054b..27829e1e2e38 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -1088,7 +1088,6 @@ static const struct data_queue_desc rt2800pci_queue_bcn = { | |||
1088 | static const struct rt2x00_ops rt2800pci_ops = { | 1088 | static const struct rt2x00_ops rt2800pci_ops = { |
1089 | .name = KBUILD_MODNAME, | 1089 | .name = KBUILD_MODNAME, |
1090 | .drv_data_size = sizeof(struct rt2800_drv_data), | 1090 | .drv_data_size = sizeof(struct rt2800_drv_data), |
1091 | .max_sta_intf = 1, | ||
1092 | .max_ap_intf = 8, | 1091 | .max_ap_intf = 8, |
1093 | .eeprom_size = EEPROM_SIZE, | 1092 | .eeprom_size = EEPROM_SIZE, |
1094 | .rf_size = RF_SIZE, | 1093 | .rf_size = RF_SIZE, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 603b65d6f28b..c9e9370eb789 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -870,7 +870,6 @@ static const struct data_queue_desc rt2800usb_queue_bcn = { | |||
870 | static const struct rt2x00_ops rt2800usb_ops = { | 870 | static const struct rt2x00_ops rt2800usb_ops = { |
871 | .name = KBUILD_MODNAME, | 871 | .name = KBUILD_MODNAME, |
872 | .drv_data_size = sizeof(struct rt2800_drv_data), | 872 | .drv_data_size = sizeof(struct rt2800_drv_data), |
873 | .max_sta_intf = 1, | ||
874 | .max_ap_intf = 8, | 873 | .max_ap_intf = 8, |
875 | .eeprom_size = EEPROM_SIZE, | 874 | .eeprom_size = EEPROM_SIZE, |
876 | .rf_size = RF_SIZE, | 875 | .rf_size = RF_SIZE, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 49375c86c334..0751b35ef6dc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -656,7 +656,6 @@ struct rt2x00lib_ops { | |||
656 | struct rt2x00_ops { | 656 | struct rt2x00_ops { |
657 | const char *name; | 657 | const char *name; |
658 | const unsigned int drv_data_size; | 658 | const unsigned int drv_data_size; |
659 | const unsigned int max_sta_intf; | ||
660 | const unsigned int max_ap_intf; | 659 | const unsigned int max_ap_intf; |
661 | const unsigned int eeprom_size; | 660 | const unsigned int eeprom_size; |
662 | const unsigned int rf_size; | 661 | const unsigned int rf_size; |
@@ -742,6 +741,14 @@ enum rt2x00_capability_flags { | |||
742 | }; | 741 | }; |
743 | 742 | ||
744 | /* | 743 | /* |
744 | * Interface combinations | ||
745 | */ | ||
746 | enum { | ||
747 | IF_COMB_AP = 0, | ||
748 | NUM_IF_COMB, | ||
749 | }; | ||
750 | |||
751 | /* | ||
745 | * rt2x00 device structure. | 752 | * rt2x00 device structure. |
746 | */ | 753 | */ |
747 | struct rt2x00_dev { | 754 | struct rt2x00_dev { |
@@ -868,6 +875,12 @@ struct rt2x00_dev { | |||
868 | unsigned int intf_beaconing; | 875 | unsigned int intf_beaconing; |
869 | 876 | ||
870 | /* | 877 | /* |
878 | * Interface combinations | ||
879 | */ | ||
880 | struct ieee80211_iface_limit if_limits_ap; | ||
881 | struct ieee80211_iface_combination if_combinations[NUM_IF_COMB]; | ||
882 | |||
883 | /* | ||
871 | * Link quality | 884 | * Link quality |
872 | */ | 885 | */ |
873 | struct link link; | 886 | struct link link; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 10cf67267775..69097d1faeb6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -1118,6 +1118,34 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) | |||
1118 | rt2x00dev->intf_associated = 0; | 1118 | rt2x00dev->intf_associated = 0; |
1119 | } | 1119 | } |
1120 | 1120 | ||
1121 | static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) | ||
1122 | { | ||
1123 | struct ieee80211_iface_limit *if_limit; | ||
1124 | struct ieee80211_iface_combination *if_combination; | ||
1125 | |||
1126 | /* | ||
1127 | * Build up AP interface limits structure. | ||
1128 | */ | ||
1129 | if_limit = &rt2x00dev->if_limits_ap; | ||
1130 | if_limit->max = rt2x00dev->ops->max_ap_intf; | ||
1131 | if_limit->types = BIT(NL80211_IFTYPE_AP); | ||
1132 | |||
1133 | /* | ||
1134 | * Build up AP interface combinations structure. | ||
1135 | */ | ||
1136 | if_combination = &rt2x00dev->if_combinations[IF_COMB_AP]; | ||
1137 | if_combination->limits = if_limit; | ||
1138 | if_combination->n_limits = 1; | ||
1139 | if_combination->max_interfaces = if_limit->max; | ||
1140 | if_combination->num_different_channels = 1; | ||
1141 | |||
1142 | /* | ||
1143 | * Finally, specify the possible combinations to mac80211. | ||
1144 | */ | ||
1145 | rt2x00dev->hw->wiphy->iface_combinations = rt2x00dev->if_combinations; | ||
1146 | rt2x00dev->hw->wiphy->n_iface_combinations = 1; | ||
1147 | } | ||
1148 | |||
1121 | /* | 1149 | /* |
1122 | * driver allocation handlers. | 1150 | * driver allocation handlers. |
1123 | */ | 1151 | */ |
@@ -1126,6 +1154,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1126 | int retval = -ENOMEM; | 1154 | int retval = -ENOMEM; |
1127 | 1155 | ||
1128 | /* | 1156 | /* |
1157 | * Set possible interface combinations. | ||
1158 | */ | ||
1159 | rt2x00lib_set_if_combinations(rt2x00dev); | ||
1160 | |||
1161 | /* | ||
1129 | * Allocate the driver data memory, if necessary. | 1162 | * Allocate the driver data memory, if necessary. |
1130 | */ | 1163 | */ |
1131 | if (rt2x00dev->ops->drv_data_size > 0) { | 1164 | if (rt2x00dev->ops->drv_data_size > 0) { |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c3d0f2f87b69..98a9e48f8e4a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -214,46 +214,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | |||
214 | !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) | 214 | !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) |
215 | return -ENODEV; | 215 | return -ENODEV; |
216 | 216 | ||
217 | switch (vif->type) { | ||
218 | case NL80211_IFTYPE_AP: | ||
219 | /* | ||
220 | * We don't support mixed combinations of | ||
221 | * sta and ap interfaces. | ||
222 | */ | ||
223 | if (rt2x00dev->intf_sta_count) | ||
224 | return -ENOBUFS; | ||
225 | |||
226 | /* | ||
227 | * Check if we exceeded the maximum amount | ||
228 | * of supported interfaces. | ||
229 | */ | ||
230 | if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) | ||
231 | return -ENOBUFS; | ||
232 | |||
233 | break; | ||
234 | case NL80211_IFTYPE_STATION: | ||
235 | case NL80211_IFTYPE_ADHOC: | ||
236 | case NL80211_IFTYPE_MESH_POINT: | ||
237 | case NL80211_IFTYPE_WDS: | ||
238 | /* | ||
239 | * We don't support mixed combinations of | ||
240 | * sta and ap interfaces. | ||
241 | */ | ||
242 | if (rt2x00dev->intf_ap_count) | ||
243 | return -ENOBUFS; | ||
244 | |||
245 | /* | ||
246 | * Check if we exceeded the maximum amount | ||
247 | * of supported interfaces. | ||
248 | */ | ||
249 | if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf) | ||
250 | return -ENOBUFS; | ||
251 | |||
252 | break; | ||
253 | default: | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | /* | 217 | /* |
258 | * Loop through all beacon queues to find a free | 218 | * Loop through all beacon queues to find a free |
259 | * entry. Since there are as much beacon entries | 219 | * entry. Since there are as much beacon entries |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2673e058caaf..d6582a2fa353 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -3045,7 +3045,6 @@ static const struct data_queue_desc rt61pci_queue_bcn = { | |||
3045 | 3045 | ||
3046 | static const struct rt2x00_ops rt61pci_ops = { | 3046 | static const struct rt2x00_ops rt61pci_ops = { |
3047 | .name = KBUILD_MODNAME, | 3047 | .name = KBUILD_MODNAME, |
3048 | .max_sta_intf = 1, | ||
3049 | .max_ap_intf = 4, | 3048 | .max_ap_intf = 4, |
3050 | .eeprom_size = EEPROM_SIZE, | 3049 | .eeprom_size = EEPROM_SIZE, |
3051 | .rf_size = RF_SIZE, | 3050 | .rf_size = RF_SIZE, |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cfa9f37cccc2..e5eb43b3eee7 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2382,7 +2382,6 @@ static const struct data_queue_desc rt73usb_queue_bcn = { | |||
2382 | 2382 | ||
2383 | static const struct rt2x00_ops rt73usb_ops = { | 2383 | static const struct rt2x00_ops rt73usb_ops = { |
2384 | .name = KBUILD_MODNAME, | 2384 | .name = KBUILD_MODNAME, |
2385 | .max_sta_intf = 1, | ||
2386 | .max_ap_intf = 4, | 2385 | .max_ap_intf = 4, |
2387 | .eeprom_size = EEPROM_SIZE, | 2386 | .eeprom_size = EEPROM_SIZE, |
2388 | .rf_size = RF_SIZE, | 2387 | .rf_size = RF_SIZE, |
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 3b20b73ee649..ec857676c39f 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig | |||
@@ -5,21 +5,9 @@ | |||
5 | menu "Near Field Communication (NFC) devices" | 5 | menu "Near Field Communication (NFC) devices" |
6 | depends on NFC | 6 | depends on NFC |
7 | 7 | ||
8 | config PN544_NFC | ||
9 | tristate "PN544 NFC driver" | ||
10 | depends on I2C | ||
11 | select CRC_CCITT | ||
12 | default n | ||
13 | ---help--- | ||
14 | Say yes if you want PN544 Near Field Communication driver. | ||
15 | This is for i2c connected version. If unsure, say N here. | ||
16 | |||
17 | To compile this driver as a module, choose m here. The module will | ||
18 | be called pn544. | ||
19 | |||
20 | config PN544_HCI_NFC | 8 | config PN544_HCI_NFC |
21 | tristate "HCI PN544 NFC driver" | 9 | tristate "HCI PN544 NFC driver" |
22 | depends on I2C && NFC_SHDLC | 10 | depends on I2C && NFC_HCI && NFC_SHDLC |
23 | select CRC_CCITT | 11 | select CRC_CCITT |
24 | default n | 12 | default n |
25 | ---help--- | 13 | ---help--- |
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 473e44cef612..bf05831fdf09 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile | |||
@@ -2,7 +2,6 @@ | |||
2 | # Makefile for nfc devices | 2 | # Makefile for nfc devices |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_PN544_NFC) += pn544.o | ||
6 | obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o | 5 | obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o |
7 | obj-$(CONFIG_NFC_PN533) += pn533.o | 6 | obj-$(CONFIG_NFC_PN533) += pn533.o |
8 | obj-$(CONFIG_NFC_WILINK) += nfcwilink.o | 7 | obj-$(CONFIG_NFC_WILINK) += nfcwilink.o |
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index e7fd4938f9bc..50b1ee41afc6 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c | |||
@@ -352,8 +352,6 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb) | |||
352 | struct nfcwilink *drv = priv_data; | 352 | struct nfcwilink *drv = priv_data; |
353 | int rc; | 353 | int rc; |
354 | 354 | ||
355 | nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len); | ||
356 | |||
357 | if (!skb) | 355 | if (!skb) |
358 | return -EFAULT; | 356 | return -EFAULT; |
359 | 357 | ||
@@ -362,6 +360,8 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb) | |||
362 | return -EFAULT; | 360 | return -EFAULT; |
363 | } | 361 | } |
364 | 362 | ||
363 | nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len); | ||
364 | |||
365 | /* strip the ST header | 365 | /* strip the ST header |
366 | (apart for the chnl byte, which is not received in the hdr) */ | 366 | (apart for the chnl byte, which is not received in the hdr) */ |
367 | skb_pull(skb, (NFCWILINK_HDR_LEN-1)); | 367 | skb_pull(skb, (NFCWILINK_HDR_LEN-1)); |
@@ -604,21 +604,7 @@ static struct platform_driver nfcwilink_driver = { | |||
604 | }, | 604 | }, |
605 | }; | 605 | }; |
606 | 606 | ||
607 | /* ------- Module Init/Exit interfaces ------ */ | 607 | module_platform_driver(nfcwilink_driver); |
608 | static int __init nfcwilink_init(void) | ||
609 | { | ||
610 | printk(KERN_INFO "NFC Driver for TI WiLink"); | ||
611 | |||
612 | return platform_driver_register(&nfcwilink_driver); | ||
613 | } | ||
614 | |||
615 | static void __exit nfcwilink_exit(void) | ||
616 | { | ||
617 | platform_driver_unregister(&nfcwilink_driver); | ||
618 | } | ||
619 | |||
620 | module_init(nfcwilink_init); | ||
621 | module_exit(nfcwilink_exit); | ||
622 | 608 | ||
623 | /* ------ Module Info ------ */ | 609 | /* ------ Module Info ------ */ |
624 | 610 | ||
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index d606f52fec84..97c440a8cd61 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -356,6 +356,7 @@ struct pn533 { | |||
356 | 356 | ||
357 | struct workqueue_struct *wq; | 357 | struct workqueue_struct *wq; |
358 | struct work_struct cmd_work; | 358 | struct work_struct cmd_work; |
359 | struct work_struct cmd_complete_work; | ||
359 | struct work_struct poll_work; | 360 | struct work_struct poll_work; |
360 | struct work_struct mi_work; | 361 | struct work_struct mi_work; |
361 | struct work_struct tg_work; | 362 | struct work_struct tg_work; |
@@ -383,6 +384,19 @@ struct pn533 { | |||
383 | u8 tgt_mode; | 384 | u8 tgt_mode; |
384 | 385 | ||
385 | u32 device_type; | 386 | u32 device_type; |
387 | |||
388 | struct list_head cmd_queue; | ||
389 | u8 cmd_pending; | ||
390 | }; | ||
391 | |||
392 | struct pn533_cmd { | ||
393 | struct list_head queue; | ||
394 | struct pn533_frame *out_frame; | ||
395 | struct pn533_frame *in_frame; | ||
396 | int in_frame_len; | ||
397 | pn533_cmd_complete_t cmd_complete; | ||
398 | void *arg; | ||
399 | gfp_t flags; | ||
386 | }; | 400 | }; |
387 | 401 | ||
388 | struct pn533_frame { | 402 | struct pn533_frame { |
@@ -487,7 +501,7 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd) | |||
487 | 501 | ||
488 | static void pn533_wq_cmd_complete(struct work_struct *work) | 502 | static void pn533_wq_cmd_complete(struct work_struct *work) |
489 | { | 503 | { |
490 | struct pn533 *dev = container_of(work, struct pn533, cmd_work); | 504 | struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); |
491 | struct pn533_frame *in_frame; | 505 | struct pn533_frame *in_frame; |
492 | int rc; | 506 | int rc; |
493 | 507 | ||
@@ -502,7 +516,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work) | |||
502 | PN533_FRAME_CMD_PARAMS_LEN(in_frame)); | 516 | PN533_FRAME_CMD_PARAMS_LEN(in_frame)); |
503 | 517 | ||
504 | if (rc != -EINPROGRESS) | 518 | if (rc != -EINPROGRESS) |
505 | mutex_unlock(&dev->cmd_lock); | 519 | queue_work(dev->wq, &dev->cmd_work); |
506 | } | 520 | } |
507 | 521 | ||
508 | static void pn533_recv_response(struct urb *urb) | 522 | static void pn533_recv_response(struct urb *urb) |
@@ -550,7 +564,7 @@ static void pn533_recv_response(struct urb *urb) | |||
550 | dev->wq_in_frame = in_frame; | 564 | dev->wq_in_frame = in_frame; |
551 | 565 | ||
552 | sched_wq: | 566 | sched_wq: |
553 | queue_work(dev->wq, &dev->cmd_work); | 567 | queue_work(dev->wq, &dev->cmd_complete_work); |
554 | } | 568 | } |
555 | 569 | ||
556 | static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) | 570 | static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) |
@@ -606,7 +620,7 @@ static void pn533_recv_ack(struct urb *urb) | |||
606 | 620 | ||
607 | sched_wq: | 621 | sched_wq: |
608 | dev->wq_in_frame = NULL; | 622 | dev->wq_in_frame = NULL; |
609 | queue_work(dev->wq, &dev->cmd_work); | 623 | queue_work(dev->wq, &dev->cmd_complete_work); |
610 | } | 624 | } |
611 | 625 | ||
612 | static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) | 626 | static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) |
@@ -669,6 +683,31 @@ error: | |||
669 | return rc; | 683 | return rc; |
670 | } | 684 | } |
671 | 685 | ||
686 | static void pn533_wq_cmd(struct work_struct *work) | ||
687 | { | ||
688 | struct pn533 *dev = container_of(work, struct pn533, cmd_work); | ||
689 | struct pn533_cmd *cmd; | ||
690 | |||
691 | mutex_lock(&dev->cmd_lock); | ||
692 | |||
693 | if (list_empty(&dev->cmd_queue)) { | ||
694 | dev->cmd_pending = 0; | ||
695 | mutex_unlock(&dev->cmd_lock); | ||
696 | return; | ||
697 | } | ||
698 | |||
699 | cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); | ||
700 | |||
701 | mutex_unlock(&dev->cmd_lock); | ||
702 | |||
703 | __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, | ||
704 | cmd->in_frame_len, cmd->cmd_complete, | ||
705 | cmd->arg, cmd->flags); | ||
706 | |||
707 | list_del(&cmd->queue); | ||
708 | kfree(cmd); | ||
709 | } | ||
710 | |||
672 | static int pn533_send_cmd_frame_async(struct pn533 *dev, | 711 | static int pn533_send_cmd_frame_async(struct pn533 *dev, |
673 | struct pn533_frame *out_frame, | 712 | struct pn533_frame *out_frame, |
674 | struct pn533_frame *in_frame, | 713 | struct pn533_frame *in_frame, |
@@ -676,21 +715,44 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, | |||
676 | pn533_cmd_complete_t cmd_complete, | 715 | pn533_cmd_complete_t cmd_complete, |
677 | void *arg, gfp_t flags) | 716 | void *arg, gfp_t flags) |
678 | { | 717 | { |
679 | int rc; | 718 | struct pn533_cmd *cmd; |
719 | int rc = 0; | ||
680 | 720 | ||
681 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 721 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
682 | 722 | ||
683 | if (!mutex_trylock(&dev->cmd_lock)) | 723 | mutex_lock(&dev->cmd_lock); |
684 | return -EBUSY; | ||
685 | 724 | ||
686 | rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, | 725 | if (!dev->cmd_pending) { |
687 | in_frame_len, cmd_complete, arg, flags); | 726 | rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, |
688 | if (rc) | 727 | in_frame_len, cmd_complete, |
689 | goto error; | 728 | arg, flags); |
729 | if (!rc) | ||
730 | dev->cmd_pending = 1; | ||
690 | 731 | ||
691 | return 0; | 732 | goto unlock; |
692 | error: | 733 | } |
734 | |||
735 | nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); | ||
736 | |||
737 | cmd = kzalloc(sizeof(struct pn533_cmd), flags); | ||
738 | if (!cmd) { | ||
739 | rc = -ENOMEM; | ||
740 | goto unlock; | ||
741 | } | ||
742 | |||
743 | INIT_LIST_HEAD(&cmd->queue); | ||
744 | cmd->out_frame = out_frame; | ||
745 | cmd->in_frame = in_frame; | ||
746 | cmd->in_frame_len = in_frame_len; | ||
747 | cmd->cmd_complete = cmd_complete; | ||
748 | cmd->arg = arg; | ||
749 | cmd->flags = flags; | ||
750 | |||
751 | list_add_tail(&cmd->queue, &dev->cmd_queue); | ||
752 | |||
753 | unlock: | ||
693 | mutex_unlock(&dev->cmd_lock); | 754 | mutex_unlock(&dev->cmd_lock); |
755 | |||
694 | return rc; | 756 | return rc; |
695 | } | 757 | } |
696 | 758 | ||
@@ -1305,8 +1367,6 @@ static void pn533_listen_mode_timer(unsigned long data) | |||
1305 | 1367 | ||
1306 | dev->cancel_listen = 1; | 1368 | dev->cancel_listen = 1; |
1307 | 1369 | ||
1308 | mutex_unlock(&dev->cmd_lock); | ||
1309 | |||
1310 | pn533_poll_next_mod(dev); | 1370 | pn533_poll_next_mod(dev); |
1311 | 1371 | ||
1312 | queue_work(dev->wq, &dev->poll_work); | 1372 | queue_work(dev->wq, &dev->poll_work); |
@@ -2131,7 +2191,7 @@ error_cmd: | |||
2131 | 2191 | ||
2132 | kfree(arg); | 2192 | kfree(arg); |
2133 | 2193 | ||
2134 | mutex_unlock(&dev->cmd_lock); | 2194 | queue_work(dev->wq, &dev->cmd_work); |
2135 | } | 2195 | } |
2136 | 2196 | ||
2137 | static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, | 2197 | static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, |
@@ -2330,13 +2390,12 @@ static int pn533_probe(struct usb_interface *interface, | |||
2330 | NULL, 0, | 2390 | NULL, 0, |
2331 | pn533_send_complete, dev); | 2391 | pn533_send_complete, dev); |
2332 | 2392 | ||
2333 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); | 2393 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd); |
2394 | INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); | ||
2334 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); | 2395 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); |
2335 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); | 2396 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); |
2336 | INIT_WORK(&dev->poll_work, pn533_wq_poll); | 2397 | INIT_WORK(&dev->poll_work, pn533_wq_poll); |
2337 | dev->wq = alloc_workqueue("pn533", | 2398 | dev->wq = alloc_ordered_workqueue("pn533", 0); |
2338 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
2339 | 1); | ||
2340 | if (dev->wq == NULL) | 2399 | if (dev->wq == NULL) |
2341 | goto error; | 2400 | goto error; |
2342 | 2401 | ||
@@ -2346,6 +2405,8 @@ static int pn533_probe(struct usb_interface *interface, | |||
2346 | 2405 | ||
2347 | skb_queue_head_init(&dev->resp_q); | 2406 | skb_queue_head_init(&dev->resp_q); |
2348 | 2407 | ||
2408 | INIT_LIST_HEAD(&dev->cmd_queue); | ||
2409 | |||
2349 | usb_set_intfdata(interface, dev); | 2410 | usb_set_intfdata(interface, dev); |
2350 | 2411 | ||
2351 | pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); | 2412 | pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); |
@@ -2417,6 +2478,7 @@ error: | |||
2417 | static void pn533_disconnect(struct usb_interface *interface) | 2478 | static void pn533_disconnect(struct usb_interface *interface) |
2418 | { | 2479 | { |
2419 | struct pn533 *dev; | 2480 | struct pn533 *dev; |
2481 | struct pn533_cmd *cmd, *n; | ||
2420 | 2482 | ||
2421 | dev = usb_get_intfdata(interface); | 2483 | dev = usb_get_intfdata(interface); |
2422 | usb_set_intfdata(interface, NULL); | 2484 | usb_set_intfdata(interface, NULL); |
@@ -2433,6 +2495,11 @@ static void pn533_disconnect(struct usb_interface *interface) | |||
2433 | 2495 | ||
2434 | del_timer(&dev->listen_timer); | 2496 | del_timer(&dev->listen_timer); |
2435 | 2497 | ||
2498 | list_for_each_entry_safe(cmd, n, &dev->cmd_queue, queue) { | ||
2499 | list_del(&cmd->queue); | ||
2500 | kfree(cmd); | ||
2501 | } | ||
2502 | |||
2436 | kfree(dev->in_frame); | 2503 | kfree(dev->in_frame); |
2437 | usb_free_urb(dev->in_urb); | 2504 | usb_free_urb(dev->in_urb); |
2438 | kfree(dev->out_frame); | 2505 | kfree(dev->out_frame); |
diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c deleted file mode 100644 index 724f65d8f9e4..000000000000 --- a/drivers/nfc/pn544.c +++ /dev/null | |||
@@ -1,893 +0,0 @@ | |||
1 | /* | ||
2 | * Driver for the PN544 NFC chip. | ||
3 | * | ||
4 | * Copyright (C) Nokia Corporation | ||
5 | * | ||
6 | * Author: Jari Vanhala <ext-jari.vanhala@nokia.com> | ||
7 | * Contact: Matti Aaltonen <matti.j.aaltonen@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/completion.h> | ||
24 | #include <linux/crc-ccitt.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/miscdevice.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/mutex.h> | ||
31 | #include <linux/nfc/pn544.h> | ||
32 | #include <linux/poll.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/serial_core.h> /* for TCGETS */ | ||
35 | #include <linux/slab.h> | ||
36 | |||
37 | #define DRIVER_CARD "PN544 NFC" | ||
38 | #define DRIVER_DESC "NFC driver for PN544" | ||
39 | |||
40 | static struct i2c_device_id pn544_id_table[] = { | ||
41 | { PN544_DRIVER_NAME, 0 }, | ||
42 | { } | ||
43 | }; | ||
44 | MODULE_DEVICE_TABLE(i2c, pn544_id_table); | ||
45 | |||
46 | #define HCI_MODE 0 | ||
47 | #define FW_MODE 1 | ||
48 | |||
49 | enum pn544_state { | ||
50 | PN544_ST_COLD, | ||
51 | PN544_ST_FW_READY, | ||
52 | PN544_ST_READY, | ||
53 | }; | ||
54 | |||
55 | enum pn544_irq { | ||
56 | PN544_NONE, | ||
57 | PN544_INT, | ||
58 | }; | ||
59 | |||
60 | struct pn544_info { | ||
61 | struct miscdevice miscdev; | ||
62 | struct i2c_client *i2c_dev; | ||
63 | struct regulator_bulk_data regs[3]; | ||
64 | |||
65 | enum pn544_state state; | ||
66 | wait_queue_head_t read_wait; | ||
67 | loff_t read_offset; | ||
68 | enum pn544_irq read_irq; | ||
69 | struct mutex read_mutex; /* Serialize read_irq access */ | ||
70 | struct mutex mutex; /* Serialize info struct access */ | ||
71 | u8 *buf; | ||
72 | size_t buflen; | ||
73 | }; | ||
74 | |||
75 | static const char reg_vdd_io[] = "Vdd_IO"; | ||
76 | static const char reg_vbat[] = "VBat"; | ||
77 | static const char reg_vsim[] = "VSim"; | ||
78 | |||
79 | /* sysfs interface */ | ||
80 | static ssize_t pn544_test(struct device *dev, | ||
81 | struct device_attribute *attr, char *buf) | ||
82 | { | ||
83 | struct pn544_info *info = dev_get_drvdata(dev); | ||
84 | struct i2c_client *client = info->i2c_dev; | ||
85 | struct pn544_nfc_platform_data *pdata = client->dev.platform_data; | ||
86 | |||
87 | return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test()); | ||
88 | } | ||
89 | |||
90 | static int pn544_enable(struct pn544_info *info, int mode) | ||
91 | { | ||
92 | struct pn544_nfc_platform_data *pdata; | ||
93 | struct i2c_client *client = info->i2c_dev; | ||
94 | |||
95 | int r; | ||
96 | |||
97 | r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs); | ||
98 | if (r < 0) | ||
99 | return r; | ||
100 | |||
101 | pdata = client->dev.platform_data; | ||
102 | info->read_irq = PN544_NONE; | ||
103 | if (pdata->enable) | ||
104 | pdata->enable(mode); | ||
105 | |||
106 | if (mode) { | ||
107 | info->state = PN544_ST_FW_READY; | ||
108 | dev_dbg(&client->dev, "now in FW-mode\n"); | ||
109 | } else { | ||
110 | info->state = PN544_ST_READY; | ||
111 | dev_dbg(&client->dev, "now in HCI-mode\n"); | ||
112 | } | ||
113 | |||
114 | usleep_range(10000, 15000); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void pn544_disable(struct pn544_info *info) | ||
120 | { | ||
121 | struct pn544_nfc_platform_data *pdata; | ||
122 | struct i2c_client *client = info->i2c_dev; | ||
123 | |||
124 | pdata = client->dev.platform_data; | ||
125 | if (pdata->disable) | ||
126 | pdata->disable(); | ||
127 | |||
128 | info->state = PN544_ST_COLD; | ||
129 | |||
130 | dev_dbg(&client->dev, "Now in OFF-mode\n"); | ||
131 | |||
132 | msleep(PN544_RESETVEN_TIME); | ||
133 | |||
134 | info->read_irq = PN544_NONE; | ||
135 | regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs); | ||
136 | } | ||
137 | |||
138 | static int check_crc(u8 *buf, int buflen) | ||
139 | { | ||
140 | u8 len; | ||
141 | u16 crc; | ||
142 | |||
143 | len = buf[0] + 1; | ||
144 | if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) { | ||
145 | pr_err(PN544_DRIVER_NAME | ||
146 | ": CRC; corrupt packet len %u (%d)\n", len, buflen); | ||
147 | print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, | ||
148 | 16, 2, buf, buflen, false); | ||
149 | return -EPERM; | ||
150 | } | ||
151 | crc = crc_ccitt(0xffff, buf, len - 2); | ||
152 | crc = ~crc; | ||
153 | |||
154 | if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) { | ||
155 | pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", | ||
156 | crc, buf[len-1], buf[len-2]); | ||
157 | |||
158 | print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, | ||
159 | 16, 2, buf, buflen, false); | ||
160 | return -EPERM; | ||
161 | } | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len) | ||
166 | { | ||
167 | int r; | ||
168 | |||
169 | if (len < 4 || len != (buf[0] + 1)) { | ||
170 | dev_err(&client->dev, "%s: Illegal message length: %d\n", | ||
171 | __func__, len); | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | if (check_crc(buf, len)) | ||
176 | return -EINVAL; | ||
177 | |||
178 | usleep_range(3000, 6000); | ||
179 | |||
180 | r = i2c_master_send(client, buf, len); | ||
181 | dev_dbg(&client->dev, "send: %d\n", r); | ||
182 | |||
183 | if (r == -EREMOTEIO) { /* Retry, chip was in standby */ | ||
184 | usleep_range(6000, 10000); | ||
185 | r = i2c_master_send(client, buf, len); | ||
186 | dev_dbg(&client->dev, "send2: %d\n", r); | ||
187 | } | ||
188 | |||
189 | if (r != len) | ||
190 | return -EREMOTEIO; | ||
191 | |||
192 | return r; | ||
193 | } | ||
194 | |||
195 | static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen) | ||
196 | { | ||
197 | int r; | ||
198 | u8 len; | ||
199 | |||
200 | /* | ||
201 | * You could read a packet in one go, but then you'd need to read | ||
202 | * max size and rest would be 0xff fill, so we do split reads. | ||
203 | */ | ||
204 | r = i2c_master_recv(client, &len, 1); | ||
205 | dev_dbg(&client->dev, "recv1: %d\n", r); | ||
206 | |||
207 | if (r != 1) | ||
208 | return -EREMOTEIO; | ||
209 | |||
210 | if (len < PN544_LLC_HCI_OVERHEAD) | ||
211 | len = PN544_LLC_HCI_OVERHEAD; | ||
212 | else if (len > (PN544_MSG_MAX_SIZE - 1)) | ||
213 | len = PN544_MSG_MAX_SIZE - 1; | ||
214 | |||
215 | if (1 + len > buflen) /* len+(data+crc16) */ | ||
216 | return -EMSGSIZE; | ||
217 | |||
218 | buf[0] = len; | ||
219 | |||
220 | r = i2c_master_recv(client, buf + 1, len); | ||
221 | dev_dbg(&client->dev, "recv2: %d\n", r); | ||
222 | |||
223 | if (r != len) | ||
224 | return -EREMOTEIO; | ||
225 | |||
226 | usleep_range(3000, 6000); | ||
227 | |||
228 | return r + 1; | ||
229 | } | ||
230 | |||
231 | static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len) | ||
232 | { | ||
233 | int r; | ||
234 | |||
235 | dev_dbg(&client->dev, "%s\n", __func__); | ||
236 | |||
237 | if (len < PN544_FW_HEADER_SIZE || | ||
238 | (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len) | ||
239 | return -EINVAL; | ||
240 | |||
241 | r = i2c_master_send(client, buf, len); | ||
242 | dev_dbg(&client->dev, "fw send: %d\n", r); | ||
243 | |||
244 | if (r == -EREMOTEIO) { /* Retry, chip was in standby */ | ||
245 | usleep_range(6000, 10000); | ||
246 | r = i2c_master_send(client, buf, len); | ||
247 | dev_dbg(&client->dev, "fw send2: %d\n", r); | ||
248 | } | ||
249 | |||
250 | if (r != len) | ||
251 | return -EREMOTEIO; | ||
252 | |||
253 | return r; | ||
254 | } | ||
255 | |||
256 | static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen) | ||
257 | { | ||
258 | int r, len; | ||
259 | |||
260 | if (buflen < PN544_FW_HEADER_SIZE) | ||
261 | return -EINVAL; | ||
262 | |||
263 | r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE); | ||
264 | dev_dbg(&client->dev, "FW recv1: %d\n", r); | ||
265 | |||
266 | if (r < 0) | ||
267 | return r; | ||
268 | |||
269 | if (r < PN544_FW_HEADER_SIZE) | ||
270 | return -EINVAL; | ||
271 | |||
272 | len = (buf[1] << 8) + buf[2]; | ||
273 | if (len == 0) /* just header, no additional data */ | ||
274 | return r; | ||
275 | |||
276 | if (len > buflen - PN544_FW_HEADER_SIZE) | ||
277 | return -EMSGSIZE; | ||
278 | |||
279 | r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len); | ||
280 | dev_dbg(&client->dev, "fw recv2: %d\n", r); | ||
281 | |||
282 | if (r != len) | ||
283 | return -EINVAL; | ||
284 | |||
285 | return r + PN544_FW_HEADER_SIZE; | ||
286 | } | ||
287 | |||
288 | static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id) | ||
289 | { | ||
290 | struct pn544_info *info = dev_id; | ||
291 | struct i2c_client *client = info->i2c_dev; | ||
292 | |||
293 | BUG_ON(!info); | ||
294 | BUG_ON(irq != info->i2c_dev->irq); | ||
295 | |||
296 | dev_dbg(&client->dev, "IRQ\n"); | ||
297 | |||
298 | mutex_lock(&info->read_mutex); | ||
299 | info->read_irq = PN544_INT; | ||
300 | mutex_unlock(&info->read_mutex); | ||
301 | |||
302 | wake_up_interruptible(&info->read_wait); | ||
303 | |||
304 | return IRQ_HANDLED; | ||
305 | } | ||
306 | |||
307 | static enum pn544_irq pn544_irq_state(struct pn544_info *info) | ||
308 | { | ||
309 | enum pn544_irq irq; | ||
310 | |||
311 | mutex_lock(&info->read_mutex); | ||
312 | irq = info->read_irq; | ||
313 | mutex_unlock(&info->read_mutex); | ||
314 | /* | ||
315 | * XXX: should we check GPIO-line status directly? | ||
316 | * return pdata->irq_status() ? PN544_INT : PN544_NONE; | ||
317 | */ | ||
318 | |||
319 | return irq; | ||
320 | } | ||
321 | |||
322 | static ssize_t pn544_read(struct file *file, char __user *buf, | ||
323 | size_t count, loff_t *offset) | ||
324 | { | ||
325 | struct pn544_info *info = container_of(file->private_data, | ||
326 | struct pn544_info, miscdev); | ||
327 | struct i2c_client *client = info->i2c_dev; | ||
328 | enum pn544_irq irq; | ||
329 | size_t len; | ||
330 | int r = 0; | ||
331 | |||
332 | dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__, | ||
333 | info, count); | ||
334 | |||
335 | mutex_lock(&info->mutex); | ||
336 | |||
337 | if (info->state == PN544_ST_COLD) { | ||
338 | r = -ENODEV; | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | irq = pn544_irq_state(info); | ||
343 | if (irq == PN544_NONE) { | ||
344 | if (file->f_flags & O_NONBLOCK) { | ||
345 | r = -EAGAIN; | ||
346 | goto out; | ||
347 | } | ||
348 | |||
349 | if (wait_event_interruptible(info->read_wait, | ||
350 | (info->read_irq == PN544_INT))) { | ||
351 | r = -ERESTARTSYS; | ||
352 | goto out; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | if (info->state == PN544_ST_FW_READY) { | ||
357 | len = min(count, info->buflen); | ||
358 | |||
359 | mutex_lock(&info->read_mutex); | ||
360 | r = pn544_fw_read(info->i2c_dev, info->buf, len); | ||
361 | info->read_irq = PN544_NONE; | ||
362 | mutex_unlock(&info->read_mutex); | ||
363 | |||
364 | if (r < 0) { | ||
365 | dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r); | ||
366 | goto out; | ||
367 | } | ||
368 | |||
369 | print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE, | ||
370 | 16, 2, info->buf, r, false); | ||
371 | |||
372 | *offset += r; | ||
373 | if (copy_to_user(buf, info->buf, r)) { | ||
374 | r = -EFAULT; | ||
375 | goto out; | ||
376 | } | ||
377 | } else { | ||
378 | len = min(count, info->buflen); | ||
379 | |||
380 | mutex_lock(&info->read_mutex); | ||
381 | r = pn544_i2c_read(info->i2c_dev, info->buf, len); | ||
382 | info->read_irq = PN544_NONE; | ||
383 | mutex_unlock(&info->read_mutex); | ||
384 | |||
385 | if (r < 0) { | ||
386 | dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r); | ||
387 | goto out; | ||
388 | } | ||
389 | print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE, | ||
390 | 16, 2, info->buf, r, false); | ||
391 | |||
392 | *offset += r; | ||
393 | if (copy_to_user(buf, info->buf, r)) { | ||
394 | r = -EFAULT; | ||
395 | goto out; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | out: | ||
400 | mutex_unlock(&info->mutex); | ||
401 | |||
402 | return r; | ||
403 | } | ||
404 | |||
405 | static unsigned int pn544_poll(struct file *file, poll_table *wait) | ||
406 | { | ||
407 | struct pn544_info *info = container_of(file->private_data, | ||
408 | struct pn544_info, miscdev); | ||
409 | struct i2c_client *client = info->i2c_dev; | ||
410 | int r = 0; | ||
411 | |||
412 | dev_dbg(&client->dev, "%s: info: %p\n", __func__, info); | ||
413 | |||
414 | mutex_lock(&info->mutex); | ||
415 | |||
416 | if (info->state == PN544_ST_COLD) { | ||
417 | r = -ENODEV; | ||
418 | goto out; | ||
419 | } | ||
420 | |||
421 | poll_wait(file, &info->read_wait, wait); | ||
422 | |||
423 | if (pn544_irq_state(info) == PN544_INT) { | ||
424 | r = POLLIN | POLLRDNORM; | ||
425 | goto out; | ||
426 | } | ||
427 | out: | ||
428 | mutex_unlock(&info->mutex); | ||
429 | |||
430 | return r; | ||
431 | } | ||
432 | |||
433 | static ssize_t pn544_write(struct file *file, const char __user *buf, | ||
434 | size_t count, loff_t *ppos) | ||
435 | { | ||
436 | struct pn544_info *info = container_of(file->private_data, | ||
437 | struct pn544_info, miscdev); | ||
438 | struct i2c_client *client = info->i2c_dev; | ||
439 | ssize_t len; | ||
440 | int r; | ||
441 | |||
442 | dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__, | ||
443 | info, count); | ||
444 | |||
445 | mutex_lock(&info->mutex); | ||
446 | |||
447 | if (info->state == PN544_ST_COLD) { | ||
448 | r = -ENODEV; | ||
449 | goto out; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * XXX: should we detect rset-writes and clean possible | ||
454 | * read_irq state | ||
455 | */ | ||
456 | if (info->state == PN544_ST_FW_READY) { | ||
457 | size_t fw_len; | ||
458 | |||
459 | if (count < PN544_FW_HEADER_SIZE) { | ||
460 | r = -EINVAL; | ||
461 | goto out; | ||
462 | } | ||
463 | |||
464 | len = min(count, info->buflen); | ||
465 | if (copy_from_user(info->buf, buf, len)) { | ||
466 | r = -EFAULT; | ||
467 | goto out; | ||
468 | } | ||
469 | |||
470 | print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE, | ||
471 | 16, 2, info->buf, len, false); | ||
472 | |||
473 | fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) + | ||
474 | info->buf[2]; | ||
475 | |||
476 | if (len > fw_len) /* 1 msg at a time */ | ||
477 | len = fw_len; | ||
478 | |||
479 | r = pn544_fw_write(info->i2c_dev, info->buf, len); | ||
480 | } else { | ||
481 | if (count < PN544_LLC_MIN_SIZE) { | ||
482 | r = -EINVAL; | ||
483 | goto out; | ||
484 | } | ||
485 | |||
486 | len = min(count, info->buflen); | ||
487 | if (copy_from_user(info->buf, buf, len)) { | ||
488 | r = -EFAULT; | ||
489 | goto out; | ||
490 | } | ||
491 | |||
492 | print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE, | ||
493 | 16, 2, info->buf, len, false); | ||
494 | |||
495 | if (len > (info->buf[0] + 1)) /* 1 msg at a time */ | ||
496 | len = info->buf[0] + 1; | ||
497 | |||
498 | r = pn544_i2c_write(info->i2c_dev, info->buf, len); | ||
499 | } | ||
500 | out: | ||
501 | mutex_unlock(&info->mutex); | ||
502 | |||
503 | return r; | ||
504 | |||
505 | } | ||
506 | |||
507 | static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
508 | { | ||
509 | struct pn544_info *info = container_of(file->private_data, | ||
510 | struct pn544_info, miscdev); | ||
511 | struct i2c_client *client = info->i2c_dev; | ||
512 | struct pn544_nfc_platform_data *pdata; | ||
513 | unsigned int val; | ||
514 | int r = 0; | ||
515 | |||
516 | dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd); | ||
517 | |||
518 | mutex_lock(&info->mutex); | ||
519 | |||
520 | if (info->state == PN544_ST_COLD) { | ||
521 | r = -ENODEV; | ||
522 | goto out; | ||
523 | } | ||
524 | |||
525 | pdata = info->i2c_dev->dev.platform_data; | ||
526 | switch (cmd) { | ||
527 | case PN544_GET_FW_MODE: | ||
528 | dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__); | ||
529 | |||
530 | val = (info->state == PN544_ST_FW_READY); | ||
531 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) { | ||
532 | r = -EFAULT; | ||
533 | goto out; | ||
534 | } | ||
535 | |||
536 | break; | ||
537 | |||
538 | case PN544_SET_FW_MODE: | ||
539 | dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__); | ||
540 | |||
541 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) { | ||
542 | r = -EFAULT; | ||
543 | goto out; | ||
544 | } | ||
545 | |||
546 | if (val) { | ||
547 | if (info->state == PN544_ST_FW_READY) | ||
548 | break; | ||
549 | |||
550 | pn544_disable(info); | ||
551 | r = pn544_enable(info, FW_MODE); | ||
552 | if (r < 0) | ||
553 | goto out; | ||
554 | } else { | ||
555 | if (info->state == PN544_ST_READY) | ||
556 | break; | ||
557 | pn544_disable(info); | ||
558 | r = pn544_enable(info, HCI_MODE); | ||
559 | if (r < 0) | ||
560 | goto out; | ||
561 | } | ||
562 | file->f_pos = info->read_offset; | ||
563 | break; | ||
564 | |||
565 | case TCGETS: | ||
566 | dev_dbg(&client->dev, "%s: TCGETS\n", __func__); | ||
567 | |||
568 | r = -ENOIOCTLCMD; | ||
569 | break; | ||
570 | |||
571 | default: | ||
572 | dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd); | ||
573 | r = -ENOIOCTLCMD; | ||
574 | break; | ||
575 | } | ||
576 | |||
577 | out: | ||
578 | mutex_unlock(&info->mutex); | ||
579 | |||
580 | return r; | ||
581 | } | ||
582 | |||
583 | static int pn544_open(struct inode *inode, struct file *file) | ||
584 | { | ||
585 | struct pn544_info *info = container_of(file->private_data, | ||
586 | struct pn544_info, miscdev); | ||
587 | struct i2c_client *client = info->i2c_dev; | ||
588 | int r = 0; | ||
589 | |||
590 | dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, | ||
591 | info, info->i2c_dev); | ||
592 | |||
593 | mutex_lock(&info->mutex); | ||
594 | |||
595 | /* | ||
596 | * Only 1 at a time. | ||
597 | * XXX: maybe user (counter) would work better | ||
598 | */ | ||
599 | if (info->state != PN544_ST_COLD) { | ||
600 | r = -EBUSY; | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | file->f_pos = info->read_offset; | ||
605 | r = pn544_enable(info, HCI_MODE); | ||
606 | |||
607 | out: | ||
608 | mutex_unlock(&info->mutex); | ||
609 | return r; | ||
610 | } | ||
611 | |||
612 | static int pn544_close(struct inode *inode, struct file *file) | ||
613 | { | ||
614 | struct pn544_info *info = container_of(file->private_data, | ||
615 | struct pn544_info, miscdev); | ||
616 | struct i2c_client *client = info->i2c_dev; | ||
617 | |||
618 | dev_dbg(&client->dev, "%s: info: %p, client %p\n", | ||
619 | __func__, info, info->i2c_dev); | ||
620 | |||
621 | mutex_lock(&info->mutex); | ||
622 | pn544_disable(info); | ||
623 | mutex_unlock(&info->mutex); | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static const struct file_operations pn544_fops = { | ||
629 | .owner = THIS_MODULE, | ||
630 | .llseek = no_llseek, | ||
631 | .read = pn544_read, | ||
632 | .write = pn544_write, | ||
633 | .poll = pn544_poll, | ||
634 | .open = pn544_open, | ||
635 | .release = pn544_close, | ||
636 | .unlocked_ioctl = pn544_ioctl, | ||
637 | }; | ||
638 | |||
639 | #ifdef CONFIG_PM | ||
640 | static int pn544_suspend(struct device *dev) | ||
641 | { | ||
642 | struct i2c_client *client = to_i2c_client(dev); | ||
643 | struct pn544_info *info; | ||
644 | int r = 0; | ||
645 | |||
646 | dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client); | ||
647 | |||
648 | info = i2c_get_clientdata(client); | ||
649 | dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, | ||
650 | info, client); | ||
651 | |||
652 | mutex_lock(&info->mutex); | ||
653 | |||
654 | switch (info->state) { | ||
655 | case PN544_ST_FW_READY: | ||
656 | /* Do not suspend while upgrading FW, please! */ | ||
657 | r = -EPERM; | ||
658 | break; | ||
659 | |||
660 | case PN544_ST_READY: | ||
661 | /* | ||
662 | * CHECK: Device should be in standby-mode. No way to check? | ||
663 | * Allowing low power mode for the regulator is potentially | ||
664 | * dangerous if pn544 does not go to suspension. | ||
665 | */ | ||
666 | break; | ||
667 | |||
668 | case PN544_ST_COLD: | ||
669 | break; | ||
670 | }; | ||
671 | |||
672 | mutex_unlock(&info->mutex); | ||
673 | return r; | ||
674 | } | ||
675 | |||
676 | static int pn544_resume(struct device *dev) | ||
677 | { | ||
678 | struct i2c_client *client = to_i2c_client(dev); | ||
679 | struct pn544_info *info = i2c_get_clientdata(client); | ||
680 | int r = 0; | ||
681 | |||
682 | dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, | ||
683 | info, client); | ||
684 | |||
685 | mutex_lock(&info->mutex); | ||
686 | |||
687 | switch (info->state) { | ||
688 | case PN544_ST_READY: | ||
689 | /* | ||
690 | * CHECK: If regulator low power mode is allowed in | ||
691 | * pn544_suspend, we should go back to normal mode | ||
692 | * here. | ||
693 | */ | ||
694 | break; | ||
695 | |||
696 | case PN544_ST_COLD: | ||
697 | break; | ||
698 | |||
699 | case PN544_ST_FW_READY: | ||
700 | break; | ||
701 | }; | ||
702 | |||
703 | mutex_unlock(&info->mutex); | ||
704 | |||
705 | return r; | ||
706 | } | ||
707 | |||
708 | static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); | ||
709 | #endif | ||
710 | |||
711 | static struct device_attribute pn544_attr = | ||
712 | __ATTR(nfc_test, S_IRUGO, pn544_test, NULL); | ||
713 | |||
714 | static int __devinit pn544_probe(struct i2c_client *client, | ||
715 | const struct i2c_device_id *id) | ||
716 | { | ||
717 | struct pn544_info *info; | ||
718 | struct pn544_nfc_platform_data *pdata; | ||
719 | int r = 0; | ||
720 | |||
721 | dev_dbg(&client->dev, "%s\n", __func__); | ||
722 | dev_dbg(&client->dev, "IRQ: %d\n", client->irq); | ||
723 | |||
724 | /* private data allocation */ | ||
725 | info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL); | ||
726 | if (!info) { | ||
727 | dev_err(&client->dev, | ||
728 | "Cannot allocate memory for pn544_info.\n"); | ||
729 | r = -ENOMEM; | ||
730 | goto err_info_alloc; | ||
731 | } | ||
732 | |||
733 | info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER); | ||
734 | info->buf = kzalloc(info->buflen, GFP_KERNEL); | ||
735 | if (!info->buf) { | ||
736 | dev_err(&client->dev, | ||
737 | "Cannot allocate memory for pn544_info->buf.\n"); | ||
738 | r = -ENOMEM; | ||
739 | goto err_buf_alloc; | ||
740 | } | ||
741 | |||
742 | info->regs[0].supply = reg_vdd_io; | ||
743 | info->regs[1].supply = reg_vbat; | ||
744 | info->regs[2].supply = reg_vsim; | ||
745 | r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs), | ||
746 | info->regs); | ||
747 | if (r < 0) | ||
748 | goto err_kmalloc; | ||
749 | |||
750 | info->i2c_dev = client; | ||
751 | info->state = PN544_ST_COLD; | ||
752 | info->read_irq = PN544_NONE; | ||
753 | mutex_init(&info->read_mutex); | ||
754 | mutex_init(&info->mutex); | ||
755 | init_waitqueue_head(&info->read_wait); | ||
756 | i2c_set_clientdata(client, info); | ||
757 | pdata = client->dev.platform_data; | ||
758 | if (!pdata) { | ||
759 | dev_err(&client->dev, "No platform data\n"); | ||
760 | r = -EINVAL; | ||
761 | goto err_reg; | ||
762 | } | ||
763 | |||
764 | if (!pdata->request_resources) { | ||
765 | dev_err(&client->dev, "request_resources() missing\n"); | ||
766 | r = -EINVAL; | ||
767 | goto err_reg; | ||
768 | } | ||
769 | |||
770 | r = pdata->request_resources(client); | ||
771 | if (r) { | ||
772 | dev_err(&client->dev, "Cannot get platform resources\n"); | ||
773 | goto err_reg; | ||
774 | } | ||
775 | |||
776 | r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn, | ||
777 | IRQF_TRIGGER_RISING, PN544_DRIVER_NAME, | ||
778 | info); | ||
779 | if (r < 0) { | ||
780 | dev_err(&client->dev, "Unable to register IRQ handler\n"); | ||
781 | goto err_res; | ||
782 | } | ||
783 | |||
784 | /* If we don't have the test we don't need the sysfs file */ | ||
785 | if (pdata->test) { | ||
786 | r = device_create_file(&client->dev, &pn544_attr); | ||
787 | if (r) { | ||
788 | dev_err(&client->dev, | ||
789 | "sysfs registration failed, error %d\n", r); | ||
790 | goto err_irq; | ||
791 | } | ||
792 | } | ||
793 | |||
794 | info->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
795 | info->miscdev.name = PN544_DRIVER_NAME; | ||
796 | info->miscdev.fops = &pn544_fops; | ||
797 | info->miscdev.parent = &client->dev; | ||
798 | r = misc_register(&info->miscdev); | ||
799 | if (r < 0) { | ||
800 | dev_err(&client->dev, "Device registration failed\n"); | ||
801 | goto err_sysfs; | ||
802 | } | ||
803 | |||
804 | dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n", | ||
805 | __func__, info, pdata, client); | ||
806 | |||
807 | return 0; | ||
808 | |||
809 | err_sysfs: | ||
810 | if (pdata->test) | ||
811 | device_remove_file(&client->dev, &pn544_attr); | ||
812 | err_irq: | ||
813 | free_irq(client->irq, info); | ||
814 | err_res: | ||
815 | if (pdata->free_resources) | ||
816 | pdata->free_resources(); | ||
817 | err_reg: | ||
818 | regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); | ||
819 | err_kmalloc: | ||
820 | kfree(info->buf); | ||
821 | err_buf_alloc: | ||
822 | kfree(info); | ||
823 | err_info_alloc: | ||
824 | return r; | ||
825 | } | ||
826 | |||
827 | static __devexit int pn544_remove(struct i2c_client *client) | ||
828 | { | ||
829 | struct pn544_info *info = i2c_get_clientdata(client); | ||
830 | struct pn544_nfc_platform_data *pdata = client->dev.platform_data; | ||
831 | |||
832 | dev_dbg(&client->dev, "%s\n", __func__); | ||
833 | |||
834 | misc_deregister(&info->miscdev); | ||
835 | if (pdata->test) | ||
836 | device_remove_file(&client->dev, &pn544_attr); | ||
837 | |||
838 | if (info->state != PN544_ST_COLD) { | ||
839 | if (pdata->disable) | ||
840 | pdata->disable(); | ||
841 | |||
842 | info->read_irq = PN544_NONE; | ||
843 | } | ||
844 | |||
845 | free_irq(client->irq, info); | ||
846 | if (pdata->free_resources) | ||
847 | pdata->free_resources(); | ||
848 | |||
849 | regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); | ||
850 | kfree(info->buf); | ||
851 | kfree(info); | ||
852 | |||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | static struct i2c_driver pn544_driver = { | ||
857 | .driver = { | ||
858 | .name = PN544_DRIVER_NAME, | ||
859 | #ifdef CONFIG_PM | ||
860 | .pm = &pn544_pm_ops, | ||
861 | #endif | ||
862 | }, | ||
863 | .probe = pn544_probe, | ||
864 | .id_table = pn544_id_table, | ||
865 | .remove = __devexit_p(pn544_remove), | ||
866 | }; | ||
867 | |||
868 | static int __init pn544_init(void) | ||
869 | { | ||
870 | int r; | ||
871 | |||
872 | pr_debug(DRIVER_DESC ": %s\n", __func__); | ||
873 | |||
874 | r = i2c_add_driver(&pn544_driver); | ||
875 | if (r) { | ||
876 | pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); | ||
877 | return r; | ||
878 | } | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static void __exit pn544_exit(void) | ||
884 | { | ||
885 | i2c_del_driver(&pn544_driver); | ||
886 | pr_info(DRIVER_DESC ", Exiting.\n"); | ||
887 | } | ||
888 | |||
889 | module_init(pn544_init); | ||
890 | module_exit(pn544_exit); | ||
891 | |||
892 | MODULE_LICENSE("GPL"); | ||
893 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index aa71807189ba..c9c8570273ab 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | #include <linux/nfc.h> | 30 | #include <linux/nfc.h> |
31 | #include <net/nfc/hci.h> | 31 | #include <net/nfc/hci.h> |
32 | #include <net/nfc/shdlc.h> | 32 | #include <net/nfc/llc.h> |
33 | 33 | ||
34 | #include <linux/nfc/pn544.h> | 34 | #include <linux/nfc/pn544.h> |
35 | 35 | ||
@@ -128,10 +128,12 @@ static struct nfc_hci_gate pn544_gates[] = { | |||
128 | 128 | ||
129 | /* Largest headroom needed for outgoing custom commands */ | 129 | /* Largest headroom needed for outgoing custom commands */ |
130 | #define PN544_CMDS_HEADROOM 2 | 130 | #define PN544_CMDS_HEADROOM 2 |
131 | #define PN544_FRAME_HEADROOM 1 | ||
132 | #define PN544_FRAME_TAILROOM 2 | ||
131 | 133 | ||
132 | struct pn544_hci_info { | 134 | struct pn544_hci_info { |
133 | struct i2c_client *i2c_dev; | 135 | struct i2c_client *i2c_dev; |
134 | struct nfc_shdlc *shdlc; | 136 | struct nfc_hci_dev *hdev; |
135 | 137 | ||
136 | enum pn544_state state; | 138 | enum pn544_state state; |
137 | 139 | ||
@@ -146,6 +148,9 @@ struct pn544_hci_info { | |||
146 | * < 0 if hardware error occured (e.g. i2c err) | 148 | * < 0 if hardware error occured (e.g. i2c err) |
147 | * and prevents normal operation. | 149 | * and prevents normal operation. |
148 | */ | 150 | */ |
151 | int async_cb_type; | ||
152 | data_exchange_cb_t async_cb; | ||
153 | void *async_cb_context; | ||
149 | }; | 154 | }; |
150 | 155 | ||
151 | static void pn544_hci_platform_init(struct pn544_hci_info *info) | 156 | static void pn544_hci_platform_init(struct pn544_hci_info *info) |
@@ -230,8 +235,12 @@ static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) | |||
230 | r = i2c_master_send(client, buf, len); | 235 | r = i2c_master_send(client, buf, len); |
231 | } | 236 | } |
232 | 237 | ||
233 | if (r >= 0 && r != len) | 238 | if (r >= 0) { |
234 | r = -EREMOTEIO; | 239 | if (r != len) |
240 | return -EREMOTEIO; | ||
241 | else | ||
242 | return 0; | ||
243 | } | ||
235 | 244 | ||
236 | return r; | 245 | return r; |
237 | } | 246 | } |
@@ -341,13 +350,16 @@ flush: | |||
341 | static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) | 350 | static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) |
342 | { | 351 | { |
343 | struct pn544_hci_info *info = dev_id; | 352 | struct pn544_hci_info *info = dev_id; |
344 | struct i2c_client *client = info->i2c_dev; | 353 | struct i2c_client *client; |
345 | struct sk_buff *skb = NULL; | 354 | struct sk_buff *skb = NULL; |
346 | int r; | 355 | int r; |
347 | 356 | ||
348 | BUG_ON(!info); | 357 | if (!info || irq != info->i2c_dev->irq) { |
349 | BUG_ON(irq != info->i2c_dev->irq); | 358 | WARN_ON_ONCE(1); |
359 | return IRQ_NONE; | ||
360 | } | ||
350 | 361 | ||
362 | client = info->i2c_dev; | ||
351 | dev_dbg(&client->dev, "IRQ\n"); | 363 | dev_dbg(&client->dev, "IRQ\n"); |
352 | 364 | ||
353 | if (info->hard_fault != 0) | 365 | if (info->hard_fault != 0) |
@@ -357,21 +369,21 @@ static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) | |||
357 | if (r == -EREMOTEIO) { | 369 | if (r == -EREMOTEIO) { |
358 | info->hard_fault = r; | 370 | info->hard_fault = r; |
359 | 371 | ||
360 | nfc_shdlc_recv_frame(info->shdlc, NULL); | 372 | nfc_hci_recv_frame(info->hdev, NULL); |
361 | 373 | ||
362 | return IRQ_HANDLED; | 374 | return IRQ_HANDLED; |
363 | } else if ((r == -ENOMEM) || (r == -EBADMSG)) { | 375 | } else if ((r == -ENOMEM) || (r == -EBADMSG)) { |
364 | return IRQ_HANDLED; | 376 | return IRQ_HANDLED; |
365 | } | 377 | } |
366 | 378 | ||
367 | nfc_shdlc_recv_frame(info->shdlc, skb); | 379 | nfc_hci_recv_frame(info->hdev, skb); |
368 | 380 | ||
369 | return IRQ_HANDLED; | 381 | return IRQ_HANDLED; |
370 | } | 382 | } |
371 | 383 | ||
372 | static int pn544_hci_open(struct nfc_shdlc *shdlc) | 384 | static int pn544_hci_open(struct nfc_hci_dev *hdev) |
373 | { | 385 | { |
374 | struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); | 386 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
375 | int r = 0; | 387 | int r = 0; |
376 | 388 | ||
377 | mutex_lock(&info->info_lock); | 389 | mutex_lock(&info->info_lock); |
@@ -391,9 +403,9 @@ out: | |||
391 | return r; | 403 | return r; |
392 | } | 404 | } |
393 | 405 | ||
394 | static void pn544_hci_close(struct nfc_shdlc *shdlc) | 406 | static void pn544_hci_close(struct nfc_hci_dev *hdev) |
395 | { | 407 | { |
396 | struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); | 408 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
397 | 409 | ||
398 | mutex_lock(&info->info_lock); | 410 | mutex_lock(&info->info_lock); |
399 | 411 | ||
@@ -408,9 +420,8 @@ out: | |||
408 | mutex_unlock(&info->info_lock); | 420 | mutex_unlock(&info->info_lock); |
409 | } | 421 | } |
410 | 422 | ||
411 | static int pn544_hci_ready(struct nfc_shdlc *shdlc) | 423 | static int pn544_hci_ready(struct nfc_hci_dev *hdev) |
412 | { | 424 | { |
413 | struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); | ||
414 | struct sk_buff *skb; | 425 | struct sk_buff *skb; |
415 | static struct hw_config { | 426 | static struct hw_config { |
416 | u8 adr[2]; | 427 | u8 adr[2]; |
@@ -576,21 +587,45 @@ static int pn544_hci_ready(struct nfc_shdlc *shdlc) | |||
576 | return 0; | 587 | return 0; |
577 | } | 588 | } |
578 | 589 | ||
579 | static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) | 590 | static void pn544_hci_add_len_crc(struct sk_buff *skb) |
580 | { | 591 | { |
581 | struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); | 592 | u16 crc; |
593 | int len; | ||
594 | |||
595 | len = skb->len + 2; | ||
596 | *skb_push(skb, 1) = len; | ||
597 | |||
598 | crc = crc_ccitt(0xffff, skb->data, skb->len); | ||
599 | crc = ~crc; | ||
600 | *skb_put(skb, 1) = crc & 0xff; | ||
601 | *skb_put(skb, 1) = crc >> 8; | ||
602 | } | ||
603 | |||
604 | static void pn544_hci_remove_len_crc(struct sk_buff *skb) | ||
605 | { | ||
606 | skb_pull(skb, PN544_FRAME_HEADROOM); | ||
607 | skb_trim(skb, PN544_FRAME_TAILROOM); | ||
608 | } | ||
609 | |||
610 | static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
611 | { | ||
612 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); | ||
582 | struct i2c_client *client = info->i2c_dev; | 613 | struct i2c_client *client = info->i2c_dev; |
614 | int r; | ||
583 | 615 | ||
584 | if (info->hard_fault != 0) | 616 | if (info->hard_fault != 0) |
585 | return info->hard_fault; | 617 | return info->hard_fault; |
586 | 618 | ||
587 | return pn544_hci_i2c_write(client, skb->data, skb->len); | 619 | pn544_hci_add_len_crc(skb); |
620 | r = pn544_hci_i2c_write(client, skb->data, skb->len); | ||
621 | pn544_hci_remove_len_crc(skb); | ||
622 | |||
623 | return r; | ||
588 | } | 624 | } |
589 | 625 | ||
590 | static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, | 626 | static int pn544_hci_start_poll(struct nfc_hci_dev *hdev, |
591 | u32 im_protocols, u32 tm_protocols) | 627 | u32 im_protocols, u32 tm_protocols) |
592 | { | 628 | { |
593 | struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); | ||
594 | u8 phases = 0; | 629 | u8 phases = 0; |
595 | int r; | 630 | int r; |
596 | u8 duration[2]; | 631 | u8 duration[2]; |
@@ -641,7 +676,7 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, | |||
641 | return r; | 676 | return r; |
642 | } | 677 | } |
643 | 678 | ||
644 | static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, | 679 | static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, |
645 | struct nfc_target *target) | 680 | struct nfc_target *target) |
646 | { | 681 | { |
647 | switch (gate) { | 682 | switch (gate) { |
@@ -659,11 +694,10 @@ static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, | |||
659 | return 0; | 694 | return 0; |
660 | } | 695 | } |
661 | 696 | ||
662 | static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, | 697 | static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev, |
663 | u8 gate, | 698 | u8 gate, |
664 | struct nfc_target *target) | 699 | struct nfc_target *target) |
665 | { | 700 | { |
666 | struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); | ||
667 | struct sk_buff *uid_skb; | 701 | struct sk_buff *uid_skb; |
668 | int r = 0; | 702 | int r = 0; |
669 | 703 | ||
@@ -704,6 +738,26 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, | |||
704 | return r; | 738 | return r; |
705 | } | 739 | } |
706 | 740 | ||
741 | #define PN544_CB_TYPE_READER_F 1 | ||
742 | |||
743 | static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb, | ||
744 | int err) | ||
745 | { | ||
746 | struct pn544_hci_info *info = context; | ||
747 | |||
748 | switch (info->async_cb_type) { | ||
749 | case PN544_CB_TYPE_READER_F: | ||
750 | if (err == 0) | ||
751 | skb_pull(skb, 1); | ||
752 | info->async_cb(info->async_cb_context, skb, err); | ||
753 | break; | ||
754 | default: | ||
755 | if (err == 0) | ||
756 | kfree_skb(skb); | ||
757 | break; | ||
758 | } | ||
759 | } | ||
760 | |||
707 | #define MIFARE_CMD_AUTH_KEY_A 0x60 | 761 | #define MIFARE_CMD_AUTH_KEY_A 0x60 |
708 | #define MIFARE_CMD_AUTH_KEY_B 0x61 | 762 | #define MIFARE_CMD_AUTH_KEY_B 0x61 |
709 | #define MIFARE_CMD_HEADER 2 | 763 | #define MIFARE_CMD_HEADER 2 |
@@ -715,13 +769,12 @@ static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, | |||
715 | * <= 0: driver handled the data exchange | 769 | * <= 0: driver handled the data exchange |
716 | * 1: driver doesn't especially handle, please do standard processing | 770 | * 1: driver doesn't especially handle, please do standard processing |
717 | */ | 771 | */ |
718 | static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, | 772 | static int pn544_hci_data_exchange(struct nfc_hci_dev *hdev, |
719 | struct nfc_target *target, | 773 | struct nfc_target *target, |
720 | struct sk_buff *skb, | 774 | struct sk_buff *skb, data_exchange_cb_t cb, |
721 | struct sk_buff **res_skb) | 775 | void *cb_context) |
722 | { | 776 | { |
723 | struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); | 777 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
724 | int r; | ||
725 | 778 | ||
726 | pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, | 779 | pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, |
727 | target->hci_reader_gate); | 780 | target->hci_reader_gate); |
@@ -746,41 +799,43 @@ static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, | |||
746 | memcpy(data, uid, MIFARE_UID_LEN); | 799 | memcpy(data, uid, MIFARE_UID_LEN); |
747 | } | 800 | } |
748 | 801 | ||
749 | return nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 802 | return nfc_hci_send_cmd_async(hdev, |
750 | PN544_MIFARE_CMD, | 803 | target->hci_reader_gate, |
751 | skb->data, skb->len, res_skb); | 804 | PN544_MIFARE_CMD, |
805 | skb->data, skb->len, | ||
806 | cb, cb_context); | ||
752 | } else | 807 | } else |
753 | return 1; | 808 | return 1; |
754 | case PN544_RF_READER_F_GATE: | 809 | case PN544_RF_READER_F_GATE: |
755 | *skb_push(skb, 1) = 0; | 810 | *skb_push(skb, 1) = 0; |
756 | *skb_push(skb, 1) = 0; | 811 | *skb_push(skb, 1) = 0; |
757 | 812 | ||
758 | r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 813 | info->async_cb_type = PN544_CB_TYPE_READER_F; |
759 | PN544_FELICA_RAW, | 814 | info->async_cb = cb; |
760 | skb->data, skb->len, res_skb); | 815 | info->async_cb_context = cb_context; |
761 | if (r == 0) | 816 | |
762 | skb_pull(*res_skb, 1); | 817 | return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
763 | return r; | 818 | PN544_FELICA_RAW, skb->data, |
819 | skb->len, | ||
820 | pn544_hci_data_exchange_cb, info); | ||
764 | case PN544_RF_READER_JEWEL_GATE: | 821 | case PN544_RF_READER_JEWEL_GATE: |
765 | return nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 822 | return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
766 | PN544_JEWEL_RAW_CMD, | 823 | PN544_JEWEL_RAW_CMD, skb->data, |
767 | skb->data, skb->len, res_skb); | 824 | skb->len, cb, cb_context); |
768 | default: | 825 | default: |
769 | return 1; | 826 | return 1; |
770 | } | 827 | } |
771 | } | 828 | } |
772 | 829 | ||
773 | static int pn544_hci_check_presence(struct nfc_shdlc *shdlc, | 830 | static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, |
774 | struct nfc_target *target) | 831 | struct nfc_target *target) |
775 | { | 832 | { |
776 | struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); | ||
777 | |||
778 | return nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 833 | return nfc_hci_send_cmd(hdev, target->hci_reader_gate, |
779 | PN544_RF_READER_CMD_PRESENCE_CHECK, | 834 | PN544_RF_READER_CMD_PRESENCE_CHECK, |
780 | NULL, 0, NULL); | 835 | NULL, 0, NULL); |
781 | } | 836 | } |
782 | 837 | ||
783 | static struct nfc_shdlc_ops pn544_shdlc_ops = { | 838 | static struct nfc_hci_ops pn544_hci_ops = { |
784 | .open = pn544_hci_open, | 839 | .open = pn544_hci_open, |
785 | .close = pn544_hci_close, | 840 | .close = pn544_hci_close, |
786 | .hci_ready = pn544_hci_ready, | 841 | .hci_ready = pn544_hci_ready, |
@@ -848,8 +903,8 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, | |||
848 | pn544_hci_platform_init(info); | 903 | pn544_hci_platform_init(info); |
849 | 904 | ||
850 | r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, | 905 | r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, |
851 | IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME, | 906 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
852 | info); | 907 | PN544_HCI_DRIVER_NAME, info); |
853 | if (r < 0) { | 908 | if (r < 0) { |
854 | dev_err(&client->dev, "Unable to register IRQ handler\n"); | 909 | dev_err(&client->dev, "Unable to register IRQ handler\n"); |
855 | goto err_rti; | 910 | goto err_rti; |
@@ -872,22 +927,30 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, | |||
872 | NFC_PROTO_ISO14443_B_MASK | | 927 | NFC_PROTO_ISO14443_B_MASK | |
873 | NFC_PROTO_NFC_DEP_MASK; | 928 | NFC_PROTO_NFC_DEP_MASK; |
874 | 929 | ||
875 | info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, | 930 | info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, |
876 | &init_data, protocols, | 931 | protocols, LLC_SHDLC_NAME, |
877 | PN544_CMDS_HEADROOM, 0, | 932 | PN544_FRAME_HEADROOM + |
878 | PN544_HCI_LLC_MAX_PAYLOAD, | 933 | PN544_CMDS_HEADROOM, |
879 | dev_name(&client->dev)); | 934 | PN544_FRAME_TAILROOM, |
880 | if (!info->shdlc) { | 935 | PN544_HCI_LLC_MAX_PAYLOAD); |
881 | dev_err(&client->dev, "Cannot allocate nfc shdlc.\n"); | 936 | if (!info->hdev) { |
937 | dev_err(&client->dev, "Cannot allocate nfc hdev.\n"); | ||
882 | r = -ENOMEM; | 938 | r = -ENOMEM; |
883 | goto err_allocshdlc; | 939 | goto err_alloc_hdev; |
884 | } | 940 | } |
885 | 941 | ||
886 | nfc_shdlc_set_clientdata(info->shdlc, info); | 942 | nfc_hci_set_clientdata(info->hdev, info); |
943 | |||
944 | r = nfc_hci_register_device(info->hdev); | ||
945 | if (r) | ||
946 | goto err_regdev; | ||
887 | 947 | ||
888 | return 0; | 948 | return 0; |
889 | 949 | ||
890 | err_allocshdlc: | 950 | err_regdev: |
951 | nfc_hci_free_device(info->hdev); | ||
952 | |||
953 | err_alloc_hdev: | ||
891 | free_irq(client->irq, info); | 954 | free_irq(client->irq, info); |
892 | 955 | ||
893 | err_rti: | 956 | err_rti: |
@@ -908,7 +971,7 @@ static __devexit int pn544_hci_remove(struct i2c_client *client) | |||
908 | 971 | ||
909 | dev_dbg(&client->dev, "%s\n", __func__); | 972 | dev_dbg(&client->dev, "%s\n", __func__); |
910 | 973 | ||
911 | nfc_shdlc_free(info->shdlc); | 974 | nfc_hci_free_device(info->hdev); |
912 | 975 | ||
913 | if (info->state != PN544_ST_COLD) { | 976 | if (info->state != PN544_ST_COLD) { |
914 | if (pdata->disable) | 977 | if (pdata->disable) |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e02fc682bb68..2385119f8bb0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1935,36 +1935,6 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr, | |||
1935 | } | 1935 | } |
1936 | 1936 | ||
1937 | /** | 1937 | /** |
1938 | * ieee80211_fhss_chan_to_freq - get channel frequency | ||
1939 | * @channel: the FHSS channel | ||
1940 | * | ||
1941 | * Convert IEEE802.11 FHSS channel to frequency (MHz) | ||
1942 | * Ref IEEE 802.11-2007 section 14.6 | ||
1943 | */ | ||
1944 | static inline int ieee80211_fhss_chan_to_freq(int channel) | ||
1945 | { | ||
1946 | if ((channel > 1) && (channel < 96)) | ||
1947 | return channel + 2400; | ||
1948 | else | ||
1949 | return -1; | ||
1950 | } | ||
1951 | |||
1952 | /** | ||
1953 | * ieee80211_freq_to_fhss_chan - get channel | ||
1954 | * @freq: the channels frequency | ||
1955 | * | ||
1956 | * Convert frequency (MHz) to IEEE802.11 FHSS channel | ||
1957 | * Ref IEEE 802.11-2007 section 14.6 | ||
1958 | */ | ||
1959 | static inline int ieee80211_freq_to_fhss_chan(int freq) | ||
1960 | { | ||
1961 | if ((freq > 2401) && (freq < 2496)) | ||
1962 | return freq - 2400; | ||
1963 | else | ||
1964 | return -1; | ||
1965 | } | ||
1966 | |||
1967 | /** | ||
1968 | * ieee80211_dsss_chan_to_freq - get channel center frequency | 1938 | * ieee80211_dsss_chan_to_freq - get channel center frequency |
1969 | * @channel: the DSSS channel | 1939 | * @channel: the DSSS channel |
1970 | * | 1940 | * |
@@ -2000,56 +1970,6 @@ static inline int ieee80211_freq_to_dsss_chan(int freq) | |||
2000 | return -1; | 1970 | return -1; |
2001 | } | 1971 | } |
2002 | 1972 | ||
2003 | /* Convert IEEE802.11 HR DSSS channel to frequency (MHz) and back | ||
2004 | * Ref IEEE 802.11-2007 section 18.4.6.2 | ||
2005 | * | ||
2006 | * The channels and frequencies are the same as those defined for DSSS | ||
2007 | */ | ||
2008 | #define ieee80211_hr_chan_to_freq(chan) ieee80211_dsss_chan_to_freq(chan) | ||
2009 | #define ieee80211_freq_to_hr_chan(freq) ieee80211_freq_to_dsss_chan(freq) | ||
2010 | |||
2011 | /* Convert IEEE802.11 ERP channel to frequency (MHz) and back | ||
2012 | * Ref IEEE 802.11-2007 section 19.4.2 | ||
2013 | */ | ||
2014 | #define ieee80211_erp_chan_to_freq(chan) ieee80211_hr_chan_to_freq(chan) | ||
2015 | #define ieee80211_freq_to_erp_chan(freq) ieee80211_freq_to_hr_chan(freq) | ||
2016 | |||
2017 | /** | ||
2018 | * ieee80211_ofdm_chan_to_freq - get channel center frequency | ||
2019 | * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz | ||
2020 | * @channel: the OFDM channel | ||
2021 | * | ||
2022 | * Convert IEEE802.11 OFDM channel to center frequency (MHz) | ||
2023 | * Ref IEEE 802.11-2007 section 17.3.8.3.2 | ||
2024 | */ | ||
2025 | static inline int ieee80211_ofdm_chan_to_freq(int s_freq, int channel) | ||
2026 | { | ||
2027 | if ((channel > 0) && (channel <= 200) && | ||
2028 | (s_freq >= 4000)) | ||
2029 | return s_freq + (channel * 5); | ||
2030 | else | ||
2031 | return -1; | ||
2032 | } | ||
2033 | |||
2034 | /** | ||
2035 | * ieee80211_freq_to_ofdm_channel - get channel | ||
2036 | * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz | ||
2037 | * @freq: the frequency | ||
2038 | * | ||
2039 | * Convert frequency (MHz) to IEEE802.11 OFDM channel | ||
2040 | * Ref IEEE 802.11-2007 section 17.3.8.3.2 | ||
2041 | * | ||
2042 | * This routine selects the channel with the closest center frequency. | ||
2043 | */ | ||
2044 | static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq) | ||
2045 | { | ||
2046 | if ((freq > (s_freq + 2)) && (freq <= (s_freq + 1202)) && | ||
2047 | (s_freq >= 4000)) | ||
2048 | return (freq + 2 - s_freq) / 5; | ||
2049 | else | ||
2050 | return -1; | ||
2051 | } | ||
2052 | |||
2053 | /** | 1973 | /** |
2054 | * ieee80211_tu_to_usec - convert time units (TU) to microseconds | 1974 | * ieee80211_tu_to_usec - convert time units (TU) to microseconds |
2055 | * @tu: the TUs | 1975 | * @tu: the TUs |
diff --git a/include/linux/nfc.h b/include/linux/nfc.h index 6189f27e305b..d908d17da56d 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h | |||
@@ -183,4 +183,15 @@ struct sockaddr_nfc_llcp { | |||
183 | 183 | ||
184 | #define NFC_HEADER_SIZE 1 | 184 | #define NFC_HEADER_SIZE 1 |
185 | 185 | ||
186 | /** | ||
187 | * Pseudo-header info for raw socket packets | ||
188 | * First byte is the adapter index | ||
189 | * Second byte contains flags | ||
190 | * - 0x01 - Direction (0=RX, 1=TX) | ||
191 | * - 0x02-0x80 - Reserved | ||
192 | **/ | ||
193 | #define NFC_LLCP_RAW_HEADER_SIZE 2 | ||
194 | #define NFC_LLCP_DIRECTION_RX 0x00 | ||
195 | #define NFC_LLCP_DIRECTION_TX 0x01 | ||
196 | |||
186 | #endif /*__LINUX_NFC_H */ | 197 | #endif /*__LINUX_NFC_H */ |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 458416279347..7df9b500c804 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -573,6 +573,11 @@ | |||
573 | * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by | 573 | * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by |
574 | * its %NL80211_ATTR_WDEV identifier. | 574 | * its %NL80211_ATTR_WDEV identifier. |
575 | * | 575 | * |
576 | * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to | ||
577 | * notify userspace that AP has rejected the connection request from a | ||
578 | * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON | ||
579 | * is used for this. | ||
580 | * | ||
576 | * @NL80211_CMD_MAX: highest used command number | 581 | * @NL80211_CMD_MAX: highest used command number |
577 | * @__NL80211_CMD_AFTER_LAST: internal use | 582 | * @__NL80211_CMD_AFTER_LAST: internal use |
578 | */ | 583 | */ |
@@ -719,6 +724,8 @@ enum nl80211_commands { | |||
719 | NL80211_CMD_START_P2P_DEVICE, | 724 | NL80211_CMD_START_P2P_DEVICE, |
720 | NL80211_CMD_STOP_P2P_DEVICE, | 725 | NL80211_CMD_STOP_P2P_DEVICE, |
721 | 726 | ||
727 | NL80211_CMD_CONN_FAILED, | ||
728 | |||
722 | /* add new commands above here */ | 729 | /* add new commands above here */ |
723 | 730 | ||
724 | /* used to define NL80211_CMD_MAX below */ | 731 | /* used to define NL80211_CMD_MAX below */ |
@@ -1262,6 +1269,10 @@ enum nl80211_commands { | |||
1262 | * was used to provide the hint. For the different types of | 1269 | * was used to provide the hint. For the different types of |
1263 | * allowed user regulatory hints see nl80211_user_reg_hint_type. | 1270 | * allowed user regulatory hints see nl80211_user_reg_hint_type. |
1264 | * | 1271 | * |
1272 | * @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected | ||
1273 | * the connection request from a station. nl80211_connect_failed_reason | ||
1274 | * enum has different reasons of connection failure. | ||
1275 | * | ||
1265 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1276 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1266 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1277 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1267 | */ | 1278 | */ |
@@ -1517,6 +1528,8 @@ enum nl80211_attrs { | |||
1517 | 1528 | ||
1518 | NL80211_ATTR_USER_REG_HINT_TYPE, | 1529 | NL80211_ATTR_USER_REG_HINT_TYPE, |
1519 | 1530 | ||
1531 | NL80211_ATTR_CONN_FAILED_REASON, | ||
1532 | |||
1520 | /* add attributes here, update the policy in nl80211.c */ | 1533 | /* add attributes here, update the policy in nl80211.c */ |
1521 | 1534 | ||
1522 | __NL80211_ATTR_AFTER_LAST, | 1535 | __NL80211_ATTR_AFTER_LAST, |
@@ -3045,4 +3058,15 @@ enum nl80211_probe_resp_offload_support_attr { | |||
3045 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3, | 3058 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3, |
3046 | }; | 3059 | }; |
3047 | 3060 | ||
3061 | /** | ||
3062 | * enum nl80211_connect_failed_reason - connection request failed reasons | ||
3063 | * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be | ||
3064 | * handled by the AP is reached. | ||
3065 | * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist. | ||
3066 | */ | ||
3067 | enum nl80211_connect_failed_reason { | ||
3068 | NL80211_CONN_FAIL_MAX_CLIENTS, | ||
3069 | NL80211_CONN_FAIL_BLOCKED_CLIENT, | ||
3070 | }; | ||
3071 | |||
3048 | #endif /* __LINUX_NL80211_H */ | 3072 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 23cf413e2acf..76b2b6bdcf36 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h | |||
@@ -302,8 +302,11 @@ enum { | |||
302 | 302 | ||
303 | /* ---- HCI Error Codes ---- */ | 303 | /* ---- HCI Error Codes ---- */ |
304 | #define HCI_ERROR_AUTH_FAILURE 0x05 | 304 | #define HCI_ERROR_AUTH_FAILURE 0x05 |
305 | #define HCI_ERROR_CONNECTION_TIMEOUT 0x08 | ||
305 | #define HCI_ERROR_REJ_BAD_ADDR 0x0f | 306 | #define HCI_ERROR_REJ_BAD_ADDR 0x0f |
306 | #define HCI_ERROR_REMOTE_USER_TERM 0x13 | 307 | #define HCI_ERROR_REMOTE_USER_TERM 0x13 |
308 | #define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14 | ||
309 | #define HCI_ERROR_REMOTE_POWER_OFF 0x15 | ||
307 | #define HCI_ERROR_LOCAL_HOST_TERM 0x16 | 310 | #define HCI_ERROR_LOCAL_HOST_TERM 0x16 |
308 | #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 | 311 | #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 |
309 | 312 | ||
@@ -1246,6 +1249,24 @@ struct hci_ev_simple_pair_complete { | |||
1246 | bdaddr_t bdaddr; | 1249 | bdaddr_t bdaddr; |
1247 | } __packed; | 1250 | } __packed; |
1248 | 1251 | ||
1252 | #define HCI_EV_USER_PASSKEY_NOTIFY 0x3b | ||
1253 | struct hci_ev_user_passkey_notify { | ||
1254 | bdaddr_t bdaddr; | ||
1255 | __le32 passkey; | ||
1256 | } __packed; | ||
1257 | |||
1258 | #define HCI_KEYPRESS_STARTED 0 | ||
1259 | #define HCI_KEYPRESS_ENTERED 1 | ||
1260 | #define HCI_KEYPRESS_ERASED 2 | ||
1261 | #define HCI_KEYPRESS_CLEARED 3 | ||
1262 | #define HCI_KEYPRESS_COMPLETED 4 | ||
1263 | |||
1264 | #define HCI_EV_KEYPRESS_NOTIFY 0x3c | ||
1265 | struct hci_ev_keypress_notify { | ||
1266 | bdaddr_t bdaddr; | ||
1267 | __u8 type; | ||
1268 | } __packed; | ||
1269 | |||
1249 | #define HCI_EV_REMOTE_HOST_FEATURES 0x3d | 1270 | #define HCI_EV_REMOTE_HOST_FEATURES 0x3d |
1250 | struct hci_ev_remote_host_features { | 1271 | struct hci_ev_remote_host_features { |
1251 | bdaddr_t bdaddr; | 1272 | bdaddr_t bdaddr; |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 41d943926d2c..e7d454609881 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -303,6 +303,8 @@ struct hci_conn { | |||
303 | __u8 pin_length; | 303 | __u8 pin_length; |
304 | __u8 enc_key_size; | 304 | __u8 enc_key_size; |
305 | __u8 io_capability; | 305 | __u8 io_capability; |
306 | __u32 passkey_notify; | ||
307 | __u8 passkey_entered; | ||
306 | __u16 disc_timeout; | 308 | __u16 disc_timeout; |
307 | unsigned long flags; | 309 | unsigned long flags; |
308 | 310 | ||
@@ -428,15 +430,6 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) | |||
428 | test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); | 430 | test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); |
429 | } | 431 | } |
430 | 432 | ||
431 | static inline void hci_conn_hash_init(struct hci_dev *hdev) | ||
432 | { | ||
433 | struct hci_conn_hash *h = &hdev->conn_hash; | ||
434 | INIT_LIST_HEAD(&h->list); | ||
435 | h->acl_num = 0; | ||
436 | h->sco_num = 0; | ||
437 | h->le_num = 0; | ||
438 | } | ||
439 | |||
440 | static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) | 433 | static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) |
441 | { | 434 | { |
442 | struct hci_conn_hash *h = &hdev->conn_hash; | 435 | struct hci_conn_hash *h = &hdev->conn_hash; |
@@ -551,9 +544,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, | |||
551 | return NULL; | 544 | return NULL; |
552 | } | 545 | } |
553 | 546 | ||
554 | void hci_acl_connect(struct hci_conn *conn); | ||
555 | void hci_acl_disconn(struct hci_conn *conn, __u8 reason); | 547 | void hci_acl_disconn(struct hci_conn *conn, __u8 reason); |
556 | void hci_add_sco(struct hci_conn *conn, __u16 handle); | ||
557 | void hci_setup_sync(struct hci_conn *conn, __u16 handle); | 548 | void hci_setup_sync(struct hci_conn *conn, __u16 handle); |
558 | void hci_sco_setup(struct hci_conn *conn, __u8 status); | 549 | void hci_sco_setup(struct hci_conn *conn, __u8 status); |
559 | 550 | ||
@@ -563,7 +554,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev); | |||
563 | void hci_conn_check_pending(struct hci_dev *hdev); | 554 | void hci_conn_check_pending(struct hci_dev *hdev); |
564 | 555 | ||
565 | struct hci_chan *hci_chan_create(struct hci_conn *conn); | 556 | struct hci_chan *hci_chan_create(struct hci_conn *conn); |
566 | int hci_chan_del(struct hci_chan *chan); | 557 | void hci_chan_del(struct hci_chan *chan); |
567 | void hci_chan_list_flush(struct hci_conn *conn); | 558 | void hci_chan_list_flush(struct hci_conn *conn); |
568 | 559 | ||
569 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | 560 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, |
@@ -614,11 +605,17 @@ static inline void hci_conn_put(struct hci_conn *conn) | |||
614 | /* ----- HCI Devices ----- */ | 605 | /* ----- HCI Devices ----- */ |
615 | static inline void hci_dev_put(struct hci_dev *d) | 606 | static inline void hci_dev_put(struct hci_dev *d) |
616 | { | 607 | { |
608 | BT_DBG("%s orig refcnt %d", d->name, | ||
609 | atomic_read(&d->dev.kobj.kref.refcount)); | ||
610 | |||
617 | put_device(&d->dev); | 611 | put_device(&d->dev); |
618 | } | 612 | } |
619 | 613 | ||
620 | static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) | 614 | static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) |
621 | { | 615 | { |
616 | BT_DBG("%s orig refcnt %d", d->name, | ||
617 | atomic_read(&d->dev.kobj.kref.refcount)); | ||
618 | |||
622 | get_device(&d->dev); | 619 | get_device(&d->dev); |
623 | return d; | 620 | return d; |
624 | } | 621 | } |
@@ -1004,7 +1001,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
1004 | u8 addr_type, u32 flags, u8 *name, u8 name_len, | 1001 | u8 addr_type, u32 flags, u8 *name, u8 name_len, |
1005 | u8 *dev_class); | 1002 | u8 *dev_class); |
1006 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | 1003 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, |
1007 | u8 link_type, u8 addr_type); | 1004 | u8 link_type, u8 addr_type, u8 reason); |
1008 | int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, | 1005 | int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, |
1009 | u8 link_type, u8 addr_type, u8 status); | 1006 | u8 link_type, u8 addr_type, u8 status); |
1010 | int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 1007 | int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
@@ -1027,6 +1024,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
1027 | u8 link_type, u8 addr_type, u8 status); | 1024 | u8 link_type, u8 addr_type, u8 status); |
1028 | int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | 1025 | int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
1029 | u8 link_type, u8 addr_type, u8 status); | 1026 | u8 link_type, u8 addr_type, u8 status); |
1027 | int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||
1028 | u8 link_type, u8 addr_type, u32 passkey, | ||
1029 | u8 entered); | ||
1030 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 1030 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
1031 | u8 addr_type, u8 status); | 1031 | u8 addr_type, u8 status); |
1032 | int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); | 1032 | int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); |
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d206296137e2..7ed8e356425a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -433,11 +433,10 @@ struct l2cap_chan { | |||
433 | struct sock *sk; | 433 | struct sock *sk; |
434 | 434 | ||
435 | struct l2cap_conn *conn; | 435 | struct l2cap_conn *conn; |
436 | struct kref kref; | ||
436 | 437 | ||
437 | __u8 state; | 438 | __u8 state; |
438 | 439 | ||
439 | atomic_t refcnt; | ||
440 | |||
441 | __le16 psm; | 440 | __le16 psm; |
442 | __u16 dcid; | 441 | __u16 dcid; |
443 | __u16 scid; | 442 | __u16 scid; |
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4348ee8bda69..22980a7c3873 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h | |||
@@ -405,7 +405,16 @@ struct mgmt_ev_device_connected { | |||
405 | __u8 eir[0]; | 405 | __u8 eir[0]; |
406 | } __packed; | 406 | } __packed; |
407 | 407 | ||
408 | #define MGMT_DEV_DISCONN_UNKNOWN 0x00 | ||
409 | #define MGMT_DEV_DISCONN_TIMEOUT 0x01 | ||
410 | #define MGMT_DEV_DISCONN_LOCAL_HOST 0x02 | ||
411 | #define MGMT_DEV_DISCONN_REMOTE 0x03 | ||
412 | |||
408 | #define MGMT_EV_DEVICE_DISCONNECTED 0x000C | 413 | #define MGMT_EV_DEVICE_DISCONNECTED 0x000C |
414 | struct mgmt_ev_device_disconnected { | ||
415 | struct mgmt_addr_info addr; | ||
416 | __u8 reason; | ||
417 | } __packed; | ||
409 | 418 | ||
410 | #define MGMT_EV_CONNECT_FAILED 0x000D | 419 | #define MGMT_EV_CONNECT_FAILED 0x000D |
411 | struct mgmt_ev_connect_failed { | 420 | struct mgmt_ev_connect_failed { |
@@ -469,3 +478,10 @@ struct mgmt_ev_device_unblocked { | |||
469 | struct mgmt_ev_device_unpaired { | 478 | struct mgmt_ev_device_unpaired { |
470 | struct mgmt_addr_info addr; | 479 | struct mgmt_addr_info addr; |
471 | } __packed; | 480 | } __packed; |
481 | |||
482 | #define MGMT_EV_PASSKEY_NOTIFY 0x0017 | ||
483 | struct mgmt_ev_passkey_notify { | ||
484 | struct mgmt_addr_info addr; | ||
485 | __le32 passkey; | ||
486 | __u8 entered; | ||
487 | } __packed; | ||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a9a2be78e73c..1b4989082244 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1580,9 +1580,7 @@ struct cfg80211_gtk_rekey_data { | |||
1580 | * @set_cqm_txe_config: Configure connection quality monitor TX error | 1580 | * @set_cqm_txe_config: Configure connection quality monitor TX error |
1581 | * thresholds. | 1581 | * thresholds. |
1582 | * @sched_scan_start: Tell the driver to start a scheduled scan. | 1582 | * @sched_scan_start: Tell the driver to start a scheduled scan. |
1583 | * @sched_scan_stop: Tell the driver to stop an ongoing scheduled | 1583 | * @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan. |
1584 | * scan. The driver_initiated flag specifies whether the driver | ||
1585 | * itself has informed that the scan has stopped. | ||
1586 | * | 1584 | * |
1587 | * @mgmt_frame_register: Notify driver that a management frame type was | 1585 | * @mgmt_frame_register: Notify driver that a management frame type was |
1588 | * registered. Note that this callback may not sleep, and cannot run | 1586 | * registered. Note that this callback may not sleep, and cannot run |
@@ -1630,7 +1628,7 @@ struct cfg80211_ops { | |||
1630 | void (*set_wakeup)(struct wiphy *wiphy, bool enabled); | 1628 | void (*set_wakeup)(struct wiphy *wiphy, bool enabled); |
1631 | 1629 | ||
1632 | struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy, | 1630 | struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy, |
1633 | char *name, | 1631 | const char *name, |
1634 | enum nl80211_iftype type, | 1632 | enum nl80211_iftype type, |
1635 | u32 *flags, | 1633 | u32 *flags, |
1636 | struct vif_params *params); | 1634 | struct vif_params *params); |
@@ -3363,6 +3361,25 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
3363 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); | 3361 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); |
3364 | 3362 | ||
3365 | /** | 3363 | /** |
3364 | * cfg80211_conn_failed - connection request failed notification | ||
3365 | * | ||
3366 | * @dev: the netdev | ||
3367 | * @mac_addr: the station's address | ||
3368 | * @reason: the reason for connection failure | ||
3369 | * @gfp: allocation flags | ||
3370 | * | ||
3371 | * Whenever a station tries to connect to an AP and if the station | ||
3372 | * could not connect to the AP as the AP has rejected the connection | ||
3373 | * for some reasons, this function is called. | ||
3374 | * | ||
3375 | * The reason for connection failure can be any of the value from | ||
3376 | * nl80211_connect_failed_reason enum | ||
3377 | */ | ||
3378 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | ||
3379 | enum nl80211_connect_failed_reason reason, | ||
3380 | gfp_t gfp); | ||
3381 | |||
3382 | /** | ||
3366 | * cfg80211_rx_mgmt - notification of received, unprocessed management frame | 3383 | * cfg80211_rx_mgmt - notification of received, unprocessed management frame |
3367 | * @wdev: wireless device receiving the frame | 3384 | * @wdev: wireless device receiving the frame |
3368 | * @freq: Frequency on which the frame was received in MHz | 3385 | * @freq: Frequency on which the frame was received in MHz |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 71f8262fc1df..82558c8decf8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -973,21 +973,29 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) | |||
973 | * generation in software. | 973 | * generation in software. |
974 | * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates | 974 | * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates |
975 | * that the key is pairwise rather then a shared key. | 975 | * that the key is pairwise rather then a shared key. |
976 | * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a | 976 | * @IEEE80211_KEY_FLAG_SW_MGMT_TX: This flag should be set by the driver for a |
977 | * CCMP key if it requires CCMP encryption of management frames (MFP) to | 977 | * CCMP key if it requires CCMP encryption of management frames (MFP) to |
978 | * be done in software. | 978 | * be done in software. |
979 | * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver | 979 | * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver |
980 | * if space should be prepared for the IV, but the IV | 980 | * if space should be prepared for the IV, but the IV |
981 | * itself should not be generated. Do not set together with | 981 | * itself should not be generated. Do not set together with |
982 | * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. | 982 | * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. |
983 | * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received | ||
984 | * management frames. The flag can help drivers that have a hardware | ||
985 | * crypto implementation that doesn't deal with management frames | ||
986 | * properly by allowing them to not upload the keys to hardware and | ||
987 | * fall back to software crypto. Note that this flag deals only with | ||
988 | * RX, if your crypto engine can't deal with TX you can also set the | ||
989 | * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. | ||
983 | */ | 990 | */ |
984 | enum ieee80211_key_flags { | 991 | enum ieee80211_key_flags { |
985 | IEEE80211_KEY_FLAG_WMM_STA = 1<<0, | 992 | IEEE80211_KEY_FLAG_WMM_STA = 1<<0, |
986 | IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, | 993 | IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, |
987 | IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, | 994 | IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, |
988 | IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, | 995 | IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, |
989 | IEEE80211_KEY_FLAG_SW_MGMT = 1<<4, | 996 | IEEE80211_KEY_FLAG_SW_MGMT_TX = 1<<4, |
990 | IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5, | 997 | IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5, |
998 | IEEE80211_KEY_FLAG_RX_MGMT = 1<<6, | ||
991 | }; | 999 | }; |
992 | 1000 | ||
993 | /** | 1001 | /** |
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index f5169b04f082..e900072950cb 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h | |||
@@ -30,6 +30,11 @@ struct nfc_hci_ops { | |||
30 | int (*open) (struct nfc_hci_dev *hdev); | 30 | int (*open) (struct nfc_hci_dev *hdev); |
31 | void (*close) (struct nfc_hci_dev *hdev); | 31 | void (*close) (struct nfc_hci_dev *hdev); |
32 | int (*hci_ready) (struct nfc_hci_dev *hdev); | 32 | int (*hci_ready) (struct nfc_hci_dev *hdev); |
33 | /* | ||
34 | * xmit must always send the complete buffer before | ||
35 | * returning. Returned result must be 0 for success | ||
36 | * or negative for failure. | ||
37 | */ | ||
33 | int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); | 38 | int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); |
34 | int (*start_poll) (struct nfc_hci_dev *hdev, | 39 | int (*start_poll) (struct nfc_hci_dev *hdev, |
35 | u32 im_protocols, u32 tm_protocols); | 40 | u32 im_protocols, u32 tm_protocols); |
@@ -38,8 +43,8 @@ struct nfc_hci_ops { | |||
38 | int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, | 43 | int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, |
39 | struct nfc_target *target); | 44 | struct nfc_target *target); |
40 | int (*data_exchange) (struct nfc_hci_dev *hdev, | 45 | int (*data_exchange) (struct nfc_hci_dev *hdev, |
41 | struct nfc_target *target, | 46 | struct nfc_target *target, struct sk_buff *skb, |
42 | struct sk_buff *skb, struct sk_buff **res_skb); | 47 | data_exchange_cb_t cb, void *cb_context); |
43 | int (*check_presence)(struct nfc_hci_dev *hdev, | 48 | int (*check_presence)(struct nfc_hci_dev *hdev, |
44 | struct nfc_target *target); | 49 | struct nfc_target *target); |
45 | }; | 50 | }; |
@@ -74,7 +79,6 @@ struct nfc_hci_dev { | |||
74 | 79 | ||
75 | struct list_head msg_tx_queue; | 80 | struct list_head msg_tx_queue; |
76 | 81 | ||
77 | struct workqueue_struct *msg_tx_wq; | ||
78 | struct work_struct msg_tx_work; | 82 | struct work_struct msg_tx_work; |
79 | 83 | ||
80 | struct timer_list cmd_timer; | 84 | struct timer_list cmd_timer; |
@@ -82,13 +86,14 @@ struct nfc_hci_dev { | |||
82 | 86 | ||
83 | struct sk_buff_head rx_hcp_frags; | 87 | struct sk_buff_head rx_hcp_frags; |
84 | 88 | ||
85 | struct workqueue_struct *msg_rx_wq; | ||
86 | struct work_struct msg_rx_work; | 89 | struct work_struct msg_rx_work; |
87 | 90 | ||
88 | struct sk_buff_head msg_rx_queue; | 91 | struct sk_buff_head msg_rx_queue; |
89 | 92 | ||
90 | struct nfc_hci_ops *ops; | 93 | struct nfc_hci_ops *ops; |
91 | 94 | ||
95 | struct nfc_llc *llc; | ||
96 | |||
92 | struct nfc_hci_init_data init_data; | 97 | struct nfc_hci_init_data init_data; |
93 | 98 | ||
94 | void *clientdata; | 99 | void *clientdata; |
@@ -105,12 +110,17 @@ struct nfc_hci_dev { | |||
105 | u8 hw_mpw; | 110 | u8 hw_mpw; |
106 | u8 hw_software; | 111 | u8 hw_software; |
107 | u8 hw_bsid; | 112 | u8 hw_bsid; |
113 | |||
114 | int async_cb_type; | ||
115 | data_exchange_cb_t async_cb; | ||
116 | void *async_cb_context; | ||
108 | }; | 117 | }; |
109 | 118 | ||
110 | /* hci device allocation */ | 119 | /* hci device allocation */ |
111 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | 120 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, |
112 | struct nfc_hci_init_data *init_data, | 121 | struct nfc_hci_init_data *init_data, |
113 | u32 protocols, | 122 | u32 protocols, |
123 | const char *llc_name, | ||
114 | int tx_headroom, | 124 | int tx_headroom, |
115 | int tx_tailroom, | 125 | int tx_tailroom, |
116 | int max_link_payload); | 126 | int max_link_payload); |
@@ -202,6 +212,9 @@ int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, | |||
202 | const u8 *param, size_t param_len); | 212 | const u8 *param, size_t param_len); |
203 | int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | 213 | int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, |
204 | const u8 *param, size_t param_len, struct sk_buff **skb); | 214 | const u8 *param, size_t param_len, struct sk_buff **skb); |
215 | int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | ||
216 | const u8 *param, size_t param_len, | ||
217 | data_exchange_cb_t cb, void *cb_context); | ||
205 | int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response, | 218 | int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response, |
206 | const u8 *param, size_t param_len); | 219 | const u8 *param, size_t param_len); |
207 | int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event, | 220 | int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event, |
diff --git a/include/net/nfc/llc.h b/include/net/nfc/llc.h new file mode 100644 index 000000000000..400ab7ae749d --- /dev/null +++ b/include/net/nfc/llc.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager public interface | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __NFC_LLC_H_ | ||
22 | #define __NFC_LLC_H_ | ||
23 | |||
24 | #include <net/nfc/hci.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | |||
27 | #define LLC_NOP_NAME "nop" | ||
28 | #define LLC_SHDLC_NAME "shdlc" | ||
29 | |||
30 | typedef void (*rcv_to_hci_t) (struct nfc_hci_dev *hdev, struct sk_buff *skb); | ||
31 | typedef int (*xmit_to_drv_t) (struct nfc_hci_dev *hdev, struct sk_buff *skb); | ||
32 | typedef void (*llc_failure_t) (struct nfc_hci_dev *hdev, int err); | ||
33 | |||
34 | struct nfc_llc; | ||
35 | |||
36 | struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev, | ||
37 | xmit_to_drv_t xmit_to_drv, | ||
38 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
39 | int tx_tailroom, llc_failure_t llc_failure); | ||
40 | void nfc_llc_free(struct nfc_llc *llc); | ||
41 | |||
42 | void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom, | ||
43 | int *rx_tailroom); | ||
44 | |||
45 | |||
46 | int nfc_llc_start(struct nfc_llc *llc); | ||
47 | int nfc_llc_stop(struct nfc_llc *llc); | ||
48 | void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb); | ||
49 | int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb); | ||
50 | |||
51 | int nfc_llc_init(void); | ||
52 | void nfc_llc_exit(void); | ||
53 | |||
54 | #endif /* __NFC_LLC_H_ */ | ||
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h index 276094b91d7c..88785e5c6b2c 100644 --- a/include/net/nfc/nci.h +++ b/include/net/nfc/nci.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #define NCI_MAX_NUM_MAPPING_CONFIGS 10 | 32 | #define NCI_MAX_NUM_MAPPING_CONFIGS 10 |
33 | #define NCI_MAX_NUM_RF_CONFIGS 10 | 33 | #define NCI_MAX_NUM_RF_CONFIGS 10 |
34 | #define NCI_MAX_NUM_CONN 10 | 34 | #define NCI_MAX_NUM_CONN 10 |
35 | #define NCI_MAX_PARAM_LEN 251 | ||
35 | 36 | ||
36 | /* NCI Status Codes */ | 37 | /* NCI Status Codes */ |
37 | #define NCI_STATUS_OK 0x00 | 38 | #define NCI_STATUS_OK 0x00 |
@@ -102,6 +103,9 @@ | |||
102 | #define NCI_RF_INTERFACE_ISO_DEP 0x02 | 103 | #define NCI_RF_INTERFACE_ISO_DEP 0x02 |
103 | #define NCI_RF_INTERFACE_NFC_DEP 0x03 | 104 | #define NCI_RF_INTERFACE_NFC_DEP 0x03 |
104 | 105 | ||
106 | /* NCI Configuration Parameter Tags */ | ||
107 | #define NCI_PN_ATR_REQ_GEN_BYTES 0x29 | ||
108 | |||
105 | /* NCI Reset types */ | 109 | /* NCI Reset types */ |
106 | #define NCI_RESET_TYPE_KEEP_CONFIG 0x00 | 110 | #define NCI_RESET_TYPE_KEEP_CONFIG 0x00 |
107 | #define NCI_RESET_TYPE_RESET_CONFIG 0x01 | 111 | #define NCI_RESET_TYPE_RESET_CONFIG 0x01 |
@@ -188,6 +192,18 @@ struct nci_core_reset_cmd { | |||
188 | 192 | ||
189 | #define NCI_OP_CORE_INIT_CMD nci_opcode_pack(NCI_GID_CORE, 0x01) | 193 | #define NCI_OP_CORE_INIT_CMD nci_opcode_pack(NCI_GID_CORE, 0x01) |
190 | 194 | ||
195 | #define NCI_OP_CORE_SET_CONFIG_CMD nci_opcode_pack(NCI_GID_CORE, 0x02) | ||
196 | struct set_config_param { | ||
197 | __u8 id; | ||
198 | __u8 len; | ||
199 | __u8 val[NCI_MAX_PARAM_LEN]; | ||
200 | } __packed; | ||
201 | |||
202 | struct nci_core_set_config_cmd { | ||
203 | __u8 num_params; | ||
204 | struct set_config_param param; /* support 1 param per cmd is enough */ | ||
205 | } __packed; | ||
206 | |||
191 | #define NCI_OP_RF_DISCOVER_MAP_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x00) | 207 | #define NCI_OP_RF_DISCOVER_MAP_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x00) |
192 | struct disc_map_config { | 208 | struct disc_map_config { |
193 | __u8 rf_protocol; | 209 | __u8 rf_protocol; |
@@ -252,6 +268,13 @@ struct nci_core_init_rsp_2 { | |||
252 | __le32 manufact_specific_info; | 268 | __le32 manufact_specific_info; |
253 | } __packed; | 269 | } __packed; |
254 | 270 | ||
271 | #define NCI_OP_CORE_SET_CONFIG_RSP nci_opcode_pack(NCI_GID_CORE, 0x02) | ||
272 | struct nci_core_set_config_rsp { | ||
273 | __u8 status; | ||
274 | __u8 num_params; | ||
275 | __u8 params_id[0]; /* variable size array */ | ||
276 | } __packed; | ||
277 | |||
255 | #define NCI_OP_RF_DISCOVER_MAP_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x00) | 278 | #define NCI_OP_RF_DISCOVER_MAP_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x00) |
256 | 279 | ||
257 | #define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03) | 280 | #define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03) |
@@ -328,6 +351,11 @@ struct activation_params_nfcb_poll_iso_dep { | |||
328 | __u8 attrib_res[50]; | 351 | __u8 attrib_res[50]; |
329 | }; | 352 | }; |
330 | 353 | ||
354 | struct activation_params_poll_nfc_dep { | ||
355 | __u8 atr_res_len; | ||
356 | __u8 atr_res[63]; | ||
357 | }; | ||
358 | |||
331 | struct nci_rf_intf_activated_ntf { | 359 | struct nci_rf_intf_activated_ntf { |
332 | __u8 rf_discovery_id; | 360 | __u8 rf_discovery_id; |
333 | __u8 rf_interface; | 361 | __u8 rf_interface; |
@@ -351,6 +379,7 @@ struct nci_rf_intf_activated_ntf { | |||
351 | union { | 379 | union { |
352 | struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep; | 380 | struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep; |
353 | struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep; | 381 | struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep; |
382 | struct activation_params_poll_nfc_dep poll_nfc_dep; | ||
354 | } activation_params; | 383 | } activation_params; |
355 | 384 | ||
356 | } __packed; | 385 | } __packed; |
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index feba74027ff8..d705d8674949 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h | |||
@@ -54,6 +54,7 @@ enum nci_state { | |||
54 | /* NCI timeouts */ | 54 | /* NCI timeouts */ |
55 | #define NCI_RESET_TIMEOUT 5000 | 55 | #define NCI_RESET_TIMEOUT 5000 |
56 | #define NCI_INIT_TIMEOUT 5000 | 56 | #define NCI_INIT_TIMEOUT 5000 |
57 | #define NCI_SET_CONFIG_TIMEOUT 5000 | ||
57 | #define NCI_RF_DISC_TIMEOUT 5000 | 58 | #define NCI_RF_DISC_TIMEOUT 5000 |
58 | #define NCI_RF_DISC_SELECT_TIMEOUT 5000 | 59 | #define NCI_RF_DISC_SELECT_TIMEOUT 5000 |
59 | #define NCI_RF_DEACTIVATE_TIMEOUT 30000 | 60 | #define NCI_RF_DEACTIVATE_TIMEOUT 30000 |
@@ -137,6 +138,10 @@ struct nci_dev { | |||
137 | data_exchange_cb_t data_exchange_cb; | 138 | data_exchange_cb_t data_exchange_cb; |
138 | void *data_exchange_cb_context; | 139 | void *data_exchange_cb_context; |
139 | struct sk_buff *rx_data_reassembly; | 140 | struct sk_buff *rx_data_reassembly; |
141 | |||
142 | /* stored during intf_activated_ntf */ | ||
143 | __u8 remote_gb[NFC_MAX_GT_LEN]; | ||
144 | __u8 remote_gb_len; | ||
140 | }; | 145 | }; |
141 | 146 | ||
142 | /* ----- NCI Devices ----- */ | 147 | /* ----- NCI Devices ----- */ |
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 6735909f826d..f05b10682c9d 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h | |||
@@ -72,6 +72,7 @@ struct nfc_ops { | |||
72 | 72 | ||
73 | #define NFC_TARGET_IDX_ANY -1 | 73 | #define NFC_TARGET_IDX_ANY -1 |
74 | #define NFC_MAX_GT_LEN 48 | 74 | #define NFC_MAX_GT_LEN 48 |
75 | #define NFC_ATR_RES_GT_OFFSET 15 | ||
75 | 76 | ||
76 | struct nfc_target { | 77 | struct nfc_target { |
77 | u32 idx; | 78 | u32 idx; |
@@ -112,7 +113,6 @@ struct nfc_dev { | |||
112 | int tx_tailroom; | 113 | int tx_tailroom; |
113 | 114 | ||
114 | struct timer_list check_pres_timer; | 115 | struct timer_list check_pres_timer; |
115 | struct workqueue_struct *check_pres_wq; | ||
116 | struct work_struct check_pres_work; | 116 | struct work_struct check_pres_work; |
117 | 117 | ||
118 | struct nfc_ops *ops; | 118 | struct nfc_ops *ops; |
diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h deleted file mode 100644 index 35e930d2f638..000000000000 --- a/include/net/nfc/shdlc.h +++ /dev/null | |||
@@ -1,107 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef __NFC_SHDLC_H | ||
21 | #define __NFC_SHDLC_H | ||
22 | |||
23 | struct nfc_shdlc; | ||
24 | |||
25 | struct nfc_shdlc_ops { | ||
26 | int (*open) (struct nfc_shdlc *shdlc); | ||
27 | void (*close) (struct nfc_shdlc *shdlc); | ||
28 | int (*hci_ready) (struct nfc_shdlc *shdlc); | ||
29 | int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb); | ||
30 | int (*start_poll) (struct nfc_shdlc *shdlc, | ||
31 | u32 im_protocols, u32 tm_protocols); | ||
32 | int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate, | ||
33 | struct nfc_target *target); | ||
34 | int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate, | ||
35 | struct nfc_target *target); | ||
36 | int (*data_exchange) (struct nfc_shdlc *shdlc, | ||
37 | struct nfc_target *target, | ||
38 | struct sk_buff *skb, struct sk_buff **res_skb); | ||
39 | int (*check_presence)(struct nfc_shdlc *shdlc, | ||
40 | struct nfc_target *target); | ||
41 | }; | ||
42 | |||
43 | enum shdlc_state { | ||
44 | SHDLC_DISCONNECTED = 0, | ||
45 | SHDLC_CONNECTING = 1, | ||
46 | SHDLC_NEGOCIATING = 2, | ||
47 | SHDLC_CONNECTED = 3 | ||
48 | }; | ||
49 | |||
50 | struct nfc_shdlc { | ||
51 | struct mutex state_mutex; | ||
52 | enum shdlc_state state; | ||
53 | int hard_fault; | ||
54 | |||
55 | struct nfc_hci_dev *hdev; | ||
56 | |||
57 | wait_queue_head_t *connect_wq; | ||
58 | int connect_tries; | ||
59 | int connect_result; | ||
60 | struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ | ||
61 | |||
62 | u8 w; /* window size */ | ||
63 | bool srej_support; | ||
64 | |||
65 | struct timer_list t1_timer; /* send ack timeout */ | ||
66 | bool t1_active; | ||
67 | |||
68 | struct timer_list t2_timer; /* guard/retransmit timeout */ | ||
69 | bool t2_active; | ||
70 | |||
71 | int ns; /* next seq num for send */ | ||
72 | int nr; /* next expected seq num for receive */ | ||
73 | int dnr; /* oldest sent unacked seq num */ | ||
74 | |||
75 | struct sk_buff_head rcv_q; | ||
76 | |||
77 | struct sk_buff_head send_q; | ||
78 | bool rnr; /* other side is not ready to receive */ | ||
79 | |||
80 | struct sk_buff_head ack_pending_q; | ||
81 | |||
82 | struct workqueue_struct *sm_wq; | ||
83 | struct work_struct sm_work; | ||
84 | |||
85 | struct nfc_shdlc_ops *ops; | ||
86 | |||
87 | int client_headroom; | ||
88 | int client_tailroom; | ||
89 | |||
90 | void *clientdata; | ||
91 | }; | ||
92 | |||
93 | void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb); | ||
94 | |||
95 | struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | ||
96 | struct nfc_hci_init_data *init_data, | ||
97 | u32 protocols, | ||
98 | int tx_headroom, int tx_tailroom, | ||
99 | int max_link_payload, const char *devname); | ||
100 | |||
101 | void nfc_shdlc_free(struct nfc_shdlc *shdlc); | ||
102 | |||
103 | void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata); | ||
104 | void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc); | ||
105 | struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc); | ||
106 | |||
107 | #endif /* __NFC_SHDLC_H */ | ||
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 58f9762b339a..9d49ee6d7219 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
@@ -567,8 +567,6 @@ static void bt_seq_stop(struct seq_file *seq, void *v) | |||
567 | 567 | ||
568 | static int bt_seq_show(struct seq_file *seq, void *v) | 568 | static int bt_seq_show(struct seq_file *seq, void *v) |
569 | { | 569 | { |
570 | struct sock *sk; | ||
571 | struct bt_sock *bt; | ||
572 | struct bt_seq_state *s = seq->private; | 570 | struct bt_seq_state *s = seq->private; |
573 | struct bt_sock_list *l = s->l; | 571 | struct bt_sock_list *l = s->l; |
574 | bdaddr_t src_baswapped, dst_baswapped; | 572 | bdaddr_t src_baswapped, dst_baswapped; |
@@ -583,8 +581,8 @@ static int bt_seq_show(struct seq_file *seq, void *v) | |||
583 | 581 | ||
584 | seq_putc(seq, '\n'); | 582 | seq_putc(seq, '\n'); |
585 | } else { | 583 | } else { |
586 | sk = sk_entry(v); | 584 | struct sock *sk = sk_entry(v); |
587 | bt = bt_sk(sk); | 585 | struct bt_sock *bt = bt_sk(sk); |
588 | baswap(&src_baswapped, &bt->src); | 586 | baswap(&src_baswapped, &bt->src); |
589 | baswap(&dst_baswapped, &bt->dst); | 587 | baswap(&dst_baswapped, &bt->dst); |
590 | 588 | ||
@@ -624,7 +622,7 @@ static int bt_seq_open(struct inode *inode, struct file *file) | |||
624 | sk_list = PDE(inode)->data; | 622 | sk_list = PDE(inode)->data; |
625 | s = __seq_open_private(file, &bt_seq_ops, | 623 | s = __seq_open_private(file, &bt_seq_ops, |
626 | sizeof(struct bt_seq_state)); | 624 | sizeof(struct bt_seq_state)); |
627 | if (s == NULL) | 625 | if (!s) |
628 | return -ENOMEM; | 626 | return -ENOMEM; |
629 | 627 | ||
630 | s->l = sk_list; | 628 | s->l = sk_list; |
@@ -646,7 +644,7 @@ int bt_procfs_init(struct module* module, struct net *net, const char *name, | |||
646 | sk_list->fops.release = seq_release_private; | 644 | sk_list->fops.release = seq_release_private; |
647 | 645 | ||
648 | pde = proc_net_fops_create(net, name, 0, &sk_list->fops); | 646 | pde = proc_net_fops_create(net, name, 0, &sk_list->fops); |
649 | if (pde == NULL) | 647 | if (!pde) |
650 | return -ENOMEM; | 648 | return -ENOMEM; |
651 | 649 | ||
652 | pde->data = sk_list; | 650 | pde->data = sk_list; |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3c094e78dde9..b9196a44f759 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <net/bluetooth/a2mp.h> | 31 | #include <net/bluetooth/a2mp.h> |
32 | #include <net/bluetooth/smp.h> | 32 | #include <net/bluetooth/smp.h> |
33 | 33 | ||
34 | static void hci_le_connect(struct hci_conn *conn) | 34 | static void hci_le_create_connection(struct hci_conn *conn) |
35 | { | 35 | { |
36 | struct hci_dev *hdev = conn->hdev; | 36 | struct hci_dev *hdev = conn->hdev; |
37 | struct hci_cp_le_create_conn cp; | 37 | struct hci_cp_le_create_conn cp; |
@@ -55,12 +55,12 @@ static void hci_le_connect(struct hci_conn *conn) | |||
55 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); | 55 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void hci_le_connect_cancel(struct hci_conn *conn) | 58 | static void hci_le_create_connection_cancel(struct hci_conn *conn) |
59 | { | 59 | { |
60 | hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); | 60 | hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); |
61 | } | 61 | } |
62 | 62 | ||
63 | void hci_acl_connect(struct hci_conn *conn) | 63 | static void hci_acl_create_connection(struct hci_conn *conn) |
64 | { | 64 | { |
65 | struct hci_dev *hdev = conn->hdev; | 65 | struct hci_dev *hdev = conn->hdev; |
66 | struct inquiry_entry *ie; | 66 | struct inquiry_entry *ie; |
@@ -104,7 +104,7 @@ void hci_acl_connect(struct hci_conn *conn) | |||
104 | hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp); | 104 | hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp); |
105 | } | 105 | } |
106 | 106 | ||
107 | static void hci_acl_connect_cancel(struct hci_conn *conn) | 107 | static void hci_acl_create_connection_cancel(struct hci_conn *conn) |
108 | { | 108 | { |
109 | struct hci_cp_create_conn_cancel cp; | 109 | struct hci_cp_create_conn_cancel cp; |
110 | 110 | ||
@@ -130,7 +130,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) | |||
130 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); | 130 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); |
131 | } | 131 | } |
132 | 132 | ||
133 | void hci_add_sco(struct hci_conn *conn, __u16 handle) | 133 | static void hci_add_sco(struct hci_conn *conn, __u16 handle) |
134 | { | 134 | { |
135 | struct hci_dev *hdev = conn->hdev; | 135 | struct hci_dev *hdev = conn->hdev; |
136 | struct hci_cp_add_sco cp; | 136 | struct hci_cp_add_sco cp; |
@@ -246,9 +246,9 @@ static void hci_conn_timeout(struct work_struct *work) | |||
246 | case BT_CONNECT2: | 246 | case BT_CONNECT2: |
247 | if (conn->out) { | 247 | if (conn->out) { |
248 | if (conn->type == ACL_LINK) | 248 | if (conn->type == ACL_LINK) |
249 | hci_acl_connect_cancel(conn); | 249 | hci_acl_create_connection_cancel(conn); |
250 | else if (conn->type == LE_LINK) | 250 | else if (conn->type == LE_LINK) |
251 | hci_le_connect_cancel(conn); | 251 | hci_le_create_connection_cancel(conn); |
252 | } | 252 | } |
253 | break; | 253 | break; |
254 | case BT_CONFIG: | 254 | case BT_CONFIG: |
@@ -471,40 +471,37 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) | |||
471 | } | 471 | } |
472 | EXPORT_SYMBOL(hci_get_route); | 472 | EXPORT_SYMBOL(hci_get_route); |
473 | 473 | ||
474 | /* Create SCO, ACL or LE connection. | 474 | static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, |
475 | * Device _must_ be locked */ | 475 | u8 dst_type, u8 sec_level, u8 auth_type) |
476 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | ||
477 | __u8 dst_type, __u8 sec_level, __u8 auth_type) | ||
478 | { | 476 | { |
479 | struct hci_conn *acl; | ||
480 | struct hci_conn *sco; | ||
481 | struct hci_conn *le; | 477 | struct hci_conn *le; |
482 | 478 | ||
483 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 479 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); |
480 | if (!le) { | ||
481 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); | ||
482 | if (le) | ||
483 | return ERR_PTR(-EBUSY); | ||
484 | 484 | ||
485 | if (type == LE_LINK) { | 485 | le = hci_conn_add(hdev, LE_LINK, dst); |
486 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | 486 | if (!le) |
487 | if (!le) { | 487 | return ERR_PTR(-ENOMEM); |
488 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, | ||
489 | BT_CONNECT); | ||
490 | if (le) | ||
491 | return ERR_PTR(-EBUSY); | ||
492 | 488 | ||
493 | le = hci_conn_add(hdev, LE_LINK, dst); | 489 | le->dst_type = bdaddr_to_le(dst_type); |
494 | if (!le) | 490 | hci_le_create_connection(le); |
495 | return ERR_PTR(-ENOMEM); | 491 | } |
496 | 492 | ||
497 | le->dst_type = bdaddr_to_le(dst_type); | 493 | le->pending_sec_level = sec_level; |
498 | hci_le_connect(le); | 494 | le->auth_type = auth_type; |
499 | } | ||
500 | 495 | ||
501 | le->pending_sec_level = sec_level; | 496 | hci_conn_hold(le); |
502 | le->auth_type = auth_type; | ||
503 | 497 | ||
504 | hci_conn_hold(le); | 498 | return le; |
499 | } | ||
505 | 500 | ||
506 | return le; | 501 | static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, |
507 | } | 502 | u8 sec_level, u8 auth_type) |
503 | { | ||
504 | struct hci_conn *acl; | ||
508 | 505 | ||
509 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); | 506 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); |
510 | if (!acl) { | 507 | if (!acl) { |
@@ -519,10 +516,20 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | |||
519 | acl->sec_level = BT_SECURITY_LOW; | 516 | acl->sec_level = BT_SECURITY_LOW; |
520 | acl->pending_sec_level = sec_level; | 517 | acl->pending_sec_level = sec_level; |
521 | acl->auth_type = auth_type; | 518 | acl->auth_type = auth_type; |
522 | hci_acl_connect(acl); | 519 | hci_acl_create_connection(acl); |
523 | } | 520 | } |
524 | 521 | ||
525 | if (type == ACL_LINK) | 522 | return acl; |
523 | } | ||
524 | |||
525 | static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, | ||
526 | bdaddr_t *dst, u8 sec_level, u8 auth_type) | ||
527 | { | ||
528 | struct hci_conn *acl; | ||
529 | struct hci_conn *sco; | ||
530 | |||
531 | acl = hci_connect_acl(hdev, dst, sec_level, auth_type); | ||
532 | if (IS_ERR(acl)) | ||
526 | return acl; | 533 | return acl; |
527 | 534 | ||
528 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); | 535 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); |
@@ -556,6 +563,25 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | |||
556 | return sco; | 563 | return sco; |
557 | } | 564 | } |
558 | 565 | ||
566 | /* Create SCO, ACL or LE connection. */ | ||
567 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | ||
568 | __u8 dst_type, __u8 sec_level, __u8 auth_type) | ||
569 | { | ||
570 | BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type); | ||
571 | |||
572 | switch (type) { | ||
573 | case LE_LINK: | ||
574 | return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type); | ||
575 | case ACL_LINK: | ||
576 | return hci_connect_acl(hdev, dst, sec_level, auth_type); | ||
577 | case SCO_LINK: | ||
578 | case ESCO_LINK: | ||
579 | return hci_connect_sco(hdev, type, dst, sec_level, auth_type); | ||
580 | } | ||
581 | |||
582 | return ERR_PTR(-EINVAL); | ||
583 | } | ||
584 | |||
559 | /* Check link security requirement */ | 585 | /* Check link security requirement */ |
560 | int hci_conn_check_link_mode(struct hci_conn *conn) | 586 | int hci_conn_check_link_mode(struct hci_conn *conn) |
561 | { | 587 | { |
@@ -775,7 +801,7 @@ void hci_conn_check_pending(struct hci_dev *hdev) | |||
775 | 801 | ||
776 | conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); | 802 | conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); |
777 | if (conn) | 803 | if (conn) |
778 | hci_acl_connect(conn); | 804 | hci_acl_create_connection(conn); |
779 | 805 | ||
780 | hci_dev_unlock(hdev); | 806 | hci_dev_unlock(hdev); |
781 | } | 807 | } |
@@ -913,7 +939,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) | |||
913 | return chan; | 939 | return chan; |
914 | } | 940 | } |
915 | 941 | ||
916 | int hci_chan_del(struct hci_chan *chan) | 942 | void hci_chan_del(struct hci_chan *chan) |
917 | { | 943 | { |
918 | struct hci_conn *conn = chan->conn; | 944 | struct hci_conn *conn = chan->conn; |
919 | struct hci_dev *hdev = conn->hdev; | 945 | struct hci_dev *hdev = conn->hdev; |
@@ -926,8 +952,6 @@ int hci_chan_del(struct hci_chan *chan) | |||
926 | 952 | ||
927 | skb_queue_purge(&chan->data_q); | 953 | skb_queue_purge(&chan->data_q); |
928 | kfree(chan); | 954 | kfree(chan); |
929 | |||
930 | return 0; | ||
931 | } | 955 | } |
932 | 956 | ||
933 | void hci_chan_list_flush(struct hci_conn *conn) | 957 | void hci_chan_list_flush(struct hci_conn *conn) |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8806869ad4d6..8a0ce706aebd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -231,6 +231,9 @@ static void amp_init(struct hci_dev *hdev) | |||
231 | 231 | ||
232 | /* Read Local AMP Info */ | 232 | /* Read Local AMP Info */ |
233 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); | 233 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); |
234 | |||
235 | /* Read Data Blk size */ | ||
236 | hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL); | ||
234 | } | 237 | } |
235 | 238 | ||
236 | static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | 239 | static void hci_init_req(struct hci_dev *hdev, unsigned long opt) |
@@ -268,7 +271,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | |||
268 | BT_ERR("Unknown device type %d", hdev->dev_type); | 271 | BT_ERR("Unknown device type %d", hdev->dev_type); |
269 | break; | 272 | break; |
270 | } | 273 | } |
271 | |||
272 | } | 274 | } |
273 | 275 | ||
274 | static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) | 276 | static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) |
@@ -1654,6 +1656,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
1654 | INIT_LIST_HEAD(&hdev->link_keys); | 1656 | INIT_LIST_HEAD(&hdev->link_keys); |
1655 | INIT_LIST_HEAD(&hdev->long_term_keys); | 1657 | INIT_LIST_HEAD(&hdev->long_term_keys); |
1656 | INIT_LIST_HEAD(&hdev->remote_oob_data); | 1658 | INIT_LIST_HEAD(&hdev->remote_oob_data); |
1659 | INIT_LIST_HEAD(&hdev->conn_hash.list); | ||
1657 | 1660 | ||
1658 | INIT_WORK(&hdev->rx_work, hci_rx_work); | 1661 | INIT_WORK(&hdev->rx_work, hci_rx_work); |
1659 | INIT_WORK(&hdev->cmd_work, hci_cmd_work); | 1662 | INIT_WORK(&hdev->cmd_work, hci_cmd_work); |
@@ -1676,7 +1679,6 @@ struct hci_dev *hci_alloc_dev(void) | |||
1676 | 1679 | ||
1677 | hci_init_sysfs(hdev); | 1680 | hci_init_sysfs(hdev); |
1678 | discovery_init(hdev); | 1681 | discovery_init(hdev); |
1679 | hci_conn_hash_init(hdev); | ||
1680 | 1682 | ||
1681 | return hdev; | 1683 | return hdev; |
1682 | } | 1684 | } |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4fd2cf3bcd05..2022b43c7353 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include <net/bluetooth/bluetooth.h> | 30 | #include <net/bluetooth/bluetooth.h> |
31 | #include <net/bluetooth/hci_core.h> | 31 | #include <net/bluetooth/hci_core.h> |
32 | #include <net/bluetooth/mgmt.h> | ||
32 | 33 | ||
33 | /* Handle HCI Event packets */ | 34 | /* Handle HCI Event packets */ |
34 | 35 | ||
@@ -303,7 +304,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
303 | 304 | ||
304 | hci_dev_lock(hdev); | 305 | hci_dev_lock(hdev); |
305 | 306 | ||
306 | if (status != 0) { | 307 | if (status) { |
307 | mgmt_write_scan_failed(hdev, param, status); | 308 | mgmt_write_scan_failed(hdev, param, status); |
308 | hdev->discov_timeout = 0; | 309 | hdev->discov_timeout = 0; |
309 | goto done; | 310 | goto done; |
@@ -925,7 +926,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) | |||
925 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | 926 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) |
926 | mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); | 927 | mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); |
927 | 928 | ||
928 | if (rp->status != 0) | 929 | if (rp->status) |
929 | goto unlock; | 930 | goto unlock; |
930 | 931 | ||
931 | cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY); | 932 | cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY); |
@@ -1891,6 +1892,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1891 | } | 1892 | } |
1892 | } | 1893 | } |
1893 | 1894 | ||
1895 | static u8 hci_to_mgmt_reason(u8 err) | ||
1896 | { | ||
1897 | switch (err) { | ||
1898 | case HCI_ERROR_CONNECTION_TIMEOUT: | ||
1899 | return MGMT_DEV_DISCONN_TIMEOUT; | ||
1900 | case HCI_ERROR_REMOTE_USER_TERM: | ||
1901 | case HCI_ERROR_REMOTE_LOW_RESOURCES: | ||
1902 | case HCI_ERROR_REMOTE_POWER_OFF: | ||
1903 | return MGMT_DEV_DISCONN_REMOTE; | ||
1904 | case HCI_ERROR_LOCAL_HOST_TERM: | ||
1905 | return MGMT_DEV_DISCONN_LOCAL_HOST; | ||
1906 | default: | ||
1907 | return MGMT_DEV_DISCONN_UNKNOWN; | ||
1908 | } | ||
1909 | } | ||
1910 | |||
1894 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1911 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
1895 | { | 1912 | { |
1896 | struct hci_ev_disconn_complete *ev = (void *) skb->data; | 1913 | struct hci_ev_disconn_complete *ev = (void *) skb->data; |
@@ -1909,12 +1926,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1909 | 1926 | ||
1910 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && | 1927 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && |
1911 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { | 1928 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { |
1912 | if (ev->status != 0) | 1929 | if (ev->status) { |
1913 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, | 1930 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, |
1914 | conn->dst_type, ev->status); | 1931 | conn->dst_type, ev->status); |
1915 | else | 1932 | } else { |
1933 | u8 reason = hci_to_mgmt_reason(ev->reason); | ||
1934 | |||
1916 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, | 1935 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, |
1917 | conn->dst_type); | 1936 | conn->dst_type, reason); |
1937 | } | ||
1918 | } | 1938 | } |
1919 | 1939 | ||
1920 | if (ev->status == 0) { | 1940 | if (ev->status == 0) { |
@@ -3259,6 +3279,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev, | |||
3259 | mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0); | 3279 | mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0); |
3260 | } | 3280 | } |
3261 | 3281 | ||
3282 | static void hci_user_passkey_notify_evt(struct hci_dev *hdev, | ||
3283 | struct sk_buff *skb) | ||
3284 | { | ||
3285 | struct hci_ev_user_passkey_notify *ev = (void *) skb->data; | ||
3286 | struct hci_conn *conn; | ||
3287 | |||
3288 | BT_DBG("%s", hdev->name); | ||
3289 | |||
3290 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
3291 | if (!conn) | ||
3292 | return; | ||
3293 | |||
3294 | conn->passkey_notify = __le32_to_cpu(ev->passkey); | ||
3295 | conn->passkey_entered = 0; | ||
3296 | |||
3297 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | ||
3298 | mgmt_user_passkey_notify(hdev, &conn->dst, conn->type, | ||
3299 | conn->dst_type, conn->passkey_notify, | ||
3300 | conn->passkey_entered); | ||
3301 | } | ||
3302 | |||
3303 | static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
3304 | { | ||
3305 | struct hci_ev_keypress_notify *ev = (void *) skb->data; | ||
3306 | struct hci_conn *conn; | ||
3307 | |||
3308 | BT_DBG("%s", hdev->name); | ||
3309 | |||
3310 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
3311 | if (!conn) | ||
3312 | return; | ||
3313 | |||
3314 | switch (ev->type) { | ||
3315 | case HCI_KEYPRESS_STARTED: | ||
3316 | conn->passkey_entered = 0; | ||
3317 | return; | ||
3318 | |||
3319 | case HCI_KEYPRESS_ENTERED: | ||
3320 | conn->passkey_entered++; | ||
3321 | break; | ||
3322 | |||
3323 | case HCI_KEYPRESS_ERASED: | ||
3324 | conn->passkey_entered--; | ||
3325 | break; | ||
3326 | |||
3327 | case HCI_KEYPRESS_CLEARED: | ||
3328 | conn->passkey_entered = 0; | ||
3329 | break; | ||
3330 | |||
3331 | case HCI_KEYPRESS_COMPLETED: | ||
3332 | return; | ||
3333 | } | ||
3334 | |||
3335 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | ||
3336 | mgmt_user_passkey_notify(hdev, &conn->dst, conn->type, | ||
3337 | conn->dst_type, conn->passkey_notify, | ||
3338 | conn->passkey_entered); | ||
3339 | } | ||
3340 | |||
3262 | static void hci_simple_pair_complete_evt(struct hci_dev *hdev, | 3341 | static void hci_simple_pair_complete_evt(struct hci_dev *hdev, |
3263 | struct sk_buff *skb) | 3342 | struct sk_buff *skb) |
3264 | { | 3343 | { |
@@ -3278,7 +3357,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, | |||
3278 | * initiated the authentication. A traditional auth_complete | 3357 | * initiated the authentication. A traditional auth_complete |
3279 | * event gets always produced as initiator and is also mapped to | 3358 | * event gets always produced as initiator and is also mapped to |
3280 | * the mgmt_auth_failed event */ | 3359 | * the mgmt_auth_failed event */ |
3281 | if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) | 3360 | if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status) |
3282 | mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, | 3361 | mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, |
3283 | ev->status); | 3362 | ev->status); |
3284 | 3363 | ||
@@ -3623,6 +3702,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
3623 | hci_user_passkey_request_evt(hdev, skb); | 3702 | hci_user_passkey_request_evt(hdev, skb); |
3624 | break; | 3703 | break; |
3625 | 3704 | ||
3705 | case HCI_EV_USER_PASSKEY_NOTIFY: | ||
3706 | hci_user_passkey_notify_evt(hdev, skb); | ||
3707 | break; | ||
3708 | |||
3709 | case HCI_EV_KEYPRESS_NOTIFY: | ||
3710 | hci_keypress_notify_evt(hdev, skb); | ||
3711 | break; | ||
3712 | |||
3626 | case HCI_EV_SIMPLE_PAIR_COMPLETE: | 3713 | case HCI_EV_SIMPLE_PAIR_COMPLETE: |
3627 | hci_simple_pair_complete_evt(hdev, skb); | 3714 | hci_simple_pair_complete_evt(hdev, skb); |
3628 | break; | 3715 | break; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bda526edfb9e..a91239dcda41 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -406,7 +406,7 @@ struct l2cap_chan *l2cap_chan_create(void) | |||
406 | 406 | ||
407 | chan->state = BT_OPEN; | 407 | chan->state = BT_OPEN; |
408 | 408 | ||
409 | atomic_set(&chan->refcnt, 1); | 409 | kref_init(&chan->kref); |
410 | 410 | ||
411 | /* This flag is cleared in l2cap_chan_ready() */ | 411 | /* This flag is cleared in l2cap_chan_ready() */ |
412 | set_bit(CONF_NOT_COMPLETE, &chan->conf_state); | 412 | set_bit(CONF_NOT_COMPLETE, &chan->conf_state); |
@@ -416,8 +416,10 @@ struct l2cap_chan *l2cap_chan_create(void) | |||
416 | return chan; | 416 | return chan; |
417 | } | 417 | } |
418 | 418 | ||
419 | static void l2cap_chan_destroy(struct l2cap_chan *chan) | 419 | static void l2cap_chan_destroy(struct kref *kref) |
420 | { | 420 | { |
421 | struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref); | ||
422 | |||
421 | BT_DBG("chan %p", chan); | 423 | BT_DBG("chan %p", chan); |
422 | 424 | ||
423 | write_lock(&chan_list_lock); | 425 | write_lock(&chan_list_lock); |
@@ -429,17 +431,16 @@ static void l2cap_chan_destroy(struct l2cap_chan *chan) | |||
429 | 431 | ||
430 | void l2cap_chan_hold(struct l2cap_chan *c) | 432 | void l2cap_chan_hold(struct l2cap_chan *c) |
431 | { | 433 | { |
432 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt)); | 434 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount)); |
433 | 435 | ||
434 | atomic_inc(&c->refcnt); | 436 | kref_get(&c->kref); |
435 | } | 437 | } |
436 | 438 | ||
437 | void l2cap_chan_put(struct l2cap_chan *c) | 439 | void l2cap_chan_put(struct l2cap_chan *c) |
438 | { | 440 | { |
439 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt)); | 441 | BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount)); |
440 | 442 | ||
441 | if (atomic_dec_and_test(&c->refcnt)) | 443 | kref_put(&c->kref, l2cap_chan_destroy); |
442 | l2cap_chan_destroy(c); | ||
443 | } | 444 | } |
444 | 445 | ||
445 | void l2cap_chan_set_defaults(struct l2cap_chan *chan) | 446 | void l2cap_chan_set_defaults(struct l2cap_chan *chan) |
@@ -1448,7 +1449,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
1448 | int err; | 1449 | int err; |
1449 | 1450 | ||
1450 | BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), | 1451 | BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), |
1451 | dst_type, __le16_to_cpu(chan->psm)); | 1452 | dst_type, __le16_to_cpu(psm)); |
1452 | 1453 | ||
1453 | hdev = hci_get_route(dst, src); | 1454 | hdev = hci_get_route(dst, src); |
1454 | if (!hdev) | 1455 | if (!hdev) |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e3296319606b..aa2ea0a8142c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -35,7 +35,7 @@ | |||
35 | bool enable_hs; | 35 | bool enable_hs; |
36 | 36 | ||
37 | #define MGMT_VERSION 1 | 37 | #define MGMT_VERSION 1 |
38 | #define MGMT_REVISION 1 | 38 | #define MGMT_REVISION 2 |
39 | 39 | ||
40 | static const u16 mgmt_commands[] = { | 40 | static const u16 mgmt_commands[] = { |
41 | MGMT_OP_READ_INDEX_LIST, | 41 | MGMT_OP_READ_INDEX_LIST, |
@@ -99,6 +99,7 @@ static const u16 mgmt_events[] = { | |||
99 | MGMT_EV_DEVICE_BLOCKED, | 99 | MGMT_EV_DEVICE_BLOCKED, |
100 | MGMT_EV_DEVICE_UNBLOCKED, | 100 | MGMT_EV_DEVICE_UNBLOCKED, |
101 | MGMT_EV_DEVICE_UNPAIRED, | 101 | MGMT_EV_DEVICE_UNPAIRED, |
102 | MGMT_EV_PASSKEY_NOTIFY, | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | /* | 105 | /* |
@@ -3093,16 +3094,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) | |||
3093 | } | 3094 | } |
3094 | 3095 | ||
3095 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | 3096 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, |
3096 | u8 link_type, u8 addr_type) | 3097 | u8 link_type, u8 addr_type, u8 reason) |
3097 | { | 3098 | { |
3098 | struct mgmt_addr_info ev; | 3099 | struct mgmt_ev_device_disconnected ev; |
3099 | struct sock *sk = NULL; | 3100 | struct sock *sk = NULL; |
3100 | int err; | 3101 | int err; |
3101 | 3102 | ||
3102 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); | 3103 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); |
3103 | 3104 | ||
3104 | bacpy(&ev.bdaddr, bdaddr); | 3105 | bacpy(&ev.addr.bdaddr, bdaddr); |
3105 | ev.type = link_to_bdaddr(link_type, addr_type); | 3106 | ev.addr.type = link_to_bdaddr(link_type, addr_type); |
3107 | ev.reason = reason; | ||
3106 | 3108 | ||
3107 | err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), | 3109 | err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), |
3108 | sk); | 3110 | sk); |
@@ -3291,6 +3293,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
3291 | MGMT_OP_USER_PASSKEY_NEG_REPLY); | 3293 | MGMT_OP_USER_PASSKEY_NEG_REPLY); |
3292 | } | 3294 | } |
3293 | 3295 | ||
3296 | int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||
3297 | u8 link_type, u8 addr_type, u32 passkey, | ||
3298 | u8 entered) | ||
3299 | { | ||
3300 | struct mgmt_ev_passkey_notify ev; | ||
3301 | |||
3302 | BT_DBG("%s", hdev->name); | ||
3303 | |||
3304 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
3305 | ev.addr.type = link_to_bdaddr(link_type, addr_type); | ||
3306 | ev.passkey = __cpu_to_le32(passkey); | ||
3307 | ev.entered = entered; | ||
3308 | |||
3309 | return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL); | ||
3310 | } | ||
3311 | |||
3294 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 3312 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
3295 | u8 addr_type, u8 status) | 3313 | u8 addr_type, u8 status) |
3296 | { | 3314 | { |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d0deb3edae21..3195a6307f50 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -869,7 +869,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
869 | 869 | ||
870 | } else { | 870 | } else { |
871 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, | 871 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, |
872 | true); | 872 | false); |
873 | } | 873 | } |
874 | 874 | ||
875 | out: | 875 | out: |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03fe6d1cff42..05f3a313db88 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -20,7 +20,8 @@ | |||
20 | #include "rate.h" | 20 | #include "rate.h" |
21 | #include "mesh.h" | 21 | #include "mesh.h" |
22 | 22 | ||
23 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, | 23 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
24 | const char *name, | ||
24 | enum nl80211_iftype type, | 25 | enum nl80211_iftype type, |
25 | u32 *flags, | 26 | u32 *flags, |
26 | struct vif_params *params) | 27 | struct vif_params *params) |
@@ -170,6 +171,38 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
170 | } | 171 | } |
171 | } | 172 | } |
172 | 173 | ||
174 | switch (sdata->vif.type) { | ||
175 | case NL80211_IFTYPE_STATION: | ||
176 | if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED) | ||
177 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
178 | break; | ||
179 | case NL80211_IFTYPE_AP: | ||
180 | case NL80211_IFTYPE_AP_VLAN: | ||
181 | /* Keys without a station are used for TX only */ | ||
182 | if (key->sta && test_sta_flag(key->sta, WLAN_STA_MFP)) | ||
183 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
184 | break; | ||
185 | case NL80211_IFTYPE_ADHOC: | ||
186 | /* no MFP (yet) */ | ||
187 | break; | ||
188 | case NL80211_IFTYPE_MESH_POINT: | ||
189 | #ifdef CONFIG_MAC80211_MESH | ||
190 | if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | ||
191 | key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; | ||
192 | break; | ||
193 | #endif | ||
194 | case NL80211_IFTYPE_WDS: | ||
195 | case NL80211_IFTYPE_MONITOR: | ||
196 | case NL80211_IFTYPE_P2P_DEVICE: | ||
197 | case NL80211_IFTYPE_UNSPECIFIED: | ||
198 | case NUM_NL80211_IFTYPES: | ||
199 | case NL80211_IFTYPE_P2P_CLIENT: | ||
200 | case NL80211_IFTYPE_P2P_GO: | ||
201 | /* shouldn't happen */ | ||
202 | WARN_ON_ONCE(1); | ||
203 | break; | ||
204 | } | ||
205 | |||
173 | err = ieee80211_key_link(key, sdata, sta); | 206 | err = ieee80211_key_link(key, sdata, sta); |
174 | if (err) | 207 | if (err) |
175 | ieee80211_key_free(sdata->local, key); | 208 | ieee80211_key_free(sdata->local, key); |
@@ -2038,9 +2071,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
2038 | */ | 2071 | */ |
2039 | if (!sdata->u.mgd.associated || | 2072 | if (!sdata->u.mgd.associated || |
2040 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { | 2073 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { |
2041 | mutex_lock(&sdata->local->iflist_mtx); | ||
2042 | ieee80211_recalc_smps(sdata->local); | 2074 | ieee80211_recalc_smps(sdata->local); |
2043 | mutex_unlock(&sdata->local->iflist_mtx); | ||
2044 | return 0; | 2075 | return 0; |
2045 | } | 2076 | } |
2046 | 2077 | ||
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f0f87e5a1d35..0bfc914ddd15 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -68,16 +68,14 @@ ieee80211_get_channel_mode(struct ieee80211_local *local, | |||
68 | return mode; | 68 | return mode; |
69 | } | 69 | } |
70 | 70 | ||
71 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | 71 | static enum nl80211_channel_type |
72 | struct ieee80211_sub_if_data *sdata, | 72 | ieee80211_get_superchan(struct ieee80211_local *local, |
73 | enum nl80211_channel_type chantype) | 73 | struct ieee80211_sub_if_data *sdata) |
74 | { | 74 | { |
75 | struct ieee80211_sub_if_data *tmp; | ||
76 | enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; | 75 | enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; |
77 | bool result; | 76 | struct ieee80211_sub_if_data *tmp; |
78 | 77 | ||
79 | mutex_lock(&local->iflist_mtx); | 78 | mutex_lock(&local->iflist_mtx); |
80 | |||
81 | list_for_each_entry(tmp, &local->interfaces, list) { | 79 | list_for_each_entry(tmp, &local->interfaces, list) { |
82 | if (tmp == sdata) | 80 | if (tmp == sdata) |
83 | continue; | 81 | continue; |
@@ -103,39 +101,70 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, | |||
103 | break; | 101 | break; |
104 | } | 102 | } |
105 | } | 103 | } |
104 | mutex_unlock(&local->iflist_mtx); | ||
106 | 105 | ||
107 | switch (superchan) { | 106 | return superchan; |
107 | } | ||
108 | |||
109 | static bool | ||
110 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | ||
111 | enum nl80211_channel_type chantype2, | ||
112 | enum nl80211_channel_type *compat) | ||
113 | { | ||
114 | /* | ||
115 | * start out with chantype1 being the result, | ||
116 | * overwriting later if needed | ||
117 | */ | ||
118 | if (compat) | ||
119 | *compat = chantype1; | ||
120 | |||
121 | switch (chantype1) { | ||
108 | case NL80211_CHAN_NO_HT: | 122 | case NL80211_CHAN_NO_HT: |
123 | if (compat) | ||
124 | *compat = chantype2; | ||
125 | break; | ||
109 | case NL80211_CHAN_HT20: | 126 | case NL80211_CHAN_HT20: |
110 | /* | 127 | /* |
111 | * allow any change that doesn't go to no-HT | 128 | * allow any change that doesn't go to no-HT |
112 | * (if it already is no-HT no change is needed) | 129 | * (if it already is no-HT no change is needed) |
113 | */ | 130 | */ |
114 | if (chantype == NL80211_CHAN_NO_HT) | 131 | if (chantype2 == NL80211_CHAN_NO_HT) |
115 | break; | 132 | break; |
116 | superchan = chantype; | 133 | if (compat) |
134 | *compat = chantype2; | ||
117 | break; | 135 | break; |
118 | case NL80211_CHAN_HT40PLUS: | 136 | case NL80211_CHAN_HT40PLUS: |
119 | case NL80211_CHAN_HT40MINUS: | 137 | case NL80211_CHAN_HT40MINUS: |
120 | /* allow smaller bandwidth and same */ | 138 | /* allow smaller bandwidth and same */ |
121 | if (chantype == NL80211_CHAN_NO_HT) | 139 | if (chantype2 == NL80211_CHAN_NO_HT) |
122 | break; | 140 | break; |
123 | if (chantype == NL80211_CHAN_HT20) | 141 | if (chantype2 == NL80211_CHAN_HT20) |
124 | break; | 142 | break; |
125 | if (superchan == chantype) | 143 | if (chantype2 == chantype1) |
126 | break; | 144 | break; |
127 | result = false; | 145 | return false; |
128 | goto out; | ||
129 | } | 146 | } |
130 | 147 | ||
131 | local->_oper_channel_type = superchan; | 148 | return true; |
149 | } | ||
150 | |||
151 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | ||
152 | struct ieee80211_sub_if_data *sdata, | ||
153 | enum nl80211_channel_type chantype) | ||
154 | { | ||
155 | enum nl80211_channel_type superchan; | ||
156 | enum nl80211_channel_type compatchan; | ||
157 | |||
158 | superchan = ieee80211_get_superchan(local, sdata); | ||
159 | if (!ieee80211_channel_types_are_compatible(superchan, chantype, | ||
160 | &compatchan)) | ||
161 | return false; | ||
162 | |||
163 | local->_oper_channel_type = compatchan; | ||
132 | 164 | ||
133 | if (sdata) | 165 | if (sdata) |
134 | sdata->vif.bss_conf.channel_type = chantype; | 166 | sdata->vif.bss_conf.channel_type = chantype; |
135 | 167 | ||
136 | result = true; | 168 | return true; |
137 | out: | ||
138 | mutex_unlock(&local->iflist_mtx); | ||
139 | 169 | ||
140 | return result; | ||
141 | } | 170 | } |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 97173f8144d4..466f4b45dd94 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -70,6 +70,7 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", | |||
70 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", | 70 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", |
71 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); | 71 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); |
72 | 72 | ||
73 | #ifdef CONFIG_PM | ||
73 | static ssize_t reset_write(struct file *file, const char __user *user_buf, | 74 | static ssize_t reset_write(struct file *file, const char __user *user_buf, |
74 | size_t count, loff_t *ppos) | 75 | size_t count, loff_t *ppos) |
75 | { | 76 | { |
@@ -88,6 +89,7 @@ static const struct file_operations reset_ops = { | |||
88 | .open = simple_open, | 89 | .open = simple_open, |
89 | .llseek = noop_llseek, | 90 | .llseek = noop_llseek, |
90 | }; | 91 | }; |
92 | #endif | ||
91 | 93 | ||
92 | static ssize_t hwflags_read(struct file *file, char __user *user_buf, | 94 | static ssize_t hwflags_read(struct file *file, char __user *user_buf, |
93 | size_t count, loff_t *ppos) | 95 | size_t count, loff_t *ppos) |
@@ -245,7 +247,9 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
245 | DEBUGFS_ADD(total_ps_buffered); | 247 | DEBUGFS_ADD(total_ps_buffered); |
246 | DEBUGFS_ADD(wep_iv); | 248 | DEBUGFS_ADD(wep_iv); |
247 | DEBUGFS_ADD(queues); | 249 | DEBUGFS_ADD(queues); |
250 | #ifdef CONFIG_PM | ||
248 | DEBUGFS_ADD_MODE(reset, 0200); | 251 | DEBUGFS_ADD_MODE(reset, 0200); |
252 | #endif | ||
249 | DEBUGFS_ADD(hwflags); | 253 | DEBUGFS_ADD(hwflags); |
250 | DEBUGFS_ADD(user_power); | 254 | DEBUGFS_ADD(user_power); |
251 | DEBUGFS_ADD(power); | 255 | DEBUGFS_ADD(power); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a9d93285dba7..5f3620f0bc0a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -278,7 +278,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
278 | if (auth && !sdata->u.ibss.auth_frame_registrations) { | 278 | if (auth && !sdata->u.ibss.auth_frame_registrations) { |
279 | ibss_dbg(sdata, | 279 | ibss_dbg(sdata, |
280 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", | 280 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", |
281 | sdata->vif.addr, sdata->u.ibss.bssid, addr); | 281 | sdata->vif.addr, addr, sdata->u.ibss.bssid); |
282 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, | 282 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, |
283 | addr, sdata->u.ibss.bssid, NULL, 0, 0); | 283 | addr, sdata->u.ibss.bssid, NULL, 0, 0); |
284 | } | 284 | } |
@@ -332,11 +332,27 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
332 | return ieee80211_ibss_finish_sta(sta, auth); | 332 | return ieee80211_ibss_finish_sta(sta, auth); |
333 | } | 333 | } |
334 | 334 | ||
335 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | ||
336 | struct ieee80211_mgmt *mgmt, | ||
337 | size_t len) | ||
338 | { | ||
339 | u16 reason = le16_to_cpu(mgmt->u.deauth.reason_code); | ||
340 | |||
341 | if (len < IEEE80211_DEAUTH_FRAME_LEN) | ||
342 | return; | ||
343 | |||
344 | ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM BSSID=%pM (reason: %d)\n", | ||
345 | mgmt->sa, mgmt->da, mgmt->bssid, reason); | ||
346 | sta_info_destroy_addr(sdata, mgmt->sa); | ||
347 | } | ||
348 | |||
335 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | 349 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, |
336 | struct ieee80211_mgmt *mgmt, | 350 | struct ieee80211_mgmt *mgmt, |
337 | size_t len) | 351 | size_t len) |
338 | { | 352 | { |
339 | u16 auth_alg, auth_transaction; | 353 | u16 auth_alg, auth_transaction; |
354 | struct sta_info *sta; | ||
355 | u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
340 | 356 | ||
341 | lockdep_assert_held(&sdata->u.ibss.mtx); | 357 | lockdep_assert_held(&sdata->u.ibss.mtx); |
342 | 358 | ||
@@ -352,10 +368,22 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
352 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", | 368 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", |
353 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); | 369 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); |
354 | sta_info_destroy_addr(sdata, mgmt->sa); | 370 | sta_info_destroy_addr(sdata, mgmt->sa); |
355 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); | 371 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); |
356 | rcu_read_unlock(); | 372 | rcu_read_unlock(); |
357 | 373 | ||
358 | /* | 374 | /* |
375 | * if we have any problem in allocating the new station, we reply with a | ||
376 | * DEAUTH frame to tell the other end that we had a problem | ||
377 | */ | ||
378 | if (!sta) { | ||
379 | ieee80211_send_deauth_disassoc(sdata, sdata->u.ibss.bssid, | ||
380 | IEEE80211_STYPE_DEAUTH, | ||
381 | WLAN_REASON_UNSPECIFIED, true, | ||
382 | deauth_frame_buf); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | /* | ||
359 | * IEEE 802.11 standard does not require authentication in IBSS | 387 | * IEEE 802.11 standard does not require authentication in IBSS |
360 | * networks and most implementations do not seem to use it. | 388 | * networks and most implementations do not seem to use it. |
361 | * However, try to reply to authentication attempts if someone | 389 | * However, try to reply to authentication attempts if someone |
@@ -902,6 +930,9 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
902 | case IEEE80211_STYPE_AUTH: | 930 | case IEEE80211_STYPE_AUTH: |
903 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); | 931 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); |
904 | break; | 932 | break; |
933 | case IEEE80211_STYPE_DEAUTH: | ||
934 | ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len); | ||
935 | break; | ||
905 | } | 936 | } |
906 | 937 | ||
907 | mgmt_out: | 938 | mgmt_out: |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 204bfedba306..8c804550465b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -68,6 +68,8 @@ struct ieee80211_local; | |||
68 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ | 68 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ |
69 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL | 69 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL |
70 | 70 | ||
71 | #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) | ||
72 | |||
71 | struct ieee80211_fragment_entry { | 73 | struct ieee80211_fragment_entry { |
72 | unsigned long first_frag_time; | 74 | unsigned long first_frag_time; |
73 | unsigned int seq; | 75 | unsigned int seq; |
@@ -411,6 +413,7 @@ struct ieee80211_if_managed { | |||
411 | struct work_struct monitor_work; | 413 | struct work_struct monitor_work; |
412 | struct work_struct chswitch_work; | 414 | struct work_struct chswitch_work; |
413 | struct work_struct beacon_connection_loss_work; | 415 | struct work_struct beacon_connection_loss_work; |
416 | struct work_struct csa_connection_drop_work; | ||
414 | 417 | ||
415 | unsigned long beacon_timeout; | 418 | unsigned long beacon_timeout; |
416 | unsigned long probe_timeout; | 419 | unsigned long probe_timeout; |
@@ -970,7 +973,6 @@ struct ieee80211_local { | |||
970 | int scan_channel_idx; | 973 | int scan_channel_idx; |
971 | int scan_ies_len; | 974 | int scan_ies_len; |
972 | 975 | ||
973 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
974 | struct work_struct sched_scan_stopped_work; | 976 | struct work_struct sched_scan_stopped_work; |
975 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 977 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
976 | 978 | ||
@@ -1057,7 +1059,7 @@ struct ieee80211_local { | |||
1057 | bool disable_dynamic_ps; | 1059 | bool disable_dynamic_ps; |
1058 | 1060 | ||
1059 | int user_power_level; /* in dBm */ | 1061 | int user_power_level; /* in dBm */ |
1060 | int power_constr_level; /* in dBm */ | 1062 | int ap_power_level; /* in dBm */ |
1061 | 1063 | ||
1062 | enum ieee80211_smps_mode smps_mode; | 1064 | enum ieee80211_smps_mode smps_mode; |
1063 | 1065 | ||
@@ -1165,7 +1167,6 @@ struct ieee802_11_elems { | |||
1165 | u8 prep_len; | 1167 | u8 prep_len; |
1166 | u8 perr_len; | 1168 | u8 perr_len; |
1167 | u8 country_elem_len; | 1169 | u8 country_elem_len; |
1168 | u8 pwr_constr_elem_len; | ||
1169 | u8 quiet_elem_len; | 1170 | u8 quiet_elem_len; |
1170 | u8 num_of_quiet_elem; /* can be more the one */ | 1171 | u8 num_of_quiet_elem; /* can be more the one */ |
1171 | u8 timeout_int_len; | 1172 | u8 timeout_int_len; |
@@ -1367,7 +1368,6 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
1367 | int ieee80211_reconfig(struct ieee80211_local *local); | 1368 | int ieee80211_reconfig(struct ieee80211_local *local); |
1368 | void ieee80211_stop_device(struct ieee80211_local *local); | 1369 | void ieee80211_stop_device(struct ieee80211_local *local); |
1369 | 1370 | ||
1370 | #ifdef CONFIG_PM | ||
1371 | int __ieee80211_suspend(struct ieee80211_hw *hw, | 1371 | int __ieee80211_suspend(struct ieee80211_hw *hw, |
1372 | struct cfg80211_wowlan *wowlan); | 1372 | struct cfg80211_wowlan *wowlan); |
1373 | 1373 | ||
@@ -1381,18 +1381,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1381 | 1381 | ||
1382 | return ieee80211_reconfig(hw_to_local(hw)); | 1382 | return ieee80211_reconfig(hw_to_local(hw)); |
1383 | } | 1383 | } |
1384 | #else | ||
1385 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw, | ||
1386 | struct cfg80211_wowlan *wowlan) | ||
1387 | { | ||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | ||
1392 | { | ||
1393 | return 0; | ||
1394 | } | ||
1395 | #endif | ||
1396 | 1384 | ||
1397 | /* utility functions/constants */ | 1385 | /* utility functions/constants */ |
1398 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 1386 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
@@ -1459,6 +1447,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1459 | u16 transaction, u16 auth_alg, | 1447 | u16 transaction, u16 auth_alg, |
1460 | u8 *extra, size_t extra_len, const u8 *bssid, | 1448 | u8 *extra, size_t extra_len, const u8 *bssid, |
1461 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); | 1449 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); |
1450 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
1451 | const u8 *bssid, u16 stype, u16 reason, | ||
1452 | bool send_frame, u8 *frame_buf); | ||
1462 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1453 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1463 | const u8 *ie, size_t ie_len, | 1454 | const u8 *ie, size_t ie_len, |
1464 | enum ieee80211_band band, u32 rate_mask, | 1455 | enum ieee80211_band band, u32 rate_mask, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d747da541747..6f8a73c64fb3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -793,11 +793,20 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
793 | flush_work(&sdata->work); | 793 | flush_work(&sdata->work); |
794 | /* | 794 | /* |
795 | * When we get here, the interface is marked down. | 795 | * When we get here, the interface is marked down. |
796 | * Call synchronize_rcu() to wait for the RX path | 796 | * Call rcu_barrier() to wait both for the RX path |
797 | * should it be using the interface and enqueuing | 797 | * should it be using the interface and enqueuing |
798 | * frames at this very time on another CPU. | 798 | * frames at this very time on another CPU, and |
799 | * for the sta free call_rcu callbacks. | ||
799 | */ | 800 | */ |
800 | synchronize_rcu(); | 801 | rcu_barrier(); |
802 | |||
803 | /* | ||
804 | * free_sta_rcu() enqueues a work for the actual | ||
805 | * sta cleanup, so we need to flush it while | ||
806 | * sdata is still valid. | ||
807 | */ | ||
808 | flush_workqueue(local->workqueue); | ||
809 | |||
801 | skb_queue_purge(&sdata->skb_queue); | 810 | skb_queue_purge(&sdata->skb_queue); |
802 | 811 | ||
803 | /* | 812 | /* |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 7ae678ba5d67..d27e61aaa71b 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -402,7 +402,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
402 | * Synchronize so the TX path can no longer be using | 402 | * Synchronize so the TX path can no longer be using |
403 | * this key before we free/remove it. | 403 | * this key before we free/remove it. |
404 | */ | 404 | */ |
405 | synchronize_rcu(); | 405 | synchronize_net(); |
406 | 406 | ||
407 | if (key->local) | 407 | if (key->local) |
408 | ieee80211_key_disable_hw_accel(key); | 408 | ieee80211_key_disable_hw_accel(key); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bd7529363193..c80c4490351c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -150,13 +150,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
150 | 150 | ||
151 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || | 151 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || |
152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || | 152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || |
153 | test_bit(SCAN_HW_SCANNING, &local->scanning)) | 153 | test_bit(SCAN_HW_SCANNING, &local->scanning) || |
154 | !local->ap_power_level) | ||
154 | power = chan->max_power; | 155 | power = chan->max_power; |
155 | else | 156 | else |
156 | power = local->power_constr_level ? | 157 | power = min(chan->max_power, local->ap_power_level); |
157 | min(chan->max_power, | ||
158 | (chan->max_reg_power - local->power_constr_level)) : | ||
159 | chan->max_power; | ||
160 | 158 | ||
161 | if (local->user_power_level >= 0) | 159 | if (local->user_power_level >= 0) |
162 | power = min(power, local->user_power_level); | 160 | power = min(power, local->user_power_level); |
@@ -366,9 +364,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
366 | struct ieee80211_local *local = | 364 | struct ieee80211_local *local = |
367 | container_of(work, struct ieee80211_local, recalc_smps); | 365 | container_of(work, struct ieee80211_local, recalc_smps); |
368 | 366 | ||
369 | mutex_lock(&local->iflist_mtx); | ||
370 | ieee80211_recalc_smps(local); | 367 | ieee80211_recalc_smps(local); |
371 | mutex_unlock(&local->iflist_mtx); | ||
372 | } | 368 | } |
373 | 369 | ||
374 | #ifdef CONFIG_INET | 370 | #ifdef CONFIG_INET |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9d7ad366ef09..3ab34d816897 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -537,7 +537,8 @@ int mesh_plink_open(struct sta_info *sta) | |||
537 | spin_lock_bh(&sta->lock); | 537 | spin_lock_bh(&sta->lock); |
538 | get_random_bytes(&llid, 2); | 538 | get_random_bytes(&llid, 2); |
539 | sta->llid = llid; | 539 | sta->llid = llid; |
540 | if (sta->plink_state != NL80211_PLINK_LISTEN) { | 540 | if (sta->plink_state != NL80211_PLINK_LISTEN && |
541 | sta->plink_state != NL80211_PLINK_BLOCKED) { | ||
541 | spin_unlock_bh(&sta->lock); | 542 | spin_unlock_bh(&sta->lock); |
542 | return -EBUSY; | 543 | return -EBUSY; |
543 | } | 544 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5d77650d4363..e714ed8bb198 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -88,8 +88,6 @@ MODULE_PARM_DESC(probe_wait_ms, | |||
88 | #define TMR_RUNNING_TIMER 0 | 88 | #define TMR_RUNNING_TIMER 0 |
89 | #define TMR_RUNNING_CHANSW 1 | 89 | #define TMR_RUNNING_CHANSW 1 |
90 | 90 | ||
91 | #define DEAUTH_DISASSOC_LEN (24 /* hdr */ + 2 /* reason */) | ||
92 | |||
93 | /* | 91 | /* |
94 | * All cfg80211 functions have to be called outside a locked | 92 | * All cfg80211 functions have to be called outside a locked |
95 | * section so that they can acquire a lock themselves... This | 93 | * section so that they can acquire a lock themselves... This |
@@ -574,46 +572,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
574 | ieee80211_tx_skb(sdata, skb); | 572 | ieee80211_tx_skb(sdata, skb); |
575 | } | 573 | } |
576 | 574 | ||
577 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
578 | const u8 *bssid, u16 stype, | ||
579 | u16 reason, bool send_frame, | ||
580 | u8 *frame_buf) | ||
581 | { | ||
582 | struct ieee80211_local *local = sdata->local; | ||
583 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
584 | struct sk_buff *skb; | ||
585 | struct ieee80211_mgmt *mgmt = (void *)frame_buf; | ||
586 | |||
587 | /* build frame */ | ||
588 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
589 | mgmt->duration = 0; /* initialize only */ | ||
590 | mgmt->seq_ctrl = 0; /* initialize only */ | ||
591 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
592 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
593 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
594 | /* u.deauth.reason_code == u.disassoc.reason_code */ | ||
595 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
596 | |||
597 | if (send_frame) { | ||
598 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
599 | DEAUTH_DISASSOC_LEN); | ||
600 | if (!skb) | ||
601 | return; | ||
602 | |||
603 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
604 | |||
605 | /* copy in frame */ | ||
606 | memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN), | ||
607 | mgmt, DEAUTH_DISASSOC_LEN); | ||
608 | |||
609 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | ||
610 | IEEE80211_SKB_CB(skb)->flags |= | ||
611 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
612 | |||
613 | ieee80211_tx_skb(sdata, skb); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 575 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
618 | struct ieee80211_sub_if_data *sdata) | 576 | struct ieee80211_sub_if_data *sdata) |
619 | { | 577 | { |
@@ -730,16 +688,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | |||
730 | 688 | ||
731 | trace_api_chswitch_done(sdata, success); | 689 | trace_api_chswitch_done(sdata, success); |
732 | if (!success) { | 690 | if (!success) { |
733 | /* | 691 | sdata_info(sdata, |
734 | * If the channel switch was not successful, stay | 692 | "driver channel switch failed, disconnecting\n"); |
735 | * around on the old channel. We currently lack | 693 | ieee80211_queue_work(&sdata->local->hw, |
736 | * good handling of this situation, possibly we | 694 | &ifmgd->csa_connection_drop_work); |
737 | * should just drop the association. | 695 | } else { |
738 | */ | 696 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
739 | sdata->local->csa_channel = sdata->local->oper_channel; | ||
740 | } | 697 | } |
741 | |||
742 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
743 | } | 698 | } |
744 | EXPORT_SYMBOL(ieee80211_chswitch_done); | 699 | EXPORT_SYMBOL(ieee80211_chswitch_done); |
745 | 700 | ||
@@ -784,8 +739,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
784 | return; | 739 | return; |
785 | 740 | ||
786 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 741 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
787 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | 742 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { |
743 | sdata_info(sdata, | ||
744 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
745 | ifmgd->associated->bssid, new_freq); | ||
746 | ieee80211_queue_work(&sdata->local->hw, | ||
747 | &ifmgd->csa_connection_drop_work); | ||
788 | return; | 748 | return; |
749 | } | ||
789 | 750 | ||
790 | sdata->local->csa_channel = new_ch; | 751 | sdata->local->csa_channel = new_ch; |
791 | 752 | ||
@@ -818,23 +779,71 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
818 | } | 779 | } |
819 | 780 | ||
820 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 781 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
821 | u16 capab_info, u8 *pwr_constr_elem, | 782 | struct ieee80211_channel *channel, |
822 | u8 pwr_constr_elem_len) | 783 | const u8 *country_ie, u8 country_ie_len, |
784 | const u8 *pwr_constr_elem) | ||
823 | { | 785 | { |
824 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | 786 | struct ieee80211_country_ie_triplet *triplet; |
787 | int chan = ieee80211_frequency_to_channel(channel->center_freq); | ||
788 | int i, chan_pwr, chan_increment, new_ap_level; | ||
789 | bool have_chan_pwr = false; | ||
825 | 790 | ||
826 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | 791 | /* Invalid IE */ |
792 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | ||
827 | return; | 793 | return; |
828 | 794 | ||
829 | /* Power constraint IE length should be 1 octet */ | 795 | triplet = (void *)(country_ie + 3); |
830 | if (pwr_constr_elem_len != 1) | 796 | country_ie_len -= 3; |
831 | return; | ||
832 | 797 | ||
833 | if ((*pwr_constr_elem <= conf->channel->max_reg_power) && | 798 | switch (channel->band) { |
834 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | 799 | default: |
835 | sdata->local->power_constr_level = *pwr_constr_elem; | 800 | WARN_ON_ONCE(1); |
836 | ieee80211_hw_config(sdata->local, 0); | 801 | /* fall through */ |
802 | case IEEE80211_BAND_2GHZ: | ||
803 | case IEEE80211_BAND_60GHZ: | ||
804 | chan_increment = 1; | ||
805 | break; | ||
806 | case IEEE80211_BAND_5GHZ: | ||
807 | chan_increment = 4; | ||
808 | break; | ||
837 | } | 809 | } |
810 | |||
811 | /* find channel */ | ||
812 | while (country_ie_len >= 3) { | ||
813 | u8 first_channel = triplet->chans.first_channel; | ||
814 | |||
815 | if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID) | ||
816 | goto next; | ||
817 | |||
818 | for (i = 0; i < triplet->chans.num_channels; i++) { | ||
819 | if (first_channel + i * chan_increment == chan) { | ||
820 | have_chan_pwr = true; | ||
821 | chan_pwr = triplet->chans.max_power; | ||
822 | break; | ||
823 | } | ||
824 | } | ||
825 | if (have_chan_pwr) | ||
826 | break; | ||
827 | |||
828 | next: | ||
829 | triplet++; | ||
830 | country_ie_len -= 3; | ||
831 | } | ||
832 | |||
833 | if (!have_chan_pwr) | ||
834 | return; | ||
835 | |||
836 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); | ||
837 | |||
838 | if (sdata->local->ap_power_level == new_ap_level) | ||
839 | return; | ||
840 | |||
841 | sdata_info(sdata, | ||
842 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", | ||
843 | new_ap_level, chan_pwr, *pwr_constr_elem, | ||
844 | sdata->u.mgd.bssid); | ||
845 | sdata->local->ap_power_level = new_ap_level; | ||
846 | ieee80211_hw_config(sdata->local, 0); | ||
838 | } | 847 | } |
839 | 848 | ||
840 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 849 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) |
@@ -1339,9 +1348,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1339 | 1348 | ||
1340 | mutex_lock(&local->iflist_mtx); | 1349 | mutex_lock(&local->iflist_mtx); |
1341 | ieee80211_recalc_ps(local, -1); | 1350 | ieee80211_recalc_ps(local, -1); |
1342 | ieee80211_recalc_smps(local); | ||
1343 | mutex_unlock(&local->iflist_mtx); | 1351 | mutex_unlock(&local->iflist_mtx); |
1344 | 1352 | ||
1353 | ieee80211_recalc_smps(local); | ||
1345 | ieee80211_recalc_ps_vif(sdata); | 1354 | ieee80211_recalc_ps_vif(sdata); |
1346 | 1355 | ||
1347 | netif_tx_start_all_queues(sdata->dev); | 1356 | netif_tx_start_all_queues(sdata->dev); |
@@ -1390,7 +1399,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1390 | sta = sta_info_get(sdata, ifmgd->bssid); | 1399 | sta = sta_info_get(sdata, ifmgd->bssid); |
1391 | if (sta) { | 1400 | if (sta) { |
1392 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | 1401 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
1393 | ieee80211_sta_tear_down_BA_sessions(sta, tx); | 1402 | ieee80211_sta_tear_down_BA_sessions(sta, false); |
1394 | } | 1403 | } |
1395 | mutex_unlock(&local->sta_mtx); | 1404 | mutex_unlock(&local->sta_mtx); |
1396 | 1405 | ||
@@ -1438,7 +1447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1438 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1447 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1439 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1448 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1440 | 1449 | ||
1441 | local->power_constr_level = 0; | 1450 | local->ap_power_level = 0; |
1442 | 1451 | ||
1443 | del_timer_sync(&local->dynamic_ps_timer); | 1452 | del_timer_sync(&local->dynamic_ps_timer); |
1444 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1453 | cancel_work_sync(&local->dynamic_ps_enable_work); |
@@ -1692,11 +1701,12 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1692 | } | 1701 | } |
1693 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 1702 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
1694 | 1703 | ||
1695 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1704 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, |
1705 | bool transmit_frame) | ||
1696 | { | 1706 | { |
1697 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1707 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1698 | struct ieee80211_local *local = sdata->local; | 1708 | struct ieee80211_local *local = sdata->local; |
1699 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 1709 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
1700 | 1710 | ||
1701 | mutex_lock(&ifmgd->mtx); | 1711 | mutex_lock(&ifmgd->mtx); |
1702 | if (!ifmgd->associated) { | 1712 | if (!ifmgd->associated) { |
@@ -1704,19 +1714,17 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1704 | return; | 1714 | return; |
1705 | } | 1715 | } |
1706 | 1716 | ||
1707 | sdata_info(sdata, "Connection to AP %pM lost\n", | ||
1708 | ifmgd->associated->bssid); | ||
1709 | |||
1710 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 1717 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
1711 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1718 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1712 | false, frame_buf); | 1719 | transmit_frame, frame_buf); |
1720 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
1713 | mutex_unlock(&ifmgd->mtx); | 1721 | mutex_unlock(&ifmgd->mtx); |
1714 | 1722 | ||
1715 | /* | 1723 | /* |
1716 | * must be outside lock due to cfg80211, | 1724 | * must be outside lock due to cfg80211, |
1717 | * but that's not a problem. | 1725 | * but that's not a problem. |
1718 | */ | 1726 | */ |
1719 | cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 1727 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
1720 | 1728 | ||
1721 | mutex_lock(&local->mtx); | 1729 | mutex_lock(&local->mtx); |
1722 | ieee80211_recalc_idle(local); | 1730 | ieee80211_recalc_idle(local); |
@@ -1739,10 +1747,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | |||
1739 | rcu_read_unlock(); | 1747 | rcu_read_unlock(); |
1740 | } | 1748 | } |
1741 | 1749 | ||
1742 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1750 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { |
1743 | __ieee80211_connection_loss(sdata); | 1751 | sdata_info(sdata, "Connection to AP %pM lost\n", |
1744 | else | 1752 | ifmgd->bssid); |
1753 | __ieee80211_disconnect(sdata, false); | ||
1754 | } else { | ||
1745 | ieee80211_mgd_probe_ap(sdata, true); | 1755 | ieee80211_mgd_probe_ap(sdata, true); |
1756 | } | ||
1757 | } | ||
1758 | |||
1759 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | ||
1760 | { | ||
1761 | struct ieee80211_sub_if_data *sdata = | ||
1762 | container_of(work, struct ieee80211_sub_if_data, | ||
1763 | u.mgd.csa_connection_drop_work); | ||
1764 | |||
1765 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
1766 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1767 | __ieee80211_disconnect(sdata, true); | ||
1746 | } | 1768 | } |
1747 | 1769 | ||
1748 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1770 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -2530,15 +2552,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2530 | bssid, true); | 2552 | bssid, true); |
2531 | } | 2553 | } |
2532 | 2554 | ||
2533 | /* Note: country IE parsing is done for us by cfg80211 */ | 2555 | if (elems.country_elem && elems.pwr_constr_elem && |
2534 | if (elems.country_elem) { | 2556 | mgmt->u.probe_resp.capab_info & |
2535 | /* TODO: IBSS also needs this */ | 2557 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) |
2536 | if (elems.pwr_constr_elem) | 2558 | ieee80211_handle_pwr_constr(sdata, local->oper_channel, |
2537 | ieee80211_handle_pwr_constr(sdata, | 2559 | elems.country_elem, |
2538 | le16_to_cpu(mgmt->u.probe_resp.capab_info), | 2560 | elems.country_elem_len, |
2539 | elems.pwr_constr_elem, | 2561 | elems.pwr_constr_elem); |
2540 | elems.pwr_constr_elem_len); | ||
2541 | } | ||
2542 | 2562 | ||
2543 | ieee80211_bss_info_change_notify(sdata, changed); | 2563 | ieee80211_bss_info_change_notify(sdata, changed); |
2544 | } | 2564 | } |
@@ -2635,7 +2655,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2635 | { | 2655 | { |
2636 | struct ieee80211_local *local = sdata->local; | 2656 | struct ieee80211_local *local = sdata->local; |
2637 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2657 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2638 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 2658 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2639 | 2659 | ||
2640 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 2660 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
2641 | false, frame_buf); | 2661 | false, frame_buf); |
@@ -2645,7 +2665,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2645 | * must be outside lock due to cfg80211, | 2665 | * must be outside lock due to cfg80211, |
2646 | * but that's not a problem. | 2666 | * but that's not a problem. |
2647 | */ | 2667 | */ |
2648 | cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 2668 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
2649 | 2669 | ||
2650 | mutex_lock(&local->mtx); | 2670 | mutex_lock(&local->mtx); |
2651 | ieee80211_recalc_idle(local); | 2671 | ieee80211_recalc_idle(local); |
@@ -2929,6 +2949,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2929 | 2949 | ||
2930 | cancel_work_sync(&ifmgd->monitor_work); | 2950 | cancel_work_sync(&ifmgd->monitor_work); |
2931 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 2951 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
2952 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
2932 | if (del_timer_sync(&ifmgd->timer)) | 2953 | if (del_timer_sync(&ifmgd->timer)) |
2933 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 2954 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
2934 | 2955 | ||
@@ -2985,6 +3006,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2985 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 3006 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2986 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 3007 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
2987 | ieee80211_beacon_connection_loss_work); | 3008 | ieee80211_beacon_connection_loss_work); |
3009 | INIT_WORK(&ifmgd->csa_connection_drop_work, | ||
3010 | ieee80211_csa_connection_drop_work); | ||
2988 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); | 3011 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); |
2989 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3012 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2990 | (unsigned long) sdata); | 3013 | (unsigned long) sdata); |
@@ -3525,7 +3548,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3525 | struct cfg80211_deauth_request *req) | 3548 | struct cfg80211_deauth_request *req) |
3526 | { | 3549 | { |
3527 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3550 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3528 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 3551 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3529 | 3552 | ||
3530 | mutex_lock(&ifmgd->mtx); | 3553 | mutex_lock(&ifmgd->mtx); |
3531 | 3554 | ||
@@ -3553,7 +3576,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3553 | 3576 | ||
3554 | mutex_unlock(&ifmgd->mtx); | 3577 | mutex_unlock(&ifmgd->mtx); |
3555 | 3578 | ||
3556 | __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 3579 | __cfg80211_send_deauth(sdata->dev, frame_buf, |
3580 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3557 | 3581 | ||
3558 | mutex_lock(&sdata->local->mtx); | 3582 | mutex_lock(&sdata->local->mtx); |
3559 | ieee80211_recalc_idle(sdata->local); | 3583 | ieee80211_recalc_idle(sdata->local); |
@@ -3567,7 +3591,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
3567 | { | 3591 | { |
3568 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3592 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3569 | u8 bssid[ETH_ALEN]; | 3593 | u8 bssid[ETH_ALEN]; |
3570 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 3594 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3571 | 3595 | ||
3572 | mutex_lock(&ifmgd->mtx); | 3596 | mutex_lock(&ifmgd->mtx); |
3573 | 3597 | ||
@@ -3592,7 +3616,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
3592 | frame_buf); | 3616 | frame_buf); |
3593 | mutex_unlock(&ifmgd->mtx); | 3617 | mutex_unlock(&ifmgd->mtx); |
3594 | 3618 | ||
3595 | __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 3619 | __cfg80211_send_disassoc(sdata->dev, frame_buf, |
3620 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3596 | 3621 | ||
3597 | mutex_lock(&sdata->local->mtx); | 3622 | mutex_lock(&sdata->local->mtx); |
3598 | ieee80211_recalc_idle(sdata->local); | 3623 | ieee80211_recalc_idle(sdata->local); |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 507121dad082..83608ac16780 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -233,8 +233,7 @@ static void ieee80211_hw_roc_start(struct work_struct *work) | |||
233 | u32 dur = dep->duration; | 233 | u32 dur = dep->duration; |
234 | dep->duration = dur - roc->duration; | 234 | dep->duration = dur - roc->duration; |
235 | roc->duration = dur; | 235 | roc->duration = dur; |
236 | list_del(&dep->list); | 236 | list_move(&dep->list, &roc->list); |
237 | list_add(&dep->list, &roc->list); | ||
238 | } | 237 | } |
239 | } | 238 | } |
240 | out_unlock: | 239 | out_unlock: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 740e414d44f4..c4cdbde24fd3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -407,7 +407,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
407 | enum ieee80211_band band = local->hw.conf.channel->band; | 407 | enum ieee80211_band band = local->hw.conf.channel->band; |
408 | 408 | ||
409 | sdata = rcu_dereference_protected(local->scan_sdata, | 409 | sdata = rcu_dereference_protected(local->scan_sdata, |
410 | lockdep_is_held(&local->mtx));; | 410 | lockdep_is_held(&local->mtx)); |
411 | 411 | ||
412 | for (i = 0; i < local->scan_req->n_ssids; i++) | 412 | for (i = 0; i < local->scan_req->n_ssids; i++) |
413 | ieee80211_send_probe_req( | 413 | ieee80211_send_probe_req( |
@@ -917,6 +917,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
917 | struct cfg80211_sched_scan_request *req) | 917 | struct cfg80211_sched_scan_request *req) |
918 | { | 918 | { |
919 | struct ieee80211_local *local = sdata->local; | 919 | struct ieee80211_local *local = sdata->local; |
920 | struct ieee80211_sched_scan_ies sched_scan_ies; | ||
920 | int ret, i; | 921 | int ret, i; |
921 | 922 | ||
922 | mutex_lock(&local->mtx); | 923 | mutex_lock(&local->mtx); |
@@ -935,33 +936,28 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
935 | if (!local->hw.wiphy->bands[i]) | 936 | if (!local->hw.wiphy->bands[i]) |
936 | continue; | 937 | continue; |
937 | 938 | ||
938 | local->sched_scan_ies.ie[i] = kzalloc(2 + | 939 | sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + |
939 | IEEE80211_MAX_SSID_LEN + | 940 | local->scan_ies_len + |
940 | local->scan_ies_len + | 941 | req->ie_len, |
941 | req->ie_len, | 942 | GFP_KERNEL); |
942 | GFP_KERNEL); | 943 | if (!sched_scan_ies.ie[i]) { |
943 | if (!local->sched_scan_ies.ie[i]) { | ||
944 | ret = -ENOMEM; | 944 | ret = -ENOMEM; |
945 | goto out_free; | 945 | goto out_free; |
946 | } | 946 | } |
947 | 947 | ||
948 | local->sched_scan_ies.len[i] = | 948 | sched_scan_ies.len[i] = |
949 | ieee80211_build_preq_ies(local, | 949 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], |
950 | local->sched_scan_ies.ie[i], | ||
951 | req->ie, req->ie_len, i, | 950 | req->ie, req->ie_len, i, |
952 | (u32) -1, 0); | 951 | (u32) -1, 0); |
953 | } | 952 | } |
954 | 953 | ||
955 | ret = drv_sched_scan_start(local, sdata, req, | 954 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
956 | &local->sched_scan_ies); | 955 | if (ret == 0) |
957 | if (ret == 0) { | ||
958 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 956 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
959 | goto out; | ||
960 | } | ||
961 | 957 | ||
962 | out_free: | 958 | out_free: |
963 | while (i > 0) | 959 | while (i > 0) |
964 | kfree(local->sched_scan_ies.ie[--i]); | 960 | kfree(sched_scan_ies.ie[--i]); |
965 | out: | 961 | out: |
966 | mutex_unlock(&local->mtx); | 962 | mutex_unlock(&local->mtx); |
967 | return ret; | 963 | return ret; |
@@ -970,7 +966,7 @@ out: | |||
970 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | 966 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) |
971 | { | 967 | { |
972 | struct ieee80211_local *local = sdata->local; | 968 | struct ieee80211_local *local = sdata->local; |
973 | int ret = 0, i; | 969 | int ret = 0; |
974 | 970 | ||
975 | mutex_lock(&local->mtx); | 971 | mutex_lock(&local->mtx); |
976 | 972 | ||
@@ -979,12 +975,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
979 | goto out; | 975 | goto out; |
980 | } | 976 | } |
981 | 977 | ||
982 | if (rcu_access_pointer(local->sched_scan_sdata)) { | 978 | if (rcu_access_pointer(local->sched_scan_sdata)) |
983 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
984 | kfree(local->sched_scan_ies.ie[i]); | ||
985 | |||
986 | drv_sched_scan_stop(local, sdata); | 979 | drv_sched_scan_stop(local, sdata); |
987 | } | 980 | |
988 | out: | 981 | out: |
989 | mutex_unlock(&local->mtx); | 982 | mutex_unlock(&local->mtx); |
990 | 983 | ||
@@ -1006,7 +999,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
1006 | struct ieee80211_local *local = | 999 | struct ieee80211_local *local = |
1007 | container_of(work, struct ieee80211_local, | 1000 | container_of(work, struct ieee80211_local, |
1008 | sched_scan_stopped_work); | 1001 | sched_scan_stopped_work); |
1009 | int i; | ||
1010 | 1002 | ||
1011 | mutex_lock(&local->mtx); | 1003 | mutex_lock(&local->mtx); |
1012 | 1004 | ||
@@ -1015,9 +1007,6 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
1015 | return; | 1007 | return; |
1016 | } | 1008 | } |
1017 | 1009 | ||
1018 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
1019 | kfree(local->sched_scan_ies.ie[i]); | ||
1020 | |||
1021 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | 1010 | rcu_assign_pointer(local->sched_scan_sdata, NULL); |
1022 | 1011 | ||
1023 | mutex_unlock(&local->mtx); | 1012 | mutex_unlock(&local->mtx); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 06fa75ceb025..797dd36a220d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -91,6 +91,70 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
91 | return -ENOENT; | 91 | return -ENOENT; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void free_sta_work(struct work_struct *wk) | ||
95 | { | ||
96 | struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk); | ||
97 | int ac, i; | ||
98 | struct tid_ampdu_tx *tid_tx; | ||
99 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
100 | struct ieee80211_local *local = sdata->local; | ||
101 | |||
102 | /* | ||
103 | * At this point, when being called as call_rcu callback, | ||
104 | * neither mac80211 nor the driver can reference this | ||
105 | * sta struct any more except by still existing timers | ||
106 | * associated with this station that we clean up below. | ||
107 | */ | ||
108 | |||
109 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
110 | BUG_ON(!sdata->bss); | ||
111 | |||
112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
113 | |||
114 | atomic_dec(&sdata->bss->num_sta_ps); | ||
115 | sta_info_recalc_tim(sta); | ||
116 | } | ||
117 | |||
118 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
119 | local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); | ||
120 | __skb_queue_purge(&sta->ps_tx_buf[ac]); | ||
121 | __skb_queue_purge(&sta->tx_filtered[ac]); | ||
122 | } | ||
123 | |||
124 | #ifdef CONFIG_MAC80211_MESH | ||
125 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
126 | mesh_accept_plinks_update(sdata); | ||
127 | mesh_plink_deactivate(sta); | ||
128 | del_timer_sync(&sta->plink_timer); | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | cancel_work_sync(&sta->drv_unblock_wk); | ||
133 | |||
134 | /* | ||
135 | * Destroy aggregation state here. It would be nice to wait for the | ||
136 | * driver to finish aggregation stop and then clean up, but for now | ||
137 | * drivers have to handle aggregation stop being requested, followed | ||
138 | * directly by station destruction. | ||
139 | */ | ||
140 | for (i = 0; i < STA_TID_NUM; i++) { | ||
141 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | ||
142 | if (!tid_tx) | ||
143 | continue; | ||
144 | __skb_queue_purge(&tid_tx->pending); | ||
145 | kfree(tid_tx); | ||
146 | } | ||
147 | |||
148 | sta_info_free(local, sta); | ||
149 | } | ||
150 | |||
151 | static void free_sta_rcu(struct rcu_head *h) | ||
152 | { | ||
153 | struct sta_info *sta = container_of(h, struct sta_info, rcu_head); | ||
154 | |||
155 | ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk); | ||
156 | } | ||
157 | |||
94 | /* protected by RCU */ | 158 | /* protected by RCU */ |
95 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 159 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
96 | const u8 *addr) | 160 | const u8 *addr) |
@@ -241,6 +305,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
241 | 305 | ||
242 | spin_lock_init(&sta->lock); | 306 | spin_lock_init(&sta->lock); |
243 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 307 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
308 | INIT_WORK(&sta->free_sta_wk, free_sta_work); | ||
244 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 309 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
245 | mutex_init(&sta->ampdu_mlme.mtx); | 310 | mutex_init(&sta->ampdu_mlme.mtx); |
246 | 311 | ||
@@ -654,8 +719,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
654 | { | 719 | { |
655 | struct ieee80211_local *local; | 720 | struct ieee80211_local *local; |
656 | struct ieee80211_sub_if_data *sdata; | 721 | struct ieee80211_sub_if_data *sdata; |
657 | int ret, i, ac; | 722 | int ret, i; |
658 | struct tid_ampdu_tx *tid_tx; | ||
659 | 723 | ||
660 | might_sleep(); | 724 | might_sleep(); |
661 | 725 | ||
@@ -674,7 +738,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
674 | * will be sufficient. | 738 | * will be sufficient. |
675 | */ | 739 | */ |
676 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | 740 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
677 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 741 | ieee80211_sta_tear_down_BA_sessions(sta, false); |
678 | 742 | ||
679 | ret = sta_info_hash_del(local, sta); | 743 | ret = sta_info_hash_del(local, sta); |
680 | if (ret) | 744 | if (ret) |
@@ -711,65 +775,14 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
711 | WARN_ON_ONCE(ret != 0); | 775 | WARN_ON_ONCE(ret != 0); |
712 | } | 776 | } |
713 | 777 | ||
714 | /* | ||
715 | * At this point, after we wait for an RCU grace period, | ||
716 | * neither mac80211 nor the driver can reference this | ||
717 | * sta struct any more except by still existing timers | ||
718 | * associated with this station that we clean up below. | ||
719 | */ | ||
720 | synchronize_rcu(); | ||
721 | |||
722 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
723 | BUG_ON(!sdata->bss); | ||
724 | |||
725 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
726 | |||
727 | atomic_dec(&sdata->bss->num_sta_ps); | ||
728 | sta_info_recalc_tim(sta); | ||
729 | } | ||
730 | |||
731 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
732 | local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]); | ||
733 | __skb_queue_purge(&sta->ps_tx_buf[ac]); | ||
734 | __skb_queue_purge(&sta->tx_filtered[ac]); | ||
735 | } | ||
736 | |||
737 | #ifdef CONFIG_MAC80211_MESH | ||
738 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
739 | mesh_accept_plinks_update(sdata); | ||
740 | #endif | ||
741 | |||
742 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); | 778 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); |
743 | 779 | ||
744 | cancel_work_sync(&sta->drv_unblock_wk); | ||
745 | |||
746 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); | 780 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); |
747 | 781 | ||
748 | rate_control_remove_sta_debugfs(sta); | 782 | rate_control_remove_sta_debugfs(sta); |
749 | ieee80211_sta_debugfs_remove(sta); | 783 | ieee80211_sta_debugfs_remove(sta); |
750 | 784 | ||
751 | #ifdef CONFIG_MAC80211_MESH | 785 | call_rcu(&sta->rcu_head, free_sta_rcu); |
752 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
753 | mesh_plink_deactivate(sta); | ||
754 | del_timer_sync(&sta->plink_timer); | ||
755 | } | ||
756 | #endif | ||
757 | |||
758 | /* | ||
759 | * Destroy aggregation state here. It would be nice to wait for the | ||
760 | * driver to finish aggregation stop and then clean up, but for now | ||
761 | * drivers have to handle aggregation stop being requested, followed | ||
762 | * directly by station destruction. | ||
763 | */ | ||
764 | for (i = 0; i < STA_TID_NUM; i++) { | ||
765 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | ||
766 | if (!tid_tx) | ||
767 | continue; | ||
768 | __skb_queue_purge(&tid_tx->pending); | ||
769 | kfree(tid_tx); | ||
770 | } | ||
771 | |||
772 | sta_info_free(local, sta); | ||
773 | 786 | ||
774 | return 0; | 787 | return 0; |
775 | } | 788 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index a470e1123a55..c88f161f8118 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -287,6 +287,7 @@ struct sta_ampdu_mlme { | |||
287 | struct sta_info { | 287 | struct sta_info { |
288 | /* General information, mostly static */ | 288 | /* General information, mostly static */ |
289 | struct list_head list; | 289 | struct list_head list; |
290 | struct rcu_head rcu_head; | ||
290 | struct sta_info __rcu *hnext; | 291 | struct sta_info __rcu *hnext; |
291 | struct ieee80211_local *local; | 292 | struct ieee80211_local *local; |
292 | struct ieee80211_sub_if_data *sdata; | 293 | struct ieee80211_sub_if_data *sdata; |
@@ -297,6 +298,7 @@ struct sta_info { | |||
297 | spinlock_t lock; | 298 | spinlock_t lock; |
298 | 299 | ||
299 | struct work_struct drv_unblock_wk; | 300 | struct work_struct drv_unblock_wk; |
301 | struct work_struct free_sta_wk; | ||
300 | 302 | ||
301 | u16 listen_interval; | 303 | u16 listen_interval; |
302 | 304 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b0801b7d572d..2ce89732d0f2 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -517,29 +517,41 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
517 | 517 | ||
518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { |
519 | u64 cookie = (unsigned long)skb; | 519 | u64 cookie = (unsigned long)skb; |
520 | bool found = false; | ||
521 | |||
520 | acked = info->flags & IEEE80211_TX_STAT_ACK; | 522 | acked = info->flags & IEEE80211_TX_STAT_ACK; |
521 | 523 | ||
522 | if (ieee80211_is_nullfunc(hdr->frame_control) || | 524 | rcu_read_lock(); |
523 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 525 | |
524 | cfg80211_probe_status(skb->dev, hdr->addr1, | 526 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
525 | cookie, acked, GFP_ATOMIC); | 527 | if (!sdata->dev) |
526 | } else if (skb->dev) { | 528 | continue; |
527 | cfg80211_mgmt_tx_status( | ||
528 | skb->dev->ieee80211_ptr, cookie, skb->data, | ||
529 | skb->len, acked, GFP_ATOMIC); | ||
530 | } else { | ||
531 | struct ieee80211_sub_if_data *p2p_sdata; | ||
532 | 529 | ||
533 | rcu_read_lock(); | 530 | if (skb->dev != sdata->dev) |
531 | continue; | ||
534 | 532 | ||
535 | p2p_sdata = rcu_dereference(local->p2p_sdata); | 533 | found = true; |
536 | if (p2p_sdata) { | 534 | break; |
537 | cfg80211_mgmt_tx_status( | 535 | } |
538 | &p2p_sdata->wdev, cookie, skb->data, | 536 | |
539 | skb->len, acked, GFP_ATOMIC); | 537 | if (!skb->dev) { |
540 | } | 538 | sdata = rcu_dereference(local->p2p_sdata); |
541 | rcu_read_unlock(); | 539 | if (sdata) |
540 | found = true; | ||
541 | } | ||
542 | |||
543 | if (!found) | ||
544 | skb->dev = NULL; | ||
545 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
546 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
547 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
548 | cookie, acked, GFP_ATOMIC); | ||
549 | } else { | ||
550 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
551 | skb->len, acked, GFP_ATOMIC); | ||
542 | } | 552 | } |
553 | |||
554 | rcu_read_unlock(); | ||
543 | } | 555 | } |
544 | 556 | ||
545 | if (unlikely(info->ack_frame_id)) { | 557 | if (unlikely(info->ack_frame_id)) { |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 29eb4e678235..e0e0d1d0e830 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -580,7 +580,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
580 | tx->key = NULL; | 580 | tx->key = NULL; |
581 | else | 581 | else |
582 | skip_hw = (tx->key->conf.flags & | 582 | skip_hw = (tx->key->conf.flags & |
583 | IEEE80211_KEY_FLAG_SW_MGMT) && | 583 | IEEE80211_KEY_FLAG_SW_MGMT_TX) && |
584 | ieee80211_is_mgmt(hdr->frame_control); | 584 | ieee80211_is_mgmt(hdr->frame_control); |
585 | break; | 585 | break; |
586 | case WLAN_CIPHER_SUITE_AES_CMAC: | 586 | case WLAN_CIPHER_SUITE_AES_CMAC: |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 471fb0516c99..22ca35054dd0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -792,8 +792,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
792 | elems->country_elem_len = elen; | 792 | elems->country_elem_len = elen; |
793 | break; | 793 | break; |
794 | case WLAN_EID_PWR_CONSTRAINT: | 794 | case WLAN_EID_PWR_CONSTRAINT: |
795 | if (elen != 1) { | ||
796 | elem_parse_failed = true; | ||
797 | break; | ||
798 | } | ||
795 | elems->pwr_constr_elem = pos; | 799 | elems->pwr_constr_elem = pos; |
796 | elems->pwr_constr_elem_len = elen; | ||
797 | break; | 800 | break; |
798 | case WLAN_EID_TIMEOUT_INTERVAL: | 801 | case WLAN_EID_TIMEOUT_INTERVAL: |
799 | elems->timeout_int = pos; | 802 | elems->timeout_int = pos; |
@@ -1004,6 +1007,45 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
1004 | ieee80211_tx_skb(sdata, skb); | 1007 | ieee80211_tx_skb(sdata, skb); |
1005 | } | 1008 | } |
1006 | 1009 | ||
1010 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
1011 | const u8 *bssid, u16 stype, u16 reason, | ||
1012 | bool send_frame, u8 *frame_buf) | ||
1013 | { | ||
1014 | struct ieee80211_local *local = sdata->local; | ||
1015 | struct sk_buff *skb; | ||
1016 | struct ieee80211_mgmt *mgmt = (void *)frame_buf; | ||
1017 | |||
1018 | /* build frame */ | ||
1019 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
1020 | mgmt->duration = 0; /* initialize only */ | ||
1021 | mgmt->seq_ctrl = 0; /* initialize only */ | ||
1022 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
1023 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
1024 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
1025 | /* u.deauth.reason_code == u.disassoc.reason_code */ | ||
1026 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
1027 | |||
1028 | if (send_frame) { | ||
1029 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
1030 | IEEE80211_DEAUTH_FRAME_LEN); | ||
1031 | if (!skb) | ||
1032 | return; | ||
1033 | |||
1034 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1035 | |||
1036 | /* copy in frame */ | ||
1037 | memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN), | ||
1038 | mgmt, IEEE80211_DEAUTH_FRAME_LEN); | ||
1039 | |||
1040 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
1041 | !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED)) | ||
1042 | IEEE80211_SKB_CB(skb)->flags |= | ||
1043 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
1044 | |||
1045 | ieee80211_tx_skb(sdata, skb); | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1007 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1049 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1008 | const u8 *ie, size_t ie_len, | 1050 | const u8 *ie, size_t ie_len, |
1009 | enum ieee80211_band band, u32 rate_mask, | 1051 | enum ieee80211_band band, u32 rate_mask, |
@@ -1564,14 +1606,13 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | |||
1564 | return 0; | 1606 | return 0; |
1565 | } | 1607 | } |
1566 | 1608 | ||
1567 | /* must hold iflist_mtx */ | ||
1568 | void ieee80211_recalc_smps(struct ieee80211_local *local) | 1609 | void ieee80211_recalc_smps(struct ieee80211_local *local) |
1569 | { | 1610 | { |
1570 | struct ieee80211_sub_if_data *sdata; | 1611 | struct ieee80211_sub_if_data *sdata; |
1571 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | 1612 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; |
1572 | int count = 0; | 1613 | int count = 0; |
1573 | 1614 | ||
1574 | lockdep_assert_held(&local->iflist_mtx); | 1615 | mutex_lock(&local->iflist_mtx); |
1575 | 1616 | ||
1576 | /* | 1617 | /* |
1577 | * This function could be improved to handle multiple | 1618 | * This function could be improved to handle multiple |
@@ -1600,12 +1641,14 @@ void ieee80211_recalc_smps(struct ieee80211_local *local) | |||
1600 | } | 1641 | } |
1601 | 1642 | ||
1602 | if (smps_mode == local->smps_mode) | 1643 | if (smps_mode == local->smps_mode) |
1603 | return; | 1644 | goto unlock; |
1604 | 1645 | ||
1605 | set: | 1646 | set: |
1606 | local->smps_mode = smps_mode; | 1647 | local->smps_mode = smps_mode; |
1607 | /* changed flag is auto-detected for this */ | 1648 | /* changed flag is auto-detected for this */ |
1608 | ieee80211_hw_config(local, 0); | 1649 | ieee80211_hw_config(local, 0); |
1650 | unlock: | ||
1651 | mutex_unlock(&local->iflist_mtx); | ||
1609 | } | 1652 | } |
1610 | 1653 | ||
1611 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | 1654 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) |
diff --git a/net/nfc/core.c b/net/nfc/core.c index ff749794bc5b..c9eacc1f145f 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -679,7 +679,7 @@ static void nfc_release(struct device *d) | |||
679 | 679 | ||
680 | if (dev->ops->check_presence) { | 680 | if (dev->ops->check_presence) { |
681 | del_timer_sync(&dev->check_pres_timer); | 681 | del_timer_sync(&dev->check_pres_timer); |
682 | destroy_workqueue(dev->check_pres_wq); | 682 | cancel_work_sync(&dev->check_pres_work); |
683 | } | 683 | } |
684 | 684 | ||
685 | nfc_genl_data_exit(&dev->genl_data); | 685 | nfc_genl_data_exit(&dev->genl_data); |
@@ -715,7 +715,7 @@ static void nfc_check_pres_timeout(unsigned long data) | |||
715 | { | 715 | { |
716 | struct nfc_dev *dev = (struct nfc_dev *)data; | 716 | struct nfc_dev *dev = (struct nfc_dev *)data; |
717 | 717 | ||
718 | queue_work(dev->check_pres_wq, &dev->check_pres_work); | 718 | queue_work(system_nrt_wq, &dev->check_pres_work); |
719 | } | 719 | } |
720 | 720 | ||
721 | struct class nfc_class = { | 721 | struct class nfc_class = { |
@@ -784,20 +784,11 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
784 | dev->targets_generation = 1; | 784 | dev->targets_generation = 1; |
785 | 785 | ||
786 | if (ops->check_presence) { | 786 | if (ops->check_presence) { |
787 | char name[32]; | ||
788 | init_timer(&dev->check_pres_timer); | 787 | init_timer(&dev->check_pres_timer); |
789 | dev->check_pres_timer.data = (unsigned long)dev; | 788 | dev->check_pres_timer.data = (unsigned long)dev; |
790 | dev->check_pres_timer.function = nfc_check_pres_timeout; | 789 | dev->check_pres_timer.function = nfc_check_pres_timeout; |
791 | 790 | ||
792 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); | 791 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); |
793 | snprintf(name, sizeof(name), "nfc%d_check_pres_wq", dev->idx); | ||
794 | dev->check_pres_wq = alloc_workqueue(name, WQ_NON_REENTRANT | | ||
795 | WQ_UNBOUND | | ||
796 | WQ_MEM_RECLAIM, 1); | ||
797 | if (dev->check_pres_wq == NULL) { | ||
798 | kfree(dev); | ||
799 | return NULL; | ||
800 | } | ||
801 | } | 792 | } |
802 | 793 | ||
803 | return dev; | 794 | return dev; |
diff --git a/net/nfc/hci/Makefile b/net/nfc/hci/Makefile index f9c44b2fb065..c5dbb6891b24 100644 --- a/net/nfc/hci/Makefile +++ b/net/nfc/hci/Makefile | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_NFC_HCI) += hci.o | 5 | obj-$(CONFIG_NFC_HCI) += hci.o |
6 | 6 | ||
7 | hci-y := core.o hcp.o command.o | 7 | hci-y := core.o hcp.o command.o llc.o llc_nop.o |
8 | hci-$(CONFIG_NFC_SHDLC) += shdlc.o | 8 | hci-$(CONFIG_NFC_SHDLC) += llc_shdlc.o |
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 46362ef979db..71c6a7086b8f 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
@@ -28,10 +28,29 @@ | |||
28 | 28 | ||
29 | #include "hci.h" | 29 | #include "hci.h" |
30 | 30 | ||
31 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, | 31 | static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, |
32 | struct sk_buff *skb, void *cb_data) | 32 | const u8 *param, size_t param_len, |
33 | data_exchange_cb_t cb, void *cb_context) | ||
33 | { | 34 | { |
34 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; | 35 | pr_debug("exec cmd async through pipe=%d, cmd=%d, plen=%zd\n", pipe, |
36 | cmd, param_len); | ||
37 | |||
38 | /* TODO: Define hci cmd execution delay. Should it be the same | ||
39 | * for all commands? | ||
40 | */ | ||
41 | return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_COMMAND, cmd, | ||
42 | param, param_len, cb, cb_context, 3000); | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * HCI command execution completion callback. | ||
47 | * err will be a standard linux error (may be converted from HCI response) | ||
48 | * skb contains the response data and must be disposed, or may be NULL if | ||
49 | * an error occured | ||
50 | */ | ||
51 | static void nfc_hci_execute_cb(void *context, struct sk_buff *skb, int err) | ||
52 | { | ||
53 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)context; | ||
35 | 54 | ||
36 | pr_debug("HCI Cmd completed with result=%d\n", err); | 55 | pr_debug("HCI Cmd completed with result=%d\n", err); |
37 | 56 | ||
@@ -55,7 +74,8 @@ static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, | |||
55 | hcp_ew.exec_complete = false; | 74 | hcp_ew.exec_complete = false; |
56 | hcp_ew.result_skb = NULL; | 75 | hcp_ew.result_skb = NULL; |
57 | 76 | ||
58 | pr_debug("through pipe=%d, cmd=%d, plen=%zd\n", pipe, cmd, param_len); | 77 | pr_debug("exec cmd sync through pipe=%d, cmd=%d, plen=%zd\n", pipe, |
78 | cmd, param_len); | ||
59 | 79 | ||
60 | /* TODO: Define hci cmd execution delay. Should it be the same | 80 | /* TODO: Define hci cmd execution delay. Should it be the same |
61 | * for all commands? | 81 | * for all commands? |
@@ -133,6 +153,23 @@ int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | |||
133 | } | 153 | } |
134 | EXPORT_SYMBOL(nfc_hci_send_cmd); | 154 | EXPORT_SYMBOL(nfc_hci_send_cmd); |
135 | 155 | ||
156 | int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, | ||
157 | const u8 *param, size_t param_len, | ||
158 | data_exchange_cb_t cb, void *cb_context) | ||
159 | { | ||
160 | u8 pipe; | ||
161 | |||
162 | pr_debug("\n"); | ||
163 | |||
164 | pipe = hdev->gate2pipe[gate]; | ||
165 | if (pipe == NFC_HCI_INVALID_PIPE) | ||
166 | return -EADDRNOTAVAIL; | ||
167 | |||
168 | return nfc_hci_execute_cmd_async(hdev, pipe, cmd, param, param_len, | ||
169 | cb, cb_context); | ||
170 | } | ||
171 | EXPORT_SYMBOL(nfc_hci_send_cmd_async); | ||
172 | |||
136 | int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, | 173 | int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, |
137 | const u8 *param, size_t param_len) | 174 | const u8 *param, size_t param_len) |
138 | { | 175 | { |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 1ac7b3fac6c9..d378d93de62e 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <net/nfc/nfc.h> | 27 | #include <net/nfc/nfc.h> |
28 | #include <net/nfc/hci.h> | 28 | #include <net/nfc/hci.h> |
29 | #include <net/nfc/llc.h> | ||
29 | 30 | ||
30 | #include "hci.h" | 31 | #include "hci.h" |
31 | 32 | ||
@@ -57,12 +58,11 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) | |||
57 | if (hdev->cmd_pending_msg) { | 58 | if (hdev->cmd_pending_msg) { |
58 | if (timer_pending(&hdev->cmd_timer) == 0) { | 59 | if (timer_pending(&hdev->cmd_timer) == 0) { |
59 | if (hdev->cmd_pending_msg->cb) | 60 | if (hdev->cmd_pending_msg->cb) |
60 | hdev->cmd_pending_msg->cb(hdev, | 61 | hdev->cmd_pending_msg->cb(hdev-> |
61 | -ETIME, | ||
62 | NULL, | ||
63 | hdev-> | ||
64 | cmd_pending_msg-> | 62 | cmd_pending_msg-> |
65 | cb_context); | 63 | cb_context, |
64 | NULL, | ||
65 | -ETIME); | ||
66 | kfree(hdev->cmd_pending_msg); | 66 | kfree(hdev->cmd_pending_msg); |
67 | hdev->cmd_pending_msg = NULL; | 67 | hdev->cmd_pending_msg = NULL; |
68 | } else | 68 | } else |
@@ -78,12 +78,12 @@ next_msg: | |||
78 | 78 | ||
79 | pr_debug("msg_tx_queue has a cmd to send\n"); | 79 | pr_debug("msg_tx_queue has a cmd to send\n"); |
80 | while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { | 80 | while ((skb = skb_dequeue(&msg->msg_frags)) != NULL) { |
81 | r = hdev->ops->xmit(hdev, skb); | 81 | r = nfc_llc_xmit_from_hci(hdev->llc, skb); |
82 | if (r < 0) { | 82 | if (r < 0) { |
83 | kfree_skb(skb); | 83 | kfree_skb(skb); |
84 | skb_queue_purge(&msg->msg_frags); | 84 | skb_queue_purge(&msg->msg_frags); |
85 | if (msg->cb) | 85 | if (msg->cb) |
86 | msg->cb(hdev, r, NULL, msg->cb_context); | 86 | msg->cb(msg->cb_context, NULL, r); |
87 | kfree(msg); | 87 | kfree(msg); |
88 | break; | 88 | break; |
89 | } | 89 | } |
@@ -133,15 +133,15 @@ static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, | |||
133 | del_timer_sync(&hdev->cmd_timer); | 133 | del_timer_sync(&hdev->cmd_timer); |
134 | 134 | ||
135 | if (hdev->cmd_pending_msg->cb) | 135 | if (hdev->cmd_pending_msg->cb) |
136 | hdev->cmd_pending_msg->cb(hdev, err, skb, | 136 | hdev->cmd_pending_msg->cb(hdev->cmd_pending_msg->cb_context, |
137 | hdev->cmd_pending_msg->cb_context); | 137 | skb, err); |
138 | else | 138 | else |
139 | kfree_skb(skb); | 139 | kfree_skb(skb); |
140 | 140 | ||
141 | kfree(hdev->cmd_pending_msg); | 141 | kfree(hdev->cmd_pending_msg); |
142 | hdev->cmd_pending_msg = NULL; | 142 | hdev->cmd_pending_msg = NULL; |
143 | 143 | ||
144 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 144 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
145 | } | 145 | } |
146 | 146 | ||
147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | 147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, |
@@ -326,7 +326,7 @@ static void nfc_hci_cmd_timeout(unsigned long data) | |||
326 | { | 326 | { |
327 | struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; | 327 | struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; |
328 | 328 | ||
329 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 329 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
330 | } | 330 | } |
331 | 331 | ||
332 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, | 332 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, |
@@ -398,8 +398,7 @@ disconnect_all: | |||
398 | nfc_hci_disconnect_all_gates(hdev); | 398 | nfc_hci_disconnect_all_gates(hdev); |
399 | 399 | ||
400 | exit: | 400 | exit: |
401 | if (skb) | 401 | kfree_skb(skb); |
402 | kfree_skb(skb); | ||
403 | 402 | ||
404 | return r; | 403 | return r; |
405 | } | 404 | } |
@@ -470,29 +469,38 @@ static int hci_dev_up(struct nfc_dev *nfc_dev) | |||
470 | return r; | 469 | return r; |
471 | } | 470 | } |
472 | 471 | ||
472 | r = nfc_llc_start(hdev->llc); | ||
473 | if (r < 0) | ||
474 | goto exit_close; | ||
475 | |||
473 | r = hci_dev_session_init(hdev); | 476 | r = hci_dev_session_init(hdev); |
474 | if (r < 0) | 477 | if (r < 0) |
475 | goto exit; | 478 | goto exit_llc; |
476 | 479 | ||
477 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | 480 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, |
478 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | 481 | NFC_HCI_EVT_END_OPERATION, NULL, 0); |
479 | if (r < 0) | 482 | if (r < 0) |
480 | goto exit; | 483 | goto exit_llc; |
481 | 484 | ||
482 | if (hdev->ops->hci_ready) { | 485 | if (hdev->ops->hci_ready) { |
483 | r = hdev->ops->hci_ready(hdev); | 486 | r = hdev->ops->hci_ready(hdev); |
484 | if (r < 0) | 487 | if (r < 0) |
485 | goto exit; | 488 | goto exit_llc; |
486 | } | 489 | } |
487 | 490 | ||
488 | r = hci_dev_version(hdev); | 491 | r = hci_dev_version(hdev); |
489 | if (r < 0) | 492 | if (r < 0) |
490 | goto exit; | 493 | goto exit_llc; |
494 | |||
495 | return 0; | ||
496 | |||
497 | exit_llc: | ||
498 | nfc_llc_stop(hdev->llc); | ||
499 | |||
500 | exit_close: | ||
501 | if (hdev->ops->close) | ||
502 | hdev->ops->close(hdev); | ||
491 | 503 | ||
492 | exit: | ||
493 | if (r < 0) | ||
494 | if (hdev->ops->close) | ||
495 | hdev->ops->close(hdev); | ||
496 | return r; | 504 | return r; |
497 | } | 505 | } |
498 | 506 | ||
@@ -500,6 +508,8 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) | |||
500 | { | 508 | { |
501 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 509 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
502 | 510 | ||
511 | nfc_llc_stop(hdev->llc); | ||
512 | |||
503 | if (hdev->ops->close) | 513 | if (hdev->ops->close) |
504 | hdev->ops->close(hdev); | 514 | hdev->ops->close(hdev); |
505 | 515 | ||
@@ -539,13 +549,37 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev, | |||
539 | { | 549 | { |
540 | } | 550 | } |
541 | 551 | ||
552 | #define HCI_CB_TYPE_TRANSCEIVE 1 | ||
553 | |||
554 | static void hci_transceive_cb(void *context, struct sk_buff *skb, int err) | ||
555 | { | ||
556 | struct nfc_hci_dev *hdev = context; | ||
557 | |||
558 | switch (hdev->async_cb_type) { | ||
559 | case HCI_CB_TYPE_TRANSCEIVE: | ||
560 | /* | ||
561 | * TODO: Check RF Error indicator to make sure data is valid. | ||
562 | * It seems that HCI cmd can complete without error, but data | ||
563 | * can be invalid if an RF error occured? Ignore for now. | ||
564 | */ | ||
565 | if (err == 0) | ||
566 | skb_trim(skb, skb->len - 1); /* RF Err ind */ | ||
567 | |||
568 | hdev->async_cb(hdev->async_cb_context, skb, err); | ||
569 | break; | ||
570 | default: | ||
571 | if (err == 0) | ||
572 | kfree_skb(skb); | ||
573 | break; | ||
574 | } | ||
575 | } | ||
576 | |||
542 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 577 | static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
543 | struct sk_buff *skb, data_exchange_cb_t cb, | 578 | struct sk_buff *skb, data_exchange_cb_t cb, |
544 | void *cb_context) | 579 | void *cb_context) |
545 | { | 580 | { |
546 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 581 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
547 | int r; | 582 | int r; |
548 | struct sk_buff *res_skb = NULL; | ||
549 | 583 | ||
550 | pr_debug("target_idx=%d\n", target->idx); | 584 | pr_debug("target_idx=%d\n", target->idx); |
551 | 585 | ||
@@ -553,40 +587,37 @@ static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
553 | case NFC_HCI_RF_READER_A_GATE: | 587 | case NFC_HCI_RF_READER_A_GATE: |
554 | case NFC_HCI_RF_READER_B_GATE: | 588 | case NFC_HCI_RF_READER_B_GATE: |
555 | if (hdev->ops->data_exchange) { | 589 | if (hdev->ops->data_exchange) { |
556 | r = hdev->ops->data_exchange(hdev, target, skb, | 590 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
557 | &res_skb); | 591 | cb_context); |
558 | if (r <= 0) /* handled */ | 592 | if (r <= 0) /* handled */ |
559 | break; | 593 | break; |
560 | } | 594 | } |
561 | 595 | ||
562 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ | 596 | *skb_push(skb, 1) = 0; /* CTR, see spec:10.2.2.1 */ |
563 | r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, | 597 | |
564 | NFC_HCI_WR_XCHG_DATA, | 598 | hdev->async_cb_type = HCI_CB_TYPE_TRANSCEIVE; |
565 | skb->data, skb->len, &res_skb); | 599 | hdev->async_cb = cb; |
566 | /* | 600 | hdev->async_cb_context = cb_context; |
567 | * TODO: Check RF Error indicator to make sure data is valid. | 601 | |
568 | * It seems that HCI cmd can complete without error, but data | 602 | r = nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
569 | * can be invalid if an RF error occured? Ignore for now. | 603 | NFC_HCI_WR_XCHG_DATA, skb->data, |
570 | */ | 604 | skb->len, hci_transceive_cb, hdev); |
571 | if (r == 0) | ||
572 | skb_trim(res_skb, res_skb->len - 1); /* RF Err ind */ | ||
573 | break; | 605 | break; |
574 | default: | 606 | default: |
575 | if (hdev->ops->data_exchange) { | 607 | if (hdev->ops->data_exchange) { |
576 | r = hdev->ops->data_exchange(hdev, target, skb, | 608 | r = hdev->ops->data_exchange(hdev, target, skb, cb, |
577 | &res_skb); | 609 | cb_context); |
578 | if (r == 1) | 610 | if (r == 1) |
579 | r = -ENOTSUPP; | 611 | r = -ENOTSUPP; |
580 | } | 612 | } |
581 | else | 613 | else |
582 | r = -ENOTSUPP; | 614 | r = -ENOTSUPP; |
615 | break; | ||
583 | } | 616 | } |
584 | 617 | ||
585 | kfree_skb(skb); | 618 | kfree_skb(skb); |
586 | 619 | ||
587 | cb(cb_context, res_skb, r); | 620 | return r; |
588 | |||
589 | return 0; | ||
590 | } | 621 | } |
591 | 622 | ||
592 | static int hci_check_presence(struct nfc_dev *nfc_dev, | 623 | static int hci_check_presence(struct nfc_dev *nfc_dev, |
@@ -600,6 +631,93 @@ static int hci_check_presence(struct nfc_dev *nfc_dev, | |||
600 | return 0; | 631 | return 0; |
601 | } | 632 | } |
602 | 633 | ||
634 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
635 | { | ||
636 | mutex_lock(&hdev->msg_tx_mutex); | ||
637 | |||
638 | if (hdev->cmd_pending_msg == NULL) { | ||
639 | nfc_driver_failure(hdev->ndev, err); | ||
640 | goto exit; | ||
641 | } | ||
642 | |||
643 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
644 | |||
645 | exit: | ||
646 | mutex_unlock(&hdev->msg_tx_mutex); | ||
647 | } | ||
648 | |||
649 | static void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err) | ||
650 | { | ||
651 | nfc_hci_failure(hdev, err); | ||
652 | } | ||
653 | |||
654 | static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
655 | { | ||
656 | struct hcp_packet *packet; | ||
657 | u8 type; | ||
658 | u8 instruction; | ||
659 | struct sk_buff *hcp_skb; | ||
660 | u8 pipe; | ||
661 | struct sk_buff *frag_skb; | ||
662 | int msg_len; | ||
663 | |||
664 | packet = (struct hcp_packet *)skb->data; | ||
665 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | ||
666 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | /* it's the last fragment. Does it need re-aggregation? */ | ||
671 | if (skb_queue_len(&hdev->rx_hcp_frags)) { | ||
672 | pipe = packet->header & NFC_HCI_FRAGMENT; | ||
673 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
674 | |||
675 | msg_len = 0; | ||
676 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
677 | msg_len += (frag_skb->len - | ||
678 | NFC_HCI_HCP_PACKET_HEADER_LEN); | ||
679 | } | ||
680 | |||
681 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
682 | msg_len, GFP_KERNEL); | ||
683 | if (hcp_skb == NULL) { | ||
684 | nfc_hci_failure(hdev, -ENOMEM); | ||
685 | return; | ||
686 | } | ||
687 | |||
688 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | ||
689 | |||
690 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
691 | msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; | ||
692 | memcpy(skb_put(hcp_skb, msg_len), | ||
693 | frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, | ||
694 | msg_len); | ||
695 | } | ||
696 | |||
697 | skb_queue_purge(&hdev->rx_hcp_frags); | ||
698 | } else { | ||
699 | packet->header &= NFC_HCI_FRAGMENT; | ||
700 | hcp_skb = skb; | ||
701 | } | ||
702 | |||
703 | /* if this is a response, dispatch immediately to | ||
704 | * unblock waiting cmd context. Otherwise, enqueue to dispatch | ||
705 | * in separate context where handler can also execute command. | ||
706 | */ | ||
707 | packet = (struct hcp_packet *)hcp_skb->data; | ||
708 | type = HCP_MSG_GET_TYPE(packet->message.header); | ||
709 | if (type == NFC_HCI_HCP_RESPONSE) { | ||
710 | pipe = packet->header; | ||
711 | instruction = HCP_MSG_GET_CMD(packet->message.header); | ||
712 | skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
713 | NFC_HCI_HCP_MESSAGE_HEADER_LEN); | ||
714 | nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); | ||
715 | } else { | ||
716 | skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); | ||
717 | queue_work(system_nrt_wq, &hdev->msg_rx_work); | ||
718 | } | ||
719 | } | ||
720 | |||
603 | static struct nfc_ops hci_nfc_ops = { | 721 | static struct nfc_ops hci_nfc_ops = { |
604 | .dev_up = hci_dev_up, | 722 | .dev_up = hci_dev_up, |
605 | .dev_down = hci_dev_down, | 723 | .dev_down = hci_dev_down, |
@@ -614,6 +732,7 @@ static struct nfc_ops hci_nfc_ops = { | |||
614 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | 732 | struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, |
615 | struct nfc_hci_init_data *init_data, | 733 | struct nfc_hci_init_data *init_data, |
616 | u32 protocols, | 734 | u32 protocols, |
735 | const char *llc_name, | ||
617 | int tx_headroom, | 736 | int tx_headroom, |
618 | int tx_tailroom, | 737 | int tx_tailroom, |
619 | int max_link_payload) | 738 | int max_link_payload) |
@@ -630,10 +749,19 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, | |||
630 | if (hdev == NULL) | 749 | if (hdev == NULL) |
631 | return NULL; | 750 | return NULL; |
632 | 751 | ||
752 | hdev->llc = nfc_llc_allocate(llc_name, hdev, ops->xmit, | ||
753 | nfc_hci_recv_from_llc, tx_headroom, | ||
754 | tx_tailroom, nfc_hci_llc_failure); | ||
755 | if (hdev->llc == NULL) { | ||
756 | kfree(hdev); | ||
757 | return NULL; | ||
758 | } | ||
759 | |||
633 | hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, | 760 | hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, |
634 | tx_headroom + HCI_CMDS_HEADROOM, | 761 | tx_headroom + HCI_CMDS_HEADROOM, |
635 | tx_tailroom); | 762 | tx_tailroom); |
636 | if (!hdev->ndev) { | 763 | if (!hdev->ndev) { |
764 | nfc_llc_free(hdev->llc); | ||
637 | kfree(hdev); | 765 | kfree(hdev); |
638 | return NULL; | 766 | return NULL; |
639 | } | 767 | } |
@@ -653,29 +781,18 @@ EXPORT_SYMBOL(nfc_hci_allocate_device); | |||
653 | void nfc_hci_free_device(struct nfc_hci_dev *hdev) | 781 | void nfc_hci_free_device(struct nfc_hci_dev *hdev) |
654 | { | 782 | { |
655 | nfc_free_device(hdev->ndev); | 783 | nfc_free_device(hdev->ndev); |
784 | nfc_llc_free(hdev->llc); | ||
656 | kfree(hdev); | 785 | kfree(hdev); |
657 | } | 786 | } |
658 | EXPORT_SYMBOL(nfc_hci_free_device); | 787 | EXPORT_SYMBOL(nfc_hci_free_device); |
659 | 788 | ||
660 | int nfc_hci_register_device(struct nfc_hci_dev *hdev) | 789 | int nfc_hci_register_device(struct nfc_hci_dev *hdev) |
661 | { | 790 | { |
662 | struct device *dev = &hdev->ndev->dev; | ||
663 | const char *devname = dev_name(dev); | ||
664 | char name[32]; | ||
665 | int r = 0; | ||
666 | |||
667 | mutex_init(&hdev->msg_tx_mutex); | 791 | mutex_init(&hdev->msg_tx_mutex); |
668 | 792 | ||
669 | INIT_LIST_HEAD(&hdev->msg_tx_queue); | 793 | INIT_LIST_HEAD(&hdev->msg_tx_queue); |
670 | 794 | ||
671 | INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); | 795 | INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); |
672 | snprintf(name, sizeof(name), "%s_hci_msg_tx_wq", devname); | ||
673 | hdev->msg_tx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
674 | WQ_MEM_RECLAIM, 1); | ||
675 | if (hdev->msg_tx_wq == NULL) { | ||
676 | r = -ENOMEM; | ||
677 | goto exit; | ||
678 | } | ||
679 | 796 | ||
680 | init_timer(&hdev->cmd_timer); | 797 | init_timer(&hdev->cmd_timer); |
681 | hdev->cmd_timer.data = (unsigned long)hdev; | 798 | hdev->cmd_timer.data = (unsigned long)hdev; |
@@ -684,27 +801,10 @@ int nfc_hci_register_device(struct nfc_hci_dev *hdev) | |||
684 | skb_queue_head_init(&hdev->rx_hcp_frags); | 801 | skb_queue_head_init(&hdev->rx_hcp_frags); |
685 | 802 | ||
686 | INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); | 803 | INIT_WORK(&hdev->msg_rx_work, nfc_hci_msg_rx_work); |
687 | snprintf(name, sizeof(name), "%s_hci_msg_rx_wq", devname); | ||
688 | hdev->msg_rx_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
689 | WQ_MEM_RECLAIM, 1); | ||
690 | if (hdev->msg_rx_wq == NULL) { | ||
691 | r = -ENOMEM; | ||
692 | goto exit; | ||
693 | } | ||
694 | 804 | ||
695 | skb_queue_head_init(&hdev->msg_rx_queue); | 805 | skb_queue_head_init(&hdev->msg_rx_queue); |
696 | 806 | ||
697 | r = nfc_register_device(hdev->ndev); | 807 | return nfc_register_device(hdev->ndev); |
698 | |||
699 | exit: | ||
700 | if (r < 0) { | ||
701 | if (hdev->msg_tx_wq) | ||
702 | destroy_workqueue(hdev->msg_tx_wq); | ||
703 | if (hdev->msg_rx_wq) | ||
704 | destroy_workqueue(hdev->msg_rx_wq); | ||
705 | } | ||
706 | |||
707 | return r; | ||
708 | } | 808 | } |
709 | EXPORT_SYMBOL(nfc_hci_register_device); | 809 | EXPORT_SYMBOL(nfc_hci_register_device); |
710 | 810 | ||
@@ -725,9 +825,8 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev) | |||
725 | 825 | ||
726 | nfc_unregister_device(hdev->ndev); | 826 | nfc_unregister_device(hdev->ndev); |
727 | 827 | ||
728 | destroy_workqueue(hdev->msg_tx_wq); | 828 | cancel_work_sync(&hdev->msg_tx_work); |
729 | 829 | cancel_work_sync(&hdev->msg_rx_work); | |
730 | destroy_workqueue(hdev->msg_rx_wq); | ||
731 | } | 830 | } |
732 | EXPORT_SYMBOL(nfc_hci_unregister_device); | 831 | EXPORT_SYMBOL(nfc_hci_unregister_device); |
733 | 832 | ||
@@ -743,93 +842,30 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) | |||
743 | } | 842 | } |
744 | EXPORT_SYMBOL(nfc_hci_get_clientdata); | 843 | EXPORT_SYMBOL(nfc_hci_get_clientdata); |
745 | 844 | ||
746 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
747 | { | ||
748 | mutex_lock(&hdev->msg_tx_mutex); | ||
749 | |||
750 | if (hdev->cmd_pending_msg == NULL) { | ||
751 | nfc_driver_failure(hdev->ndev, err); | ||
752 | goto exit; | ||
753 | } | ||
754 | |||
755 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
756 | |||
757 | exit: | ||
758 | mutex_unlock(&hdev->msg_tx_mutex); | ||
759 | } | ||
760 | |||
761 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) | 845 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) |
762 | { | 846 | { |
763 | nfc_hci_failure(hdev, err); | 847 | nfc_hci_failure(hdev, err); |
764 | } | 848 | } |
765 | EXPORT_SYMBOL(nfc_hci_driver_failure); | 849 | EXPORT_SYMBOL(nfc_hci_driver_failure); |
766 | 850 | ||
767 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | 851 | void inline nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
768 | { | 852 | { |
769 | struct hcp_packet *packet; | 853 | nfc_llc_rcv_from_drv(hdev->llc, skb); |
770 | u8 type; | 854 | } |
771 | u8 instruction; | 855 | EXPORT_SYMBOL(nfc_hci_recv_frame); |
772 | struct sk_buff *hcp_skb; | ||
773 | u8 pipe; | ||
774 | struct sk_buff *frag_skb; | ||
775 | int msg_len; | ||
776 | |||
777 | packet = (struct hcp_packet *)skb->data; | ||
778 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | ||
779 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | /* it's the last fragment. Does it need re-aggregation? */ | ||
784 | if (skb_queue_len(&hdev->rx_hcp_frags)) { | ||
785 | pipe = packet->header & NFC_HCI_FRAGMENT; | ||
786 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | ||
787 | |||
788 | msg_len = 0; | ||
789 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
790 | msg_len += (frag_skb->len - | ||
791 | NFC_HCI_HCP_PACKET_HEADER_LEN); | ||
792 | } | ||
793 | |||
794 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
795 | msg_len, GFP_KERNEL); | ||
796 | if (hcp_skb == NULL) { | ||
797 | nfc_hci_failure(hdev, -ENOMEM); | ||
798 | return; | ||
799 | } | ||
800 | |||
801 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | ||
802 | |||
803 | skb_queue_walk(&hdev->rx_hcp_frags, frag_skb) { | ||
804 | msg_len = frag_skb->len - NFC_HCI_HCP_PACKET_HEADER_LEN; | ||
805 | memcpy(skb_put(hcp_skb, msg_len), | ||
806 | frag_skb->data + NFC_HCI_HCP_PACKET_HEADER_LEN, | ||
807 | msg_len); | ||
808 | } | ||
809 | 856 | ||
810 | skb_queue_purge(&hdev->rx_hcp_frags); | 857 | static int __init nfc_hci_init(void) |
811 | } else { | 858 | { |
812 | packet->header &= NFC_HCI_FRAGMENT; | 859 | return nfc_llc_init(); |
813 | hcp_skb = skb; | 860 | } |
814 | } | ||
815 | 861 | ||
816 | /* if this is a response, dispatch immediately to | 862 | static void __exit nfc_hci_exit(void) |
817 | * unblock waiting cmd context. Otherwise, enqueue to dispatch | 863 | { |
818 | * in separate context where handler can also execute command. | 864 | nfc_llc_exit(); |
819 | */ | ||
820 | packet = (struct hcp_packet *)hcp_skb->data; | ||
821 | type = HCP_MSG_GET_TYPE(packet->message.header); | ||
822 | if (type == NFC_HCI_HCP_RESPONSE) { | ||
823 | pipe = packet->header; | ||
824 | instruction = HCP_MSG_GET_CMD(packet->message.header); | ||
825 | skb_pull(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN + | ||
826 | NFC_HCI_HCP_MESSAGE_HEADER_LEN); | ||
827 | nfc_hci_hcp_message_rx(hdev, pipe, type, instruction, hcp_skb); | ||
828 | } else { | ||
829 | skb_queue_tail(&hdev->msg_rx_queue, hcp_skb); | ||
830 | queue_work(hdev->msg_rx_wq, &hdev->msg_rx_work); | ||
831 | } | ||
832 | } | 865 | } |
833 | EXPORT_SYMBOL(nfc_hci_recv_frame); | 866 | |
867 | subsys_initcall(nfc_hci_init); | ||
868 | module_exit(nfc_hci_exit); | ||
834 | 869 | ||
835 | MODULE_LICENSE("GPL"); | 870 | MODULE_LICENSE("GPL"); |
871 | MODULE_DESCRIPTION("NFC HCI Core"); | ||
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index fa9a21e92239..b274d12c18ac 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h | |||
@@ -20,6 +20,8 @@ | |||
20 | #ifndef __LOCAL_HCI_H | 20 | #ifndef __LOCAL_HCI_H |
21 | #define __LOCAL_HCI_H | 21 | #define __LOCAL_HCI_H |
22 | 22 | ||
23 | #include <net/nfc/hci.h> | ||
24 | |||
23 | struct gate_pipe_map { | 25 | struct gate_pipe_map { |
24 | u8 gate; | 26 | u8 gate; |
25 | u8 pipe; | 27 | u8 pipe; |
@@ -35,15 +37,6 @@ struct hcp_packet { | |||
35 | struct hcp_message message; | 37 | struct hcp_message message; |
36 | } __packed; | 38 | } __packed; |
37 | 39 | ||
38 | /* | ||
39 | * HCI command execution completion callback. | ||
40 | * result will be a standard linux error (may be converted from HCI response) | ||
41 | * skb contains the response data and must be disposed, or may be NULL if | ||
42 | * an error occured | ||
43 | */ | ||
44 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, | ||
45 | struct sk_buff *skb, void *cb_data); | ||
46 | |||
47 | struct hcp_exec_waiter { | 40 | struct hcp_exec_waiter { |
48 | wait_queue_head_t *wq; | 41 | wait_queue_head_t *wq; |
49 | bool exec_complete; | 42 | bool exec_complete; |
@@ -55,7 +48,7 @@ struct hci_msg { | |||
55 | struct list_head msg_l; | 48 | struct list_head msg_l; |
56 | struct sk_buff_head msg_frags; | 49 | struct sk_buff_head msg_frags; |
57 | bool wait_response; | 50 | bool wait_response; |
58 | hci_cmd_cb_t cb; | 51 | data_exchange_cb_t cb; |
59 | void *cb_context; | 52 | void *cb_context; |
60 | unsigned long completion_delay; | 53 | unsigned long completion_delay; |
61 | }; | 54 | }; |
@@ -83,7 +76,7 @@ struct hci_create_pipe_resp { | |||
83 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | 76 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, |
84 | u8 type, u8 instruction, | 77 | u8 type, u8 instruction, |
85 | const u8 *payload, size_t payload_len, | 78 | const u8 *payload, size_t payload_len, |
86 | hci_cmd_cb_t cb, void *cb_data, | 79 | data_exchange_cb_t cb, void *cb_context, |
87 | unsigned long completion_delay); | 80 | unsigned long completion_delay); |
88 | 81 | ||
89 | u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe); | 82 | u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe); |
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index f4dad1a89740..208eedd07ee3 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c | |||
@@ -35,7 +35,7 @@ | |||
35 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | 35 | int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, |
36 | u8 type, u8 instruction, | 36 | u8 type, u8 instruction, |
37 | const u8 *payload, size_t payload_len, | 37 | const u8 *payload, size_t payload_len, |
38 | hci_cmd_cb_t cb, void *cb_data, | 38 | data_exchange_cb_t cb, void *cb_context, |
39 | unsigned long completion_delay) | 39 | unsigned long completion_delay) |
40 | { | 40 | { |
41 | struct nfc_dev *ndev = hdev->ndev; | 41 | struct nfc_dev *ndev = hdev->ndev; |
@@ -52,7 +52,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | |||
52 | skb_queue_head_init(&cmd->msg_frags); | 52 | skb_queue_head_init(&cmd->msg_frags); |
53 | cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; | 53 | cmd->wait_response = (type == NFC_HCI_HCP_COMMAND) ? true : false; |
54 | cmd->cb = cb; | 54 | cmd->cb = cb; |
55 | cmd->cb_context = cb_data; | 55 | cmd->cb_context = cb_context; |
56 | cmd->completion_delay = completion_delay; | 56 | cmd->completion_delay = completion_delay; |
57 | 57 | ||
58 | hci_len = payload_len + 1; | 58 | hci_len = payload_len + 1; |
@@ -108,7 +108,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, | |||
108 | list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); | 108 | list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); |
109 | mutex_unlock(&hdev->msg_tx_mutex); | 109 | mutex_unlock(&hdev->msg_tx_mutex); |
110 | 110 | ||
111 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 111 | queue_work(system_nrt_wq, &hdev->msg_tx_work); |
112 | 112 | ||
113 | return 0; | 113 | return 0; |
114 | 114 | ||
diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c new file mode 100644 index 000000000000..ae1205ded87f --- /dev/null +++ b/net/nfc/hci/llc.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <net/nfc/llc.h> | ||
22 | |||
23 | #include "llc.h" | ||
24 | |||
25 | static struct list_head llc_engines; | ||
26 | |||
27 | int nfc_llc_init(void) | ||
28 | { | ||
29 | int r; | ||
30 | |||
31 | INIT_LIST_HEAD(&llc_engines); | ||
32 | |||
33 | r = nfc_llc_nop_register(); | ||
34 | if (r) | ||
35 | goto exit; | ||
36 | |||
37 | r = nfc_llc_shdlc_register(); | ||
38 | if (r) | ||
39 | goto exit; | ||
40 | |||
41 | return 0; | ||
42 | |||
43 | exit: | ||
44 | nfc_llc_exit(); | ||
45 | return r; | ||
46 | } | ||
47 | |||
48 | void nfc_llc_exit(void) | ||
49 | { | ||
50 | struct nfc_llc_engine *llc_engine, *n; | ||
51 | |||
52 | list_for_each_entry_safe(llc_engine, n, &llc_engines, entry) { | ||
53 | list_del(&llc_engine->entry); | ||
54 | kfree(llc_engine->name); | ||
55 | kfree(llc_engine); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | int nfc_llc_register(const char *name, struct nfc_llc_ops *ops) | ||
60 | { | ||
61 | struct nfc_llc_engine *llc_engine; | ||
62 | |||
63 | llc_engine = kzalloc(sizeof(struct nfc_llc_engine), GFP_KERNEL); | ||
64 | if (llc_engine == NULL) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | llc_engine->name = kstrdup(name, GFP_KERNEL); | ||
68 | if (llc_engine->name == NULL) { | ||
69 | kfree(llc_engine); | ||
70 | return -ENOMEM; | ||
71 | } | ||
72 | llc_engine->ops = ops; | ||
73 | |||
74 | INIT_LIST_HEAD(&llc_engine->entry); | ||
75 | list_add_tail (&llc_engine->entry, &llc_engines); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static struct nfc_llc_engine *nfc_llc_name_to_engine(const char *name) | ||
81 | { | ||
82 | struct nfc_llc_engine *llc_engine; | ||
83 | |||
84 | list_for_each_entry(llc_engine, &llc_engines, entry) { | ||
85 | if (strcmp(llc_engine->name, name) == 0) | ||
86 | return llc_engine; | ||
87 | } | ||
88 | |||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | void nfc_llc_unregister(const char *name) | ||
93 | { | ||
94 | struct nfc_llc_engine *llc_engine; | ||
95 | |||
96 | llc_engine = nfc_llc_name_to_engine(name); | ||
97 | if (llc_engine == NULL) | ||
98 | return; | ||
99 | |||
100 | list_del(&llc_engine->entry); | ||
101 | kfree(llc_engine->name); | ||
102 | kfree(llc_engine); | ||
103 | } | ||
104 | |||
105 | struct nfc_llc *nfc_llc_allocate(const char *name, struct nfc_hci_dev *hdev, | ||
106 | xmit_to_drv_t xmit_to_drv, | ||
107 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
108 | int tx_tailroom, llc_failure_t llc_failure) | ||
109 | { | ||
110 | struct nfc_llc_engine *llc_engine; | ||
111 | struct nfc_llc *llc; | ||
112 | |||
113 | llc_engine = nfc_llc_name_to_engine(name); | ||
114 | if (llc_engine == NULL) | ||
115 | return NULL; | ||
116 | |||
117 | llc = kzalloc(sizeof(struct nfc_llc), GFP_KERNEL); | ||
118 | if (llc == NULL) | ||
119 | return NULL; | ||
120 | |||
121 | llc->data = llc_engine->ops->init(hdev, xmit_to_drv, rcv_to_hci, | ||
122 | tx_headroom, tx_tailroom, | ||
123 | &llc->rx_headroom, &llc->rx_tailroom, | ||
124 | llc_failure); | ||
125 | if (llc->data == NULL) { | ||
126 | kfree(llc); | ||
127 | return NULL; | ||
128 | } | ||
129 | llc->ops = llc_engine->ops; | ||
130 | |||
131 | return llc; | ||
132 | } | ||
133 | |||
134 | void nfc_llc_free(struct nfc_llc *llc) | ||
135 | { | ||
136 | llc->ops->deinit(llc); | ||
137 | kfree(llc); | ||
138 | } | ||
139 | |||
140 | inline void nfc_llc_get_rx_head_tail_room(struct nfc_llc *llc, int *rx_headroom, | ||
141 | int *rx_tailroom) | ||
142 | { | ||
143 | *rx_headroom = llc->rx_headroom; | ||
144 | *rx_tailroom = llc->rx_tailroom; | ||
145 | } | ||
146 | |||
147 | inline int nfc_llc_start(struct nfc_llc *llc) | ||
148 | { | ||
149 | return llc->ops->start(llc); | ||
150 | } | ||
151 | |||
152 | inline int nfc_llc_stop(struct nfc_llc *llc) | ||
153 | { | ||
154 | return llc->ops->stop(llc); | ||
155 | } | ||
156 | |||
157 | inline void nfc_llc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) | ||
158 | { | ||
159 | llc->ops->rcv_from_drv(llc, skb); | ||
160 | } | ||
161 | |||
162 | inline int nfc_llc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) | ||
163 | { | ||
164 | return llc->ops->xmit_from_hci(llc, skb); | ||
165 | } | ||
166 | |||
167 | inline void *nfc_llc_get_data(struct nfc_llc *llc) | ||
168 | { | ||
169 | return llc->data; | ||
170 | } | ||
diff --git a/net/nfc/hci/llc.h b/net/nfc/hci/llc.h new file mode 100644 index 000000000000..7be0b7f3ceb6 --- /dev/null +++ b/net/nfc/hci/llc.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Link Layer Control manager | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __LOCAL_LLC_H_ | ||
22 | #define __LOCAL_LLC_H_ | ||
23 | |||
24 | #include <net/nfc/hci.h> | ||
25 | #include <net/nfc/llc.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | struct nfc_llc_ops { | ||
29 | void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | ||
30 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
31 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
32 | llc_failure_t llc_failure); | ||
33 | void (*deinit) (struct nfc_llc *llc); | ||
34 | int (*start) (struct nfc_llc *llc); | ||
35 | int (*stop) (struct nfc_llc *llc); | ||
36 | void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb); | ||
37 | int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb); | ||
38 | }; | ||
39 | |||
40 | struct nfc_llc_engine { | ||
41 | const char *name; | ||
42 | struct nfc_llc_ops *ops; | ||
43 | struct list_head entry; | ||
44 | }; | ||
45 | |||
46 | struct nfc_llc { | ||
47 | void *data; | ||
48 | struct nfc_llc_ops *ops; | ||
49 | int rx_headroom; | ||
50 | int rx_tailroom; | ||
51 | }; | ||
52 | |||
53 | void *nfc_llc_get_data(struct nfc_llc *llc); | ||
54 | |||
55 | int nfc_llc_register(const char *name, struct nfc_llc_ops *ops); | ||
56 | void nfc_llc_unregister(const char *name); | ||
57 | |||
58 | int nfc_llc_nop_register(void); | ||
59 | |||
60 | #if defined(CONFIG_NFC_SHDLC) | ||
61 | int nfc_llc_shdlc_register(void); | ||
62 | #else | ||
63 | static inline int nfc_llc_shdlc_register(void) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | #endif | ||
68 | |||
69 | #endif /* __LOCAL_LLC_H_ */ | ||
diff --git a/net/nfc/hci/llc_nop.c b/net/nfc/hci/llc_nop.c new file mode 100644 index 000000000000..87b10291b40f --- /dev/null +++ b/net/nfc/hci/llc_nop.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * nop (passthrough) Link Layer Control | ||
3 | * | ||
4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | #include "llc.h" | ||
24 | |||
25 | struct llc_nop { | ||
26 | struct nfc_hci_dev *hdev; | ||
27 | xmit_to_drv_t xmit_to_drv; | ||
28 | rcv_to_hci_t rcv_to_hci; | ||
29 | int tx_headroom; | ||
30 | int tx_tailroom; | ||
31 | llc_failure_t llc_failure; | ||
32 | }; | ||
33 | |||
34 | static void *llc_nop_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, | ||
35 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
36 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
37 | llc_failure_t llc_failure) | ||
38 | { | ||
39 | struct llc_nop *llc_nop; | ||
40 | |||
41 | *rx_headroom = 0; | ||
42 | *rx_tailroom = 0; | ||
43 | |||
44 | llc_nop = kzalloc(sizeof(struct llc_nop), GFP_KERNEL); | ||
45 | if (llc_nop == NULL) | ||
46 | return NULL; | ||
47 | |||
48 | llc_nop->hdev = hdev; | ||
49 | llc_nop->xmit_to_drv = xmit_to_drv; | ||
50 | llc_nop->rcv_to_hci = rcv_to_hci; | ||
51 | llc_nop->tx_headroom = tx_headroom; | ||
52 | llc_nop->tx_tailroom = tx_tailroom; | ||
53 | llc_nop->llc_failure = llc_failure; | ||
54 | |||
55 | return llc_nop; | ||
56 | } | ||
57 | |||
58 | static void llc_nop_deinit(struct nfc_llc *llc) | ||
59 | { | ||
60 | kfree(nfc_llc_get_data(llc)); | ||
61 | } | ||
62 | |||
63 | static int llc_nop_start(struct nfc_llc *llc) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int llc_nop_stop(struct nfc_llc *llc) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void llc_nop_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) | ||
74 | { | ||
75 | struct llc_nop *llc_nop = nfc_llc_get_data(llc); | ||
76 | |||
77 | llc_nop->rcv_to_hci(llc_nop->hdev, skb); | ||
78 | } | ||
79 | |||
80 | static int llc_nop_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) | ||
81 | { | ||
82 | struct llc_nop *llc_nop = nfc_llc_get_data(llc); | ||
83 | |||
84 | return llc_nop->xmit_to_drv(llc_nop->hdev, skb); | ||
85 | } | ||
86 | |||
87 | static struct nfc_llc_ops llc_nop_ops = { | ||
88 | .init = llc_nop_init, | ||
89 | .deinit = llc_nop_deinit, | ||
90 | .start = llc_nop_start, | ||
91 | .stop = llc_nop_stop, | ||
92 | .rcv_from_drv = llc_nop_rcv_from_drv, | ||
93 | .xmit_from_hci = llc_nop_xmit_from_hci, | ||
94 | }; | ||
95 | |||
96 | int nfc_llc_nop_register(void) | ||
97 | { | ||
98 | return nfc_llc_register(LLC_NOP_NAME, &llc_nop_ops); | ||
99 | } | ||
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/llc_shdlc.c index 6f840c18c892..8f69d791dcb3 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/llc_shdlc.c | |||
@@ -1,10 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * shdlc Link Layer Control | ||
3 | * | ||
2 | * Copyright (C) 2012 Intel Corporation. All rights reserved. | 4 | * Copyright (C) 2012 Intel Corporation. All rights reserved. |
3 | * | 5 | * |
4 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify it |
5 | * it under the terms of the GNU General Public License as published by | 7 | * under the terms and conditions of the GNU General Public License, |
6 | * the Free Software Foundation; either version 2 of the License, or | 8 | * version 2, as published by the Free Software Foundation. |
7 | * (at your option) any later version. | ||
8 | * | 9 | * |
9 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
@@ -19,18 +20,65 @@ | |||
19 | 20 | ||
20 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ | 21 | #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ |
21 | 22 | ||
23 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
23 | #include <linux/export.h> | ||
24 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
25 | #include <linux/crc-ccitt.h> | ||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | 28 | ||
29 | #include <net/nfc/hci.h> | 29 | #include "llc.h" |
30 | #include <net/nfc/shdlc.h> | 30 | |
31 | enum shdlc_state { | ||
32 | SHDLC_DISCONNECTED = 0, | ||
33 | SHDLC_CONNECTING = 1, | ||
34 | SHDLC_NEGOTIATING = 2, | ||
35 | SHDLC_HALF_CONNECTED = 3, | ||
36 | SHDLC_CONNECTED = 4 | ||
37 | }; | ||
38 | |||
39 | struct llc_shdlc { | ||
40 | struct nfc_hci_dev *hdev; | ||
41 | xmit_to_drv_t xmit_to_drv; | ||
42 | rcv_to_hci_t rcv_to_hci; | ||
43 | |||
44 | struct mutex state_mutex; | ||
45 | enum shdlc_state state; | ||
46 | int hard_fault; | ||
47 | |||
48 | wait_queue_head_t *connect_wq; | ||
49 | int connect_tries; | ||
50 | int connect_result; | ||
51 | struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ | ||
52 | |||
53 | u8 w; /* window size */ | ||
54 | bool srej_support; | ||
55 | |||
56 | struct timer_list t1_timer; /* send ack timeout */ | ||
57 | bool t1_active; | ||
58 | |||
59 | struct timer_list t2_timer; /* guard/retransmit timeout */ | ||
60 | bool t2_active; | ||
61 | |||
62 | int ns; /* next seq num for send */ | ||
63 | int nr; /* next expected seq num for receive */ | ||
64 | int dnr; /* oldest sent unacked seq num */ | ||
65 | |||
66 | struct sk_buff_head rcv_q; | ||
67 | |||
68 | struct sk_buff_head send_q; | ||
69 | bool rnr; /* other side is not ready to receive */ | ||
70 | |||
71 | struct sk_buff_head ack_pending_q; | ||
72 | |||
73 | struct work_struct sm_work; | ||
74 | |||
75 | int tx_headroom; | ||
76 | int tx_tailroom; | ||
77 | |||
78 | llc_failure_t llc_failure; | ||
79 | }; | ||
31 | 80 | ||
32 | #define SHDLC_LLC_HEAD_ROOM 2 | 81 | #define SHDLC_LLC_HEAD_ROOM 2 |
33 | #define SHDLC_LLC_TAIL_ROOM 2 | ||
34 | 82 | ||
35 | #define SHDLC_MAX_WINDOW 4 | 83 | #define SHDLC_MAX_WINDOW 4 |
36 | #define SHDLC_SREJ_SUPPORT false | 84 | #define SHDLC_SREJ_SUPPORT false |
@@ -71,7 +119,7 @@ do { \ | |||
71 | } while (0) | 119 | } while (0) |
72 | 120 | ||
73 | /* checks x < y <= z modulo 8 */ | 121 | /* checks x < y <= z modulo 8 */ |
74 | static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) | 122 | static bool llc_shdlc_x_lt_y_lteq_z(int x, int y, int z) |
75 | { | 123 | { |
76 | if (x < z) | 124 | if (x < z) |
77 | return ((x < y) && (y <= z)) ? true : false; | 125 | return ((x < y) && (y <= z)) ? true : false; |
@@ -80,7 +128,7 @@ static bool nfc_shdlc_x_lt_y_lteq_z(int x, int y, int z) | |||
80 | } | 128 | } |
81 | 129 | ||
82 | /* checks x <= y < z modulo 8 */ | 130 | /* checks x <= y < z modulo 8 */ |
83 | static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) | 131 | static bool llc_shdlc_x_lteq_y_lt_z(int x, int y, int z) |
84 | { | 132 | { |
85 | if (x <= z) | 133 | if (x <= z) |
86 | return ((x <= y) && (y < z)) ? true : false; | 134 | return ((x <= y) && (y < z)) ? true : false; |
@@ -88,36 +136,21 @@ static bool nfc_shdlc_x_lteq_y_lt_z(int x, int y, int z) | |||
88 | return ((y >= x) || (y < z)) ? true : false; | 136 | return ((y >= x) || (y < z)) ? true : false; |
89 | } | 137 | } |
90 | 138 | ||
91 | static struct sk_buff *nfc_shdlc_alloc_skb(struct nfc_shdlc *shdlc, | 139 | static struct sk_buff *llc_shdlc_alloc_skb(struct llc_shdlc *shdlc, |
92 | int payload_len) | 140 | int payload_len) |
93 | { | 141 | { |
94 | struct sk_buff *skb; | 142 | struct sk_buff *skb; |
95 | 143 | ||
96 | skb = alloc_skb(shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM + | 144 | skb = alloc_skb(shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM + |
97 | shdlc->client_tailroom + SHDLC_LLC_TAIL_ROOM + | 145 | shdlc->tx_tailroom + payload_len, GFP_KERNEL); |
98 | payload_len, GFP_KERNEL); | ||
99 | if (skb) | 146 | if (skb) |
100 | skb_reserve(skb, shdlc->client_headroom + SHDLC_LLC_HEAD_ROOM); | 147 | skb_reserve(skb, shdlc->tx_headroom + SHDLC_LLC_HEAD_ROOM); |
101 | 148 | ||
102 | return skb; | 149 | return skb; |
103 | } | 150 | } |
104 | 151 | ||
105 | static void nfc_shdlc_add_len_crc(struct sk_buff *skb) | ||
106 | { | ||
107 | u16 crc; | ||
108 | int len; | ||
109 | |||
110 | len = skb->len + 2; | ||
111 | *skb_push(skb, 1) = len; | ||
112 | |||
113 | crc = crc_ccitt(0xffff, skb->data, skb->len); | ||
114 | crc = ~crc; | ||
115 | *skb_put(skb, 1) = crc & 0xff; | ||
116 | *skb_put(skb, 1) = crc >> 8; | ||
117 | } | ||
118 | |||
119 | /* immediately sends an S frame. */ | 152 | /* immediately sends an S frame. */ |
120 | static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | 153 | static int llc_shdlc_send_s_frame(struct llc_shdlc *shdlc, |
121 | enum sframe_type sframe_type, int nr) | 154 | enum sframe_type sframe_type, int nr) |
122 | { | 155 | { |
123 | int r; | 156 | int r; |
@@ -125,15 +158,13 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | |||
125 | 158 | ||
126 | pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); | 159 | pr_debug("sframe_type=%d nr=%d\n", sframe_type, nr); |
127 | 160 | ||
128 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 161 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
129 | if (skb == NULL) | 162 | if (skb == NULL) |
130 | return -ENOMEM; | 163 | return -ENOMEM; |
131 | 164 | ||
132 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; | 165 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_S | (sframe_type << 3) | nr; |
133 | 166 | ||
134 | nfc_shdlc_add_len_crc(skb); | 167 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
135 | |||
136 | r = shdlc->ops->xmit(shdlc, skb); | ||
137 | 168 | ||
138 | kfree_skb(skb); | 169 | kfree_skb(skb); |
139 | 170 | ||
@@ -141,7 +172,7 @@ static int nfc_shdlc_send_s_frame(struct nfc_shdlc *shdlc, | |||
141 | } | 172 | } |
142 | 173 | ||
143 | /* immediately sends an U frame. skb may contain optional payload */ | 174 | /* immediately sends an U frame. skb may contain optional payload */ |
144 | static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | 175 | static int llc_shdlc_send_u_frame(struct llc_shdlc *shdlc, |
145 | struct sk_buff *skb, | 176 | struct sk_buff *skb, |
146 | enum uframe_modifier uframe_modifier) | 177 | enum uframe_modifier uframe_modifier) |
147 | { | 178 | { |
@@ -151,9 +182,7 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | |||
151 | 182 | ||
152 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; | 183 | *skb_push(skb, 1) = SHDLC_CONTROL_HEAD_U | uframe_modifier; |
153 | 184 | ||
154 | nfc_shdlc_add_len_crc(skb); | 185 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
155 | |||
156 | r = shdlc->ops->xmit(shdlc, skb); | ||
157 | 186 | ||
158 | kfree_skb(skb); | 187 | kfree_skb(skb); |
159 | 188 | ||
@@ -164,7 +193,7 @@ static int nfc_shdlc_send_u_frame(struct nfc_shdlc *shdlc, | |||
164 | * Free ack_pending frames until y_nr - 1, and reset t2 according to | 193 | * Free ack_pending frames until y_nr - 1, and reset t2 according to |
165 | * the remaining oldest ack_pending frame sent time | 194 | * the remaining oldest ack_pending frame sent time |
166 | */ | 195 | */ |
167 | static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) | 196 | static void llc_shdlc_reset_t2(struct llc_shdlc *shdlc, int y_nr) |
168 | { | 197 | { |
169 | struct sk_buff *skb; | 198 | struct sk_buff *skb; |
170 | int dnr = shdlc->dnr; /* MUST initially be < y_nr */ | 199 | int dnr = shdlc->dnr; /* MUST initially be < y_nr */ |
@@ -204,7 +233,7 @@ static void nfc_shdlc_reset_t2(struct nfc_shdlc *shdlc, int y_nr) | |||
204 | * Receive validated frames from lower layer. skb contains HCI payload only. | 233 | * Receive validated frames from lower layer. skb contains HCI payload only. |
205 | * Handle according to algorithm at spec:10.8.2 | 234 | * Handle according to algorithm at spec:10.8.2 |
206 | */ | 235 | */ |
207 | static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, | 236 | static void llc_shdlc_rcv_i_frame(struct llc_shdlc *shdlc, |
208 | struct sk_buff *skb, int ns, int nr) | 237 | struct sk_buff *skb, int ns, int nr) |
209 | { | 238 | { |
210 | int x_ns = ns; | 239 | int x_ns = ns; |
@@ -216,66 +245,64 @@ static void nfc_shdlc_rcv_i_frame(struct nfc_shdlc *shdlc, | |||
216 | goto exit; | 245 | goto exit; |
217 | 246 | ||
218 | if (x_ns != shdlc->nr) { | 247 | if (x_ns != shdlc->nr) { |
219 | nfc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); | 248 | llc_shdlc_send_s_frame(shdlc, S_FRAME_REJ, shdlc->nr); |
220 | goto exit; | 249 | goto exit; |
221 | } | 250 | } |
222 | 251 | ||
223 | if (shdlc->t1_active == false) { | 252 | if (shdlc->t1_active == false) { |
224 | shdlc->t1_active = true; | 253 | shdlc->t1_active = true; |
225 | mod_timer(&shdlc->t1_timer, | 254 | mod_timer(&shdlc->t1_timer, jiffies + |
226 | msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); | 255 | msecs_to_jiffies(SHDLC_T1_VALUE_MS(shdlc->w))); |
227 | pr_debug("(re)Start T1(send ack)\n"); | 256 | pr_debug("(re)Start T1(send ack)\n"); |
228 | } | 257 | } |
229 | 258 | ||
230 | if (skb->len) { | 259 | if (skb->len) { |
231 | nfc_hci_recv_frame(shdlc->hdev, skb); | 260 | shdlc->rcv_to_hci(shdlc->hdev, skb); |
232 | skb = NULL; | 261 | skb = NULL; |
233 | } | 262 | } |
234 | 263 | ||
235 | shdlc->nr = (shdlc->nr + 1) % 8; | 264 | shdlc->nr = (shdlc->nr + 1) % 8; |
236 | 265 | ||
237 | if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { | 266 | if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { |
238 | nfc_shdlc_reset_t2(shdlc, y_nr); | 267 | llc_shdlc_reset_t2(shdlc, y_nr); |
239 | 268 | ||
240 | shdlc->dnr = y_nr; | 269 | shdlc->dnr = y_nr; |
241 | } | 270 | } |
242 | 271 | ||
243 | exit: | 272 | exit: |
244 | if (skb) | 273 | kfree_skb(skb); |
245 | kfree_skb(skb); | ||
246 | } | 274 | } |
247 | 275 | ||
248 | static void nfc_shdlc_rcv_ack(struct nfc_shdlc *shdlc, int y_nr) | 276 | static void llc_shdlc_rcv_ack(struct llc_shdlc *shdlc, int y_nr) |
249 | { | 277 | { |
250 | pr_debug("remote acked up to frame %d excluded\n", y_nr); | 278 | pr_debug("remote acked up to frame %d excluded\n", y_nr); |
251 | 279 | ||
252 | if (nfc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { | 280 | if (llc_shdlc_x_lt_y_lteq_z(shdlc->dnr, y_nr, shdlc->ns)) { |
253 | nfc_shdlc_reset_t2(shdlc, y_nr); | 281 | llc_shdlc_reset_t2(shdlc, y_nr); |
254 | shdlc->dnr = y_nr; | 282 | shdlc->dnr = y_nr; |
255 | } | 283 | } |
256 | } | 284 | } |
257 | 285 | ||
258 | static void nfc_shdlc_requeue_ack_pending(struct nfc_shdlc *shdlc) | 286 | static void llc_shdlc_requeue_ack_pending(struct llc_shdlc *shdlc) |
259 | { | 287 | { |
260 | struct sk_buff *skb; | 288 | struct sk_buff *skb; |
261 | 289 | ||
262 | pr_debug("ns reset to %d\n", shdlc->dnr); | 290 | pr_debug("ns reset to %d\n", shdlc->dnr); |
263 | 291 | ||
264 | while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { | 292 | while ((skb = skb_dequeue_tail(&shdlc->ack_pending_q))) { |
265 | skb_pull(skb, 2); /* remove len+control */ | 293 | skb_pull(skb, 1); /* remove control field */ |
266 | skb_trim(skb, skb->len - 2); /* remove crc */ | ||
267 | skb_queue_head(&shdlc->send_q, skb); | 294 | skb_queue_head(&shdlc->send_q, skb); |
268 | } | 295 | } |
269 | shdlc->ns = shdlc->dnr; | 296 | shdlc->ns = shdlc->dnr; |
270 | } | 297 | } |
271 | 298 | ||
272 | static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) | 299 | static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr) |
273 | { | 300 | { |
274 | struct sk_buff *skb; | 301 | struct sk_buff *skb; |
275 | 302 | ||
276 | pr_debug("remote asks retransmition from frame %d\n", y_nr); | 303 | pr_debug("remote asks retransmition from frame %d\n", y_nr); |
277 | 304 | ||
278 | if (nfc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { | 305 | if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) { |
279 | if (shdlc->t2_active) { | 306 | if (shdlc->t2_active) { |
280 | del_timer_sync(&shdlc->t2_timer); | 307 | del_timer_sync(&shdlc->t2_timer); |
281 | shdlc->t2_active = false; | 308 | shdlc->t2_active = false; |
@@ -289,12 +316,12 @@ static void nfc_shdlc_rcv_rej(struct nfc_shdlc *shdlc, int y_nr) | |||
289 | } | 316 | } |
290 | } | 317 | } |
291 | 318 | ||
292 | nfc_shdlc_requeue_ack_pending(shdlc); | 319 | llc_shdlc_requeue_ack_pending(shdlc); |
293 | } | 320 | } |
294 | } | 321 | } |
295 | 322 | ||
296 | /* See spec RR:10.8.3 REJ:10.8.4 */ | 323 | /* See spec RR:10.8.3 REJ:10.8.4 */ |
297 | static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | 324 | static void llc_shdlc_rcv_s_frame(struct llc_shdlc *shdlc, |
298 | enum sframe_type s_frame_type, int nr) | 325 | enum sframe_type s_frame_type, int nr) |
299 | { | 326 | { |
300 | struct sk_buff *skb; | 327 | struct sk_buff *skb; |
@@ -304,21 +331,21 @@ static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | |||
304 | 331 | ||
305 | switch (s_frame_type) { | 332 | switch (s_frame_type) { |
306 | case S_FRAME_RR: | 333 | case S_FRAME_RR: |
307 | nfc_shdlc_rcv_ack(shdlc, nr); | 334 | llc_shdlc_rcv_ack(shdlc, nr); |
308 | if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ | 335 | if (shdlc->rnr == true) { /* see SHDLC 10.7.7 */ |
309 | shdlc->rnr = false; | 336 | shdlc->rnr = false; |
310 | if (shdlc->send_q.qlen == 0) { | 337 | if (shdlc->send_q.qlen == 0) { |
311 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 338 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
312 | if (skb) | 339 | if (skb) |
313 | skb_queue_tail(&shdlc->send_q, skb); | 340 | skb_queue_tail(&shdlc->send_q, skb); |
314 | } | 341 | } |
315 | } | 342 | } |
316 | break; | 343 | break; |
317 | case S_FRAME_REJ: | 344 | case S_FRAME_REJ: |
318 | nfc_shdlc_rcv_rej(shdlc, nr); | 345 | llc_shdlc_rcv_rej(shdlc, nr); |
319 | break; | 346 | break; |
320 | case S_FRAME_RNR: | 347 | case S_FRAME_RNR: |
321 | nfc_shdlc_rcv_ack(shdlc, nr); | 348 | llc_shdlc_rcv_ack(shdlc, nr); |
322 | shdlc->rnr = true; | 349 | shdlc->rnr = true; |
323 | break; | 350 | break; |
324 | default: | 351 | default: |
@@ -326,7 +353,7 @@ static void nfc_shdlc_rcv_s_frame(struct nfc_shdlc *shdlc, | |||
326 | } | 353 | } |
327 | } | 354 | } |
328 | 355 | ||
329 | static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | 356 | static void llc_shdlc_connect_complete(struct llc_shdlc *shdlc, int r) |
330 | { | 357 | { |
331 | pr_debug("result=%d\n", r); | 358 | pr_debug("result=%d\n", r); |
332 | 359 | ||
@@ -337,7 +364,7 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
337 | shdlc->nr = 0; | 364 | shdlc->nr = 0; |
338 | shdlc->dnr = 0; | 365 | shdlc->dnr = 0; |
339 | 366 | ||
340 | shdlc->state = SHDLC_CONNECTED; | 367 | shdlc->state = SHDLC_HALF_CONNECTED; |
341 | } else { | 368 | } else { |
342 | shdlc->state = SHDLC_DISCONNECTED; | 369 | shdlc->state = SHDLC_DISCONNECTED; |
343 | } | 370 | } |
@@ -347,36 +374,36 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
347 | wake_up(shdlc->connect_wq); | 374 | wake_up(shdlc->connect_wq); |
348 | } | 375 | } |
349 | 376 | ||
350 | static int nfc_shdlc_connect_initiate(struct nfc_shdlc *shdlc) | 377 | static int llc_shdlc_connect_initiate(struct llc_shdlc *shdlc) |
351 | { | 378 | { |
352 | struct sk_buff *skb; | 379 | struct sk_buff *skb; |
353 | 380 | ||
354 | pr_debug("\n"); | 381 | pr_debug("\n"); |
355 | 382 | ||
356 | skb = nfc_shdlc_alloc_skb(shdlc, 2); | 383 | skb = llc_shdlc_alloc_skb(shdlc, 2); |
357 | if (skb == NULL) | 384 | if (skb == NULL) |
358 | return -ENOMEM; | 385 | return -ENOMEM; |
359 | 386 | ||
360 | *skb_put(skb, 1) = SHDLC_MAX_WINDOW; | 387 | *skb_put(skb, 1) = SHDLC_MAX_WINDOW; |
361 | *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; | 388 | *skb_put(skb, 1) = SHDLC_SREJ_SUPPORT ? 1 : 0; |
362 | 389 | ||
363 | return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); | 390 | return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_RSET); |
364 | } | 391 | } |
365 | 392 | ||
366 | static int nfc_shdlc_connect_send_ua(struct nfc_shdlc *shdlc) | 393 | static int llc_shdlc_connect_send_ua(struct llc_shdlc *shdlc) |
367 | { | 394 | { |
368 | struct sk_buff *skb; | 395 | struct sk_buff *skb; |
369 | 396 | ||
370 | pr_debug("\n"); | 397 | pr_debug("\n"); |
371 | 398 | ||
372 | skb = nfc_shdlc_alloc_skb(shdlc, 0); | 399 | skb = llc_shdlc_alloc_skb(shdlc, 0); |
373 | if (skb == NULL) | 400 | if (skb == NULL) |
374 | return -ENOMEM; | 401 | return -ENOMEM; |
375 | 402 | ||
376 | return nfc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); | 403 | return llc_shdlc_send_u_frame(shdlc, skb, U_FRAME_UA); |
377 | } | 404 | } |
378 | 405 | ||
379 | static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | 406 | static void llc_shdlc_rcv_u_frame(struct llc_shdlc *shdlc, |
380 | struct sk_buff *skb, | 407 | struct sk_buff *skb, |
381 | enum uframe_modifier u_frame_modifier) | 408 | enum uframe_modifier u_frame_modifier) |
382 | { | 409 | { |
@@ -388,8 +415,13 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
388 | 415 | ||
389 | switch (u_frame_modifier) { | 416 | switch (u_frame_modifier) { |
390 | case U_FRAME_RSET: | 417 | case U_FRAME_RSET: |
391 | if (shdlc->state == SHDLC_NEGOCIATING) { | 418 | switch (shdlc->state) { |
392 | /* we sent RSET, but chip wants to negociate */ | 419 | case SHDLC_NEGOTIATING: |
420 | case SHDLC_CONNECTING: | ||
421 | /* | ||
422 | * We sent RSET, but chip wants to negociate or we | ||
423 | * got RSET before we managed to send out our. | ||
424 | */ | ||
393 | if (skb->len > 0) | 425 | if (skb->len > 0) |
394 | w = skb->data[0]; | 426 | w = skb->data[0]; |
395 | 427 | ||
@@ -401,22 +433,34 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
401 | (SHDLC_SREJ_SUPPORT || (srej_support == false))) { | 433 | (SHDLC_SREJ_SUPPORT || (srej_support == false))) { |
402 | shdlc->w = w; | 434 | shdlc->w = w; |
403 | shdlc->srej_support = srej_support; | 435 | shdlc->srej_support = srej_support; |
404 | r = nfc_shdlc_connect_send_ua(shdlc); | 436 | r = llc_shdlc_connect_send_ua(shdlc); |
405 | nfc_shdlc_connect_complete(shdlc, r); | 437 | llc_shdlc_connect_complete(shdlc, r); |
406 | } | 438 | } |
407 | } else if (shdlc->state == SHDLC_CONNECTED) { | 439 | break; |
440 | case SHDLC_HALF_CONNECTED: | ||
441 | /* | ||
442 | * Chip resent RSET due to its timeout - Ignote it | ||
443 | * as we already sent UA. | ||
444 | */ | ||
445 | break; | ||
446 | case SHDLC_CONNECTED: | ||
408 | /* | 447 | /* |
409 | * Chip wants to reset link. This is unexpected and | 448 | * Chip wants to reset link. This is unexpected and |
410 | * unsupported. | 449 | * unsupported. |
411 | */ | 450 | */ |
412 | shdlc->hard_fault = -ECONNRESET; | 451 | shdlc->hard_fault = -ECONNRESET; |
452 | break; | ||
453 | default: | ||
454 | break; | ||
413 | } | 455 | } |
414 | break; | 456 | break; |
415 | case U_FRAME_UA: | 457 | case U_FRAME_UA: |
416 | if ((shdlc->state == SHDLC_CONNECTING && | 458 | if ((shdlc->state == SHDLC_CONNECTING && |
417 | shdlc->connect_tries > 0) || | 459 | shdlc->connect_tries > 0) || |
418 | (shdlc->state == SHDLC_NEGOCIATING)) | 460 | (shdlc->state == SHDLC_NEGOTIATING)) { |
419 | nfc_shdlc_connect_complete(shdlc, 0); | 461 | llc_shdlc_connect_complete(shdlc, 0); |
462 | shdlc->state = SHDLC_CONNECTED; | ||
463 | } | ||
420 | break; | 464 | break; |
421 | default: | 465 | default: |
422 | break; | 466 | break; |
@@ -425,7 +469,7 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
425 | kfree_skb(skb); | 469 | kfree_skb(skb); |
426 | } | 470 | } |
427 | 471 | ||
428 | static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | 472 | static void llc_shdlc_handle_rcv_queue(struct llc_shdlc *shdlc) |
429 | { | 473 | { |
430 | struct sk_buff *skb; | 474 | struct sk_buff *skb; |
431 | u8 control; | 475 | u8 control; |
@@ -443,19 +487,25 @@ static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | |||
443 | switch (control & SHDLC_CONTROL_HEAD_MASK) { | 487 | switch (control & SHDLC_CONTROL_HEAD_MASK) { |
444 | case SHDLC_CONTROL_HEAD_I: | 488 | case SHDLC_CONTROL_HEAD_I: |
445 | case SHDLC_CONTROL_HEAD_I2: | 489 | case SHDLC_CONTROL_HEAD_I2: |
490 | if (shdlc->state == SHDLC_HALF_CONNECTED) | ||
491 | shdlc->state = SHDLC_CONNECTED; | ||
492 | |||
446 | ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; | 493 | ns = (control & SHDLC_CONTROL_NS_MASK) >> 3; |
447 | nr = control & SHDLC_CONTROL_NR_MASK; | 494 | nr = control & SHDLC_CONTROL_NR_MASK; |
448 | nfc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); | 495 | llc_shdlc_rcv_i_frame(shdlc, skb, ns, nr); |
449 | break; | 496 | break; |
450 | case SHDLC_CONTROL_HEAD_S: | 497 | case SHDLC_CONTROL_HEAD_S: |
498 | if (shdlc->state == SHDLC_HALF_CONNECTED) | ||
499 | shdlc->state = SHDLC_CONNECTED; | ||
500 | |||
451 | s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; | 501 | s_frame_type = (control & SHDLC_CONTROL_TYPE_MASK) >> 3; |
452 | nr = control & SHDLC_CONTROL_NR_MASK; | 502 | nr = control & SHDLC_CONTROL_NR_MASK; |
453 | nfc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); | 503 | llc_shdlc_rcv_s_frame(shdlc, s_frame_type, nr); |
454 | kfree_skb(skb); | 504 | kfree_skb(skb); |
455 | break; | 505 | break; |
456 | case SHDLC_CONTROL_HEAD_U: | 506 | case SHDLC_CONTROL_HEAD_U: |
457 | u_frame_modifier = control & SHDLC_CONTROL_M_MASK; | 507 | u_frame_modifier = control & SHDLC_CONTROL_M_MASK; |
458 | nfc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); | 508 | llc_shdlc_rcv_u_frame(shdlc, skb, u_frame_modifier); |
459 | break; | 509 | break; |
460 | default: | 510 | default: |
461 | pr_err("UNKNOWN Control=%d\n", control); | 511 | pr_err("UNKNOWN Control=%d\n", control); |
@@ -465,7 +515,7 @@ static void nfc_shdlc_handle_rcv_queue(struct nfc_shdlc *shdlc) | |||
465 | } | 515 | } |
466 | } | 516 | } |
467 | 517 | ||
468 | static int nfc_shdlc_w_used(int ns, int dnr) | 518 | static int llc_shdlc_w_used(int ns, int dnr) |
469 | { | 519 | { |
470 | int unack_count; | 520 | int unack_count; |
471 | 521 | ||
@@ -478,7 +528,7 @@ static int nfc_shdlc_w_used(int ns, int dnr) | |||
478 | } | 528 | } |
479 | 529 | ||
480 | /* Send frames according to algorithm at spec:10.8.1 */ | 530 | /* Send frames according to algorithm at spec:10.8.1 */ |
481 | static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | 531 | static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) |
482 | { | 532 | { |
483 | struct sk_buff *skb; | 533 | struct sk_buff *skb; |
484 | int r; | 534 | int r; |
@@ -489,7 +539,7 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
489 | ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", | 539 | ("sendQlen=%d ns=%d dnr=%d rnr=%s w_room=%d unackQlen=%d\n", |
490 | shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, | 540 | shdlc->send_q.qlen, shdlc->ns, shdlc->dnr, |
491 | shdlc->rnr == false ? "false" : "true", | 541 | shdlc->rnr == false ? "false" : "true", |
492 | shdlc->w - nfc_shdlc_w_used(shdlc->ns, shdlc->dnr), | 542 | shdlc->w - llc_shdlc_w_used(shdlc->ns, shdlc->dnr), |
493 | shdlc->ack_pending_q.qlen); | 543 | shdlc->ack_pending_q.qlen); |
494 | 544 | ||
495 | while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && | 545 | while (shdlc->send_q.qlen && shdlc->ack_pending_q.qlen < shdlc->w && |
@@ -508,11 +558,9 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
508 | 558 | ||
509 | pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, | 559 | pr_debug("Sending I-Frame %d, waiting to rcv %d\n", shdlc->ns, |
510 | shdlc->nr); | 560 | shdlc->nr); |
511 | /* SHDLC_DUMP_SKB("shdlc frame written", skb); */ | 561 | SHDLC_DUMP_SKB("shdlc frame written", skb); |
512 | |||
513 | nfc_shdlc_add_len_crc(skb); | ||
514 | 562 | ||
515 | r = shdlc->ops->xmit(shdlc, skb); | 563 | r = shdlc->xmit_to_drv(shdlc->hdev, skb); |
516 | if (r < 0) { | 564 | if (r < 0) { |
517 | shdlc->hard_fault = r; | 565 | shdlc->hard_fault = r; |
518 | break; | 566 | break; |
@@ -534,36 +582,36 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
534 | } | 582 | } |
535 | } | 583 | } |
536 | 584 | ||
537 | static void nfc_shdlc_connect_timeout(unsigned long data) | 585 | static void llc_shdlc_connect_timeout(unsigned long data) |
538 | { | 586 | { |
539 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 587 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
540 | 588 | ||
541 | pr_debug("\n"); | 589 | pr_debug("\n"); |
542 | 590 | ||
543 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 591 | queue_work(system_nrt_wq, &shdlc->sm_work); |
544 | } | 592 | } |
545 | 593 | ||
546 | static void nfc_shdlc_t1_timeout(unsigned long data) | 594 | static void llc_shdlc_t1_timeout(unsigned long data) |
547 | { | 595 | { |
548 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 596 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
549 | 597 | ||
550 | pr_debug("SoftIRQ: need to send ack\n"); | 598 | pr_debug("SoftIRQ: need to send ack\n"); |
551 | 599 | ||
552 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 600 | queue_work(system_nrt_wq, &shdlc->sm_work); |
553 | } | 601 | } |
554 | 602 | ||
555 | static void nfc_shdlc_t2_timeout(unsigned long data) | 603 | static void llc_shdlc_t2_timeout(unsigned long data) |
556 | { | 604 | { |
557 | struct nfc_shdlc *shdlc = (struct nfc_shdlc *)data; | 605 | struct llc_shdlc *shdlc = (struct llc_shdlc *)data; |
558 | 606 | ||
559 | pr_debug("SoftIRQ: need to retransmit\n"); | 607 | pr_debug("SoftIRQ: need to retransmit\n"); |
560 | 608 | ||
561 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 609 | queue_work(system_nrt_wq, &shdlc->sm_work); |
562 | } | 610 | } |
563 | 611 | ||
564 | static void nfc_shdlc_sm_work(struct work_struct *work) | 612 | static void llc_shdlc_sm_work(struct work_struct *work) |
565 | { | 613 | { |
566 | struct nfc_shdlc *shdlc = container_of(work, struct nfc_shdlc, sm_work); | 614 | struct llc_shdlc *shdlc = container_of(work, struct llc_shdlc, sm_work); |
567 | int r; | 615 | int r; |
568 | 616 | ||
569 | pr_debug("\n"); | 617 | pr_debug("\n"); |
@@ -578,46 +626,47 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
578 | break; | 626 | break; |
579 | case SHDLC_CONNECTING: | 627 | case SHDLC_CONNECTING: |
580 | if (shdlc->hard_fault) { | 628 | if (shdlc->hard_fault) { |
581 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | 629 | llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); |
582 | break; | 630 | break; |
583 | } | 631 | } |
584 | 632 | ||
585 | if (shdlc->connect_tries++ < 5) | 633 | if (shdlc->connect_tries++ < 5) |
586 | r = nfc_shdlc_connect_initiate(shdlc); | 634 | r = llc_shdlc_connect_initiate(shdlc); |
587 | else | 635 | else |
588 | r = -ETIME; | 636 | r = -ETIME; |
589 | if (r < 0) | 637 | if (r < 0) |
590 | nfc_shdlc_connect_complete(shdlc, r); | 638 | llc_shdlc_connect_complete(shdlc, r); |
591 | else { | 639 | else { |
592 | mod_timer(&shdlc->connect_timer, jiffies + | 640 | mod_timer(&shdlc->connect_timer, jiffies + |
593 | msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); | 641 | msecs_to_jiffies(SHDLC_CONNECT_VALUE_MS)); |
594 | 642 | ||
595 | shdlc->state = SHDLC_NEGOCIATING; | 643 | shdlc->state = SHDLC_NEGOTIATING; |
596 | } | 644 | } |
597 | break; | 645 | break; |
598 | case SHDLC_NEGOCIATING: | 646 | case SHDLC_NEGOTIATING: |
599 | if (timer_pending(&shdlc->connect_timer) == 0) { | 647 | if (timer_pending(&shdlc->connect_timer) == 0) { |
600 | shdlc->state = SHDLC_CONNECTING; | 648 | shdlc->state = SHDLC_CONNECTING; |
601 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 649 | queue_work(system_nrt_wq, &shdlc->sm_work); |
602 | } | 650 | } |
603 | 651 | ||
604 | nfc_shdlc_handle_rcv_queue(shdlc); | 652 | llc_shdlc_handle_rcv_queue(shdlc); |
605 | 653 | ||
606 | if (shdlc->hard_fault) { | 654 | if (shdlc->hard_fault) { |
607 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | 655 | llc_shdlc_connect_complete(shdlc, shdlc->hard_fault); |
608 | break; | 656 | break; |
609 | } | 657 | } |
610 | break; | 658 | break; |
659 | case SHDLC_HALF_CONNECTED: | ||
611 | case SHDLC_CONNECTED: | 660 | case SHDLC_CONNECTED: |
612 | nfc_shdlc_handle_rcv_queue(shdlc); | 661 | llc_shdlc_handle_rcv_queue(shdlc); |
613 | nfc_shdlc_handle_send_queue(shdlc); | 662 | llc_shdlc_handle_send_queue(shdlc); |
614 | 663 | ||
615 | if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { | 664 | if (shdlc->t1_active && timer_pending(&shdlc->t1_timer) == 0) { |
616 | pr_debug | 665 | pr_debug |
617 | ("Handle T1(send ack) elapsed (T1 now inactive)\n"); | 666 | ("Handle T1(send ack) elapsed (T1 now inactive)\n"); |
618 | 667 | ||
619 | shdlc->t1_active = false; | 668 | shdlc->t1_active = false; |
620 | r = nfc_shdlc_send_s_frame(shdlc, S_FRAME_RR, | 669 | r = llc_shdlc_send_s_frame(shdlc, S_FRAME_RR, |
621 | shdlc->nr); | 670 | shdlc->nr); |
622 | if (r < 0) | 671 | if (r < 0) |
623 | shdlc->hard_fault = r; | 672 | shdlc->hard_fault = r; |
@@ -629,12 +678,12 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
629 | 678 | ||
630 | shdlc->t2_active = false; | 679 | shdlc->t2_active = false; |
631 | 680 | ||
632 | nfc_shdlc_requeue_ack_pending(shdlc); | 681 | llc_shdlc_requeue_ack_pending(shdlc); |
633 | nfc_shdlc_handle_send_queue(shdlc); | 682 | llc_shdlc_handle_send_queue(shdlc); |
634 | } | 683 | } |
635 | 684 | ||
636 | if (shdlc->hard_fault) { | 685 | if (shdlc->hard_fault) { |
637 | nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); | 686 | shdlc->llc_failure(shdlc->hdev, shdlc->hard_fault); |
638 | } | 687 | } |
639 | break; | 688 | break; |
640 | default: | 689 | default: |
@@ -647,7 +696,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
647 | * Called from syscall context to establish shdlc link. Sleeps until | 696 | * Called from syscall context to establish shdlc link. Sleeps until |
648 | * link is ready or failure. | 697 | * link is ready or failure. |
649 | */ | 698 | */ |
650 | static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) | 699 | static int llc_shdlc_connect(struct llc_shdlc *shdlc) |
651 | { | 700 | { |
652 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); | 701 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(connect_wq); |
653 | 702 | ||
@@ -662,14 +711,14 @@ static int nfc_shdlc_connect(struct nfc_shdlc *shdlc) | |||
662 | 711 | ||
663 | mutex_unlock(&shdlc->state_mutex); | 712 | mutex_unlock(&shdlc->state_mutex); |
664 | 713 | ||
665 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 714 | queue_work(system_nrt_wq, &shdlc->sm_work); |
666 | 715 | ||
667 | wait_event(connect_wq, shdlc->connect_result != 1); | 716 | wait_event(connect_wq, shdlc->connect_result != 1); |
668 | 717 | ||
669 | return shdlc->connect_result; | 718 | return shdlc->connect_result; |
670 | } | 719 | } |
671 | 720 | ||
672 | static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | 721 | static void llc_shdlc_disconnect(struct llc_shdlc *shdlc) |
673 | { | 722 | { |
674 | pr_debug("\n"); | 723 | pr_debug("\n"); |
675 | 724 | ||
@@ -679,7 +728,7 @@ static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | |||
679 | 728 | ||
680 | mutex_unlock(&shdlc->state_mutex); | 729 | mutex_unlock(&shdlc->state_mutex); |
681 | 730 | ||
682 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 731 | queue_work(system_nrt_wq, &shdlc->sm_work); |
683 | } | 732 | } |
684 | 733 | ||
685 | /* | 734 | /* |
@@ -687,7 +736,7 @@ static void nfc_shdlc_disconnect(struct nfc_shdlc *shdlc) | |||
687 | * skb contains only LLC header and payload. | 736 | * skb contains only LLC header and payload. |
688 | * If skb == NULL, it is a notification that the link below is dead. | 737 | * If skb == NULL, it is a notification that the link below is dead. |
689 | */ | 738 | */ |
690 | void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) | 739 | static void llc_shdlc_recv_frame(struct llc_shdlc *shdlc, struct sk_buff *skb) |
691 | { | 740 | { |
692 | if (skb == NULL) { | 741 | if (skb == NULL) { |
693 | pr_err("NULL Frame -> link is dead\n"); | 742 | pr_err("NULL Frame -> link is dead\n"); |
@@ -697,176 +746,37 @@ void nfc_shdlc_recv_frame(struct nfc_shdlc *shdlc, struct sk_buff *skb) | |||
697 | skb_queue_tail(&shdlc->rcv_q, skb); | 746 | skb_queue_tail(&shdlc->rcv_q, skb); |
698 | } | 747 | } |
699 | 748 | ||
700 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 749 | queue_work(system_nrt_wq, &shdlc->sm_work); |
701 | } | ||
702 | EXPORT_SYMBOL(nfc_shdlc_recv_frame); | ||
703 | |||
704 | static int nfc_shdlc_open(struct nfc_hci_dev *hdev) | ||
705 | { | ||
706 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
707 | int r; | ||
708 | |||
709 | pr_debug("\n"); | ||
710 | |||
711 | if (shdlc->ops->open) { | ||
712 | r = shdlc->ops->open(shdlc); | ||
713 | if (r < 0) | ||
714 | return r; | ||
715 | } | ||
716 | |||
717 | r = nfc_shdlc_connect(shdlc); | ||
718 | if (r < 0 && shdlc->ops->close) | ||
719 | shdlc->ops->close(shdlc); | ||
720 | |||
721 | return r; | ||
722 | } | ||
723 | |||
724 | static void nfc_shdlc_close(struct nfc_hci_dev *hdev) | ||
725 | { | ||
726 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
727 | |||
728 | pr_debug("\n"); | ||
729 | |||
730 | nfc_shdlc_disconnect(shdlc); | ||
731 | |||
732 | if (shdlc->ops->close) | ||
733 | shdlc->ops->close(shdlc); | ||
734 | } | 750 | } |
735 | 751 | ||
736 | static int nfc_shdlc_hci_ready(struct nfc_hci_dev *hdev) | 752 | static void *llc_shdlc_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, |
753 | rcv_to_hci_t rcv_to_hci, int tx_headroom, | ||
754 | int tx_tailroom, int *rx_headroom, int *rx_tailroom, | ||
755 | llc_failure_t llc_failure) | ||
737 | { | 756 | { |
738 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | 757 | struct llc_shdlc *shdlc; |
739 | int r = 0; | ||
740 | |||
741 | pr_debug("\n"); | ||
742 | 758 | ||
743 | if (shdlc->ops->hci_ready) | 759 | *rx_headroom = SHDLC_LLC_HEAD_ROOM; |
744 | r = shdlc->ops->hci_ready(shdlc); | 760 | *rx_tailroom = 0; |
745 | |||
746 | return r; | ||
747 | } | ||
748 | |||
749 | static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) | ||
750 | { | ||
751 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
752 | |||
753 | SHDLC_DUMP_SKB("queuing HCP packet to shdlc", skb); | ||
754 | |||
755 | skb_queue_tail(&shdlc->send_q, skb); | ||
756 | 761 | ||
757 | queue_work(shdlc->sm_wq, &shdlc->sm_work); | 762 | shdlc = kzalloc(sizeof(struct llc_shdlc), GFP_KERNEL); |
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, | ||
763 | u32 im_protocols, u32 tm_protocols) | ||
764 | { | ||
765 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
766 | |||
767 | pr_debug("\n"); | ||
768 | |||
769 | if (shdlc->ops->start_poll) | ||
770 | return shdlc->ops->start_poll(shdlc, | ||
771 | im_protocols, tm_protocols); | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int nfc_shdlc_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, | ||
777 | struct nfc_target *target) | ||
778 | { | ||
779 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
780 | |||
781 | if (shdlc->ops->target_from_gate) | ||
782 | return shdlc->ops->target_from_gate(shdlc, gate, target); | ||
783 | |||
784 | return -EPERM; | ||
785 | } | ||
786 | |||
787 | static int nfc_shdlc_complete_target_discovered(struct nfc_hci_dev *hdev, | ||
788 | u8 gate, | ||
789 | struct nfc_target *target) | ||
790 | { | ||
791 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
792 | |||
793 | pr_debug("\n"); | ||
794 | |||
795 | if (shdlc->ops->complete_target_discovered) | ||
796 | return shdlc->ops->complete_target_discovered(shdlc, gate, | ||
797 | target); | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, | ||
803 | struct nfc_target *target, | ||
804 | struct sk_buff *skb, | ||
805 | struct sk_buff **res_skb) | ||
806 | { | ||
807 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
808 | |||
809 | if (shdlc->ops->data_exchange) | ||
810 | return shdlc->ops->data_exchange(shdlc, target, skb, res_skb); | ||
811 | |||
812 | return -EPERM; | ||
813 | } | ||
814 | |||
815 | static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, | ||
816 | struct nfc_target *target) | ||
817 | { | ||
818 | struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); | ||
819 | |||
820 | if (shdlc->ops->check_presence) | ||
821 | return shdlc->ops->check_presence(shdlc, target); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static struct nfc_hci_ops shdlc_ops = { | ||
827 | .open = nfc_shdlc_open, | ||
828 | .close = nfc_shdlc_close, | ||
829 | .hci_ready = nfc_shdlc_hci_ready, | ||
830 | .xmit = nfc_shdlc_xmit, | ||
831 | .start_poll = nfc_shdlc_start_poll, | ||
832 | .target_from_gate = nfc_shdlc_target_from_gate, | ||
833 | .complete_target_discovered = nfc_shdlc_complete_target_discovered, | ||
834 | .data_exchange = nfc_shdlc_data_exchange, | ||
835 | .check_presence = nfc_shdlc_check_presence, | ||
836 | }; | ||
837 | |||
838 | struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | ||
839 | struct nfc_hci_init_data *init_data, | ||
840 | u32 protocols, | ||
841 | int tx_headroom, int tx_tailroom, | ||
842 | int max_link_payload, const char *devname) | ||
843 | { | ||
844 | struct nfc_shdlc *shdlc; | ||
845 | int r; | ||
846 | char name[32]; | ||
847 | |||
848 | if (ops->xmit == NULL) | ||
849 | return NULL; | ||
850 | |||
851 | shdlc = kzalloc(sizeof(struct nfc_shdlc), GFP_KERNEL); | ||
852 | if (shdlc == NULL) | 763 | if (shdlc == NULL) |
853 | return NULL; | 764 | return NULL; |
854 | 765 | ||
855 | mutex_init(&shdlc->state_mutex); | 766 | mutex_init(&shdlc->state_mutex); |
856 | shdlc->ops = ops; | ||
857 | shdlc->state = SHDLC_DISCONNECTED; | 767 | shdlc->state = SHDLC_DISCONNECTED; |
858 | 768 | ||
859 | init_timer(&shdlc->connect_timer); | 769 | init_timer(&shdlc->connect_timer); |
860 | shdlc->connect_timer.data = (unsigned long)shdlc; | 770 | shdlc->connect_timer.data = (unsigned long)shdlc; |
861 | shdlc->connect_timer.function = nfc_shdlc_connect_timeout; | 771 | shdlc->connect_timer.function = llc_shdlc_connect_timeout; |
862 | 772 | ||
863 | init_timer(&shdlc->t1_timer); | 773 | init_timer(&shdlc->t1_timer); |
864 | shdlc->t1_timer.data = (unsigned long)shdlc; | 774 | shdlc->t1_timer.data = (unsigned long)shdlc; |
865 | shdlc->t1_timer.function = nfc_shdlc_t1_timeout; | 775 | shdlc->t1_timer.function = llc_shdlc_t1_timeout; |
866 | 776 | ||
867 | init_timer(&shdlc->t2_timer); | 777 | init_timer(&shdlc->t2_timer); |
868 | shdlc->t2_timer.data = (unsigned long)shdlc; | 778 | shdlc->t2_timer.data = (unsigned long)shdlc; |
869 | shdlc->t2_timer.function = nfc_shdlc_t2_timeout; | 779 | shdlc->t2_timer.function = llc_shdlc_t2_timeout; |
870 | 780 | ||
871 | shdlc->w = SHDLC_MAX_WINDOW; | 781 | shdlc->w = SHDLC_MAX_WINDOW; |
872 | shdlc->srej_support = SHDLC_SREJ_SUPPORT; | 782 | shdlc->srej_support = SHDLC_SREJ_SUPPORT; |
@@ -875,77 +785,73 @@ struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, | |||
875 | skb_queue_head_init(&shdlc->send_q); | 785 | skb_queue_head_init(&shdlc->send_q); |
876 | skb_queue_head_init(&shdlc->ack_pending_q); | 786 | skb_queue_head_init(&shdlc->ack_pending_q); |
877 | 787 | ||
878 | INIT_WORK(&shdlc->sm_work, nfc_shdlc_sm_work); | 788 | INIT_WORK(&shdlc->sm_work, llc_shdlc_sm_work); |
879 | snprintf(name, sizeof(name), "%s_shdlc_sm_wq", devname); | ||
880 | shdlc->sm_wq = alloc_workqueue(name, WQ_NON_REENTRANT | WQ_UNBOUND | | ||
881 | WQ_MEM_RECLAIM, 1); | ||
882 | if (shdlc->sm_wq == NULL) | ||
883 | goto err_allocwq; | ||
884 | 789 | ||
885 | shdlc->client_headroom = tx_headroom; | 790 | shdlc->hdev = hdev; |
886 | shdlc->client_tailroom = tx_tailroom; | 791 | shdlc->xmit_to_drv = xmit_to_drv; |
887 | 792 | shdlc->rcv_to_hci = rcv_to_hci; | |
888 | shdlc->hdev = nfc_hci_allocate_device(&shdlc_ops, init_data, protocols, | 793 | shdlc->tx_headroom = tx_headroom; |
889 | tx_headroom + SHDLC_LLC_HEAD_ROOM, | 794 | shdlc->tx_tailroom = tx_tailroom; |
890 | tx_tailroom + SHDLC_LLC_TAIL_ROOM, | 795 | shdlc->llc_failure = llc_failure; |
891 | max_link_payload); | ||
892 | if (shdlc->hdev == NULL) | ||
893 | goto err_allocdev; | ||
894 | |||
895 | nfc_hci_set_clientdata(shdlc->hdev, shdlc); | ||
896 | |||
897 | r = nfc_hci_register_device(shdlc->hdev); | ||
898 | if (r < 0) | ||
899 | goto err_regdev; | ||
900 | 796 | ||
901 | return shdlc; | 797 | return shdlc; |
798 | } | ||
902 | 799 | ||
903 | err_regdev: | 800 | static void llc_shdlc_deinit(struct nfc_llc *llc) |
904 | nfc_hci_free_device(shdlc->hdev); | 801 | { |
802 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); | ||
905 | 803 | ||
906 | err_allocdev: | 804 | skb_queue_purge(&shdlc->rcv_q); |
907 | destroy_workqueue(shdlc->sm_wq); | 805 | skb_queue_purge(&shdlc->send_q); |
806 | skb_queue_purge(&shdlc->ack_pending_q); | ||
908 | 807 | ||
909 | err_allocwq: | ||
910 | kfree(shdlc); | 808 | kfree(shdlc); |
911 | |||
912 | return NULL; | ||
913 | } | 809 | } |
914 | EXPORT_SYMBOL(nfc_shdlc_allocate); | ||
915 | 810 | ||
916 | void nfc_shdlc_free(struct nfc_shdlc *shdlc) | 811 | static int llc_shdlc_start(struct nfc_llc *llc) |
917 | { | 812 | { |
918 | pr_debug("\n"); | 813 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
919 | 814 | ||
920 | nfc_hci_unregister_device(shdlc->hdev); | 815 | return llc_shdlc_connect(shdlc); |
921 | nfc_hci_free_device(shdlc->hdev); | 816 | } |
922 | 817 | ||
923 | destroy_workqueue(shdlc->sm_wq); | 818 | static int llc_shdlc_stop(struct nfc_llc *llc) |
819 | { | ||
820 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); | ||
924 | 821 | ||
925 | skb_queue_purge(&shdlc->rcv_q); | 822 | llc_shdlc_disconnect(shdlc); |
926 | skb_queue_purge(&shdlc->send_q); | ||
927 | skb_queue_purge(&shdlc->ack_pending_q); | ||
928 | 823 | ||
929 | kfree(shdlc); | 824 | return 0; |
930 | } | 825 | } |
931 | EXPORT_SYMBOL(nfc_shdlc_free); | ||
932 | 826 | ||
933 | void nfc_shdlc_set_clientdata(struct nfc_shdlc *shdlc, void *clientdata) | 827 | static void llc_shdlc_rcv_from_drv(struct nfc_llc *llc, struct sk_buff *skb) |
934 | { | 828 | { |
935 | pr_debug("\n"); | 829 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
936 | 830 | ||
937 | shdlc->clientdata = clientdata; | 831 | llc_shdlc_recv_frame(shdlc, skb); |
938 | } | 832 | } |
939 | EXPORT_SYMBOL(nfc_shdlc_set_clientdata); | ||
940 | 833 | ||
941 | void *nfc_shdlc_get_clientdata(struct nfc_shdlc *shdlc) | 834 | static int llc_shdlc_xmit_from_hci(struct nfc_llc *llc, struct sk_buff *skb) |
942 | { | 835 | { |
943 | return shdlc->clientdata; | 836 | struct llc_shdlc *shdlc = nfc_llc_get_data(llc); |
837 | |||
838 | skb_queue_tail(&shdlc->send_q, skb); | ||
839 | |||
840 | queue_work(system_nrt_wq, &shdlc->sm_work); | ||
841 | |||
842 | return 0; | ||
944 | } | 843 | } |
945 | EXPORT_SYMBOL(nfc_shdlc_get_clientdata); | ||
946 | 844 | ||
947 | struct nfc_hci_dev *nfc_shdlc_get_hci_dev(struct nfc_shdlc *shdlc) | 845 | static struct nfc_llc_ops llc_shdlc_ops = { |
846 | .init = llc_shdlc_init, | ||
847 | .deinit = llc_shdlc_deinit, | ||
848 | .start = llc_shdlc_start, | ||
849 | .stop = llc_shdlc_stop, | ||
850 | .rcv_from_drv = llc_shdlc_rcv_from_drv, | ||
851 | .xmit_from_hci = llc_shdlc_xmit_from_hci, | ||
852 | }; | ||
853 | |||
854 | int nfc_llc_shdlc_register(void) | ||
948 | { | 855 | { |
949 | return shdlc->hdev; | 856 | return nfc_llc_register(LLC_SHDLC_NAME, &llc_shdlc_ops); |
950 | } | 857 | } |
951 | EXPORT_SYMBOL(nfc_shdlc_get_hci_dev); | ||
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index b982b5b890d7..c45ccd6c094c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -312,6 +312,8 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) | |||
312 | 312 | ||
313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); | 313 | skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); |
314 | 314 | ||
315 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX); | ||
316 | |||
315 | return nfc_data_exchange(dev, local->target_idx, skb, | 317 | return nfc_data_exchange(dev, local->target_idx, skb, |
316 | nfc_llcp_recv, local); | 318 | nfc_llcp_recv, local); |
317 | } | 319 | } |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 82f0f7588b46..c12c5ef3d036 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -56,7 +56,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { | 56 | sk_for_each_safe(sk, node, tmp, &local->sockets.head) { |
57 | llcp_sock = nfc_llcp_sock(sk); | 57 | llcp_sock = nfc_llcp_sock(sk); |
58 | 58 | ||
59 | lock_sock(sk); | 59 | bh_lock_sock(sk); |
60 | 60 | ||
61 | if (sk->sk_state == LLCP_CONNECTED) | 61 | if (sk->sk_state == LLCP_CONNECTED) |
62 | nfc_put_device(llcp_sock->dev); | 62 | nfc_put_device(llcp_sock->dev); |
@@ -68,26 +68,26 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) | |||
68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, | 68 | list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue, |
69 | accept_queue) { | 69 | accept_queue) { |
70 | accept_sk = &lsk->sk; | 70 | accept_sk = &lsk->sk; |
71 | lock_sock(accept_sk); | 71 | bh_lock_sock(accept_sk); |
72 | 72 | ||
73 | nfc_llcp_accept_unlink(accept_sk); | 73 | nfc_llcp_accept_unlink(accept_sk); |
74 | 74 | ||
75 | accept_sk->sk_state = LLCP_CLOSED; | 75 | accept_sk->sk_state = LLCP_CLOSED; |
76 | 76 | ||
77 | release_sock(accept_sk); | 77 | bh_unlock_sock(accept_sk); |
78 | 78 | ||
79 | sock_orphan(accept_sk); | 79 | sock_orphan(accept_sk); |
80 | } | 80 | } |
81 | 81 | ||
82 | if (listen == true) { | 82 | if (listen == true) { |
83 | release_sock(sk); | 83 | bh_unlock_sock(sk); |
84 | continue; | 84 | continue; |
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | sk->sk_state = LLCP_CLOSED; | 88 | sk->sk_state = LLCP_CLOSED; |
89 | 89 | ||
90 | release_sock(sk); | 90 | bh_unlock_sock(sk); |
91 | 91 | ||
92 | sock_orphan(sk); | 92 | sock_orphan(sk); |
93 | 93 | ||
@@ -114,9 +114,9 @@ static void local_release(struct kref *ref) | |||
114 | nfc_llcp_socket_release(local, false); | 114 | nfc_llcp_socket_release(local, false); |
115 | del_timer_sync(&local->link_timer); | 115 | del_timer_sync(&local->link_timer); |
116 | skb_queue_purge(&local->tx_queue); | 116 | skb_queue_purge(&local->tx_queue); |
117 | destroy_workqueue(local->tx_wq); | 117 | cancel_work_sync(&local->tx_work); |
118 | destroy_workqueue(local->rx_wq); | 118 | cancel_work_sync(&local->rx_work); |
119 | destroy_workqueue(local->timeout_wq); | 119 | cancel_work_sync(&local->timeout_work); |
120 | kfree_skb(local->rx_pending); | 120 | kfree_skb(local->rx_pending); |
121 | kfree(local); | 121 | kfree(local); |
122 | } | 122 | } |
@@ -181,7 +181,7 @@ static void nfc_llcp_symm_timer(unsigned long data) | |||
181 | 181 | ||
182 | pr_err("SYMM timeout\n"); | 182 | pr_err("SYMM timeout\n"); |
183 | 183 | ||
184 | queue_work(local->timeout_wq, &local->timeout_work); | 184 | queue_work(system_nrt_wq, &local->timeout_work); |
185 | } | 185 | } |
186 | 186 | ||
187 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) | 187 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) |
@@ -426,6 +426,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
426 | u8 *miux_tlv, miux_length; | 426 | u8 *miux_tlv, miux_length; |
427 | __be16 miux; | 427 | __be16 miux; |
428 | u8 gb_len = 0; | 428 | u8 gb_len = 0; |
429 | int ret = 0; | ||
429 | 430 | ||
430 | version = LLCP_VERSION_11; | 431 | version = LLCP_VERSION_11; |
431 | version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, | 432 | version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version, |
@@ -450,8 +451,8 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
450 | gb_len += ARRAY_SIZE(llcp_magic); | 451 | gb_len += ARRAY_SIZE(llcp_magic); |
451 | 452 | ||
452 | if (gb_len > NFC_MAX_GT_LEN) { | 453 | if (gb_len > NFC_MAX_GT_LEN) { |
453 | kfree(version_tlv); | 454 | ret = -EINVAL; |
454 | return -EINVAL; | 455 | goto out; |
455 | } | 456 | } |
456 | 457 | ||
457 | gb_cur = local->gb; | 458 | gb_cur = local->gb; |
@@ -471,12 +472,15 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
471 | memcpy(gb_cur, miux_tlv, miux_length); | 472 | memcpy(gb_cur, miux_tlv, miux_length); |
472 | gb_cur += miux_length; | 473 | gb_cur += miux_length; |
473 | 474 | ||
475 | local->gb_len = gb_len; | ||
476 | |||
477 | out: | ||
474 | kfree(version_tlv); | 478 | kfree(version_tlv); |
475 | kfree(lto_tlv); | 479 | kfree(lto_tlv); |
480 | kfree(wks_tlv); | ||
481 | kfree(miux_tlv); | ||
476 | 482 | ||
477 | local->gb_len = gb_len; | 483 | return ret; |
478 | |||
479 | return 0; | ||
480 | } | 484 | } |
481 | 485 | ||
482 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | 486 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) |
@@ -554,6 +558,46 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu) | |||
554 | sock->recv_ack_n = (sock->recv_n - 1) % 16; | 558 | sock->recv_ack_n = (sock->recv_n - 1) % 16; |
555 | } | 559 | } |
556 | 560 | ||
561 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
562 | struct sk_buff *skb, u8 direction) | ||
563 | { | ||
564 | struct hlist_node *node; | ||
565 | struct sk_buff *skb_copy = NULL, *nskb; | ||
566 | struct sock *sk; | ||
567 | u8 *data; | ||
568 | |||
569 | read_lock(&local->raw_sockets.lock); | ||
570 | |||
571 | sk_for_each(sk, node, &local->raw_sockets.head) { | ||
572 | if (sk->sk_state != LLCP_BOUND) | ||
573 | continue; | ||
574 | |||
575 | if (skb_copy == NULL) { | ||
576 | skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE, | ||
577 | GFP_ATOMIC); | ||
578 | |||
579 | if (skb_copy == NULL) | ||
580 | continue; | ||
581 | |||
582 | data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE); | ||
583 | |||
584 | data[0] = local->dev ? local->dev->idx : 0xFF; | ||
585 | data[1] = direction; | ||
586 | } | ||
587 | |||
588 | nskb = skb_clone(skb_copy, GFP_ATOMIC); | ||
589 | if (!nskb) | ||
590 | continue; | ||
591 | |||
592 | if (sock_queue_rcv_skb(sk, nskb)) | ||
593 | kfree_skb(nskb); | ||
594 | } | ||
595 | |||
596 | read_unlock(&local->raw_sockets.lock); | ||
597 | |||
598 | kfree_skb(skb_copy); | ||
599 | } | ||
600 | |||
557 | static void nfc_llcp_tx_work(struct work_struct *work) | 601 | static void nfc_llcp_tx_work(struct work_struct *work) |
558 | { | 602 | { |
559 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 603 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, |
@@ -574,6 +618,9 @@ static void nfc_llcp_tx_work(struct work_struct *work) | |||
574 | DUMP_PREFIX_OFFSET, 16, 1, | 618 | DUMP_PREFIX_OFFSET, 16, 1, |
575 | skb->data, skb->len, true); | 619 | skb->data, skb->len, true); |
576 | 620 | ||
621 | nfc_llcp_send_to_raw_sock(local, skb, | ||
622 | NFC_LLCP_DIRECTION_TX); | ||
623 | |||
577 | ret = nfc_data_exchange(local->dev, local->target_idx, | 624 | ret = nfc_data_exchange(local->dev, local->target_idx, |
578 | skb, nfc_llcp_recv, local); | 625 | skb, nfc_llcp_recv, local); |
579 | 626 | ||
@@ -1018,6 +1065,8 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1018 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, | 1065 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, |
1019 | 16, 1, skb->data, skb->len, true); | 1066 | 16, 1, skb->data, skb->len, true); |
1020 | 1067 | ||
1068 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | ||
1069 | |||
1021 | switch (ptype) { | 1070 | switch (ptype) { |
1022 | case LLCP_PDU_SYMM: | 1071 | case LLCP_PDU_SYMM: |
1023 | pr_debug("SYMM\n"); | 1072 | pr_debug("SYMM\n"); |
@@ -1052,7 +1101,7 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1052 | 1101 | ||
1053 | } | 1102 | } |
1054 | 1103 | ||
1055 | queue_work(local->tx_wq, &local->tx_work); | 1104 | queue_work(system_nrt_wq, &local->tx_work); |
1056 | kfree_skb(local->rx_pending); | 1105 | kfree_skb(local->rx_pending); |
1057 | local->rx_pending = NULL; | 1106 | local->rx_pending = NULL; |
1058 | 1107 | ||
@@ -1071,7 +1120,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err) | |||
1071 | 1120 | ||
1072 | local->rx_pending = skb_get(skb); | 1121 | local->rx_pending = skb_get(skb); |
1073 | del_timer(&local->link_timer); | 1122 | del_timer(&local->link_timer); |
1074 | queue_work(local->rx_wq, &local->rx_work); | 1123 | queue_work(system_nrt_wq, &local->rx_work); |
1075 | 1124 | ||
1076 | return; | 1125 | return; |
1077 | } | 1126 | } |
@@ -1086,7 +1135,7 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) | |||
1086 | 1135 | ||
1087 | local->rx_pending = skb_get(skb); | 1136 | local->rx_pending = skb_get(skb); |
1088 | del_timer(&local->link_timer); | 1137 | del_timer(&local->link_timer); |
1089 | queue_work(local->rx_wq, &local->rx_work); | 1138 | queue_work(system_nrt_wq, &local->rx_work); |
1090 | 1139 | ||
1091 | return 0; | 1140 | return 0; |
1092 | } | 1141 | } |
@@ -1121,7 +1170,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | |||
1121 | if (rf_mode == NFC_RF_INITIATOR) { | 1170 | if (rf_mode == NFC_RF_INITIATOR) { |
1122 | pr_debug("Queueing Tx work\n"); | 1171 | pr_debug("Queueing Tx work\n"); |
1123 | 1172 | ||
1124 | queue_work(local->tx_wq, &local->tx_work); | 1173 | queue_work(system_nrt_wq, &local->tx_work); |
1125 | } else { | 1174 | } else { |
1126 | mod_timer(&local->link_timer, | 1175 | mod_timer(&local->link_timer, |
1127 | jiffies + msecs_to_jiffies(local->remote_lto)); | 1176 | jiffies + msecs_to_jiffies(local->remote_lto)); |
@@ -1130,10 +1179,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | |||
1130 | 1179 | ||
1131 | int nfc_llcp_register_device(struct nfc_dev *ndev) | 1180 | int nfc_llcp_register_device(struct nfc_dev *ndev) |
1132 | { | 1181 | { |
1133 | struct device *dev = &ndev->dev; | ||
1134 | struct nfc_llcp_local *local; | 1182 | struct nfc_llcp_local *local; |
1135 | char name[32]; | ||
1136 | int err; | ||
1137 | 1183 | ||
1138 | local = kzalloc(sizeof(struct nfc_llcp_local), GFP_KERNEL); | 1184 | local = kzalloc(sizeof(struct nfc_llcp_local), GFP_KERNEL); |
1139 | if (local == NULL) | 1185 | if (local == NULL) |
@@ -1149,41 +1195,15 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1149 | 1195 | ||
1150 | skb_queue_head_init(&local->tx_queue); | 1196 | skb_queue_head_init(&local->tx_queue); |
1151 | INIT_WORK(&local->tx_work, nfc_llcp_tx_work); | 1197 | INIT_WORK(&local->tx_work, nfc_llcp_tx_work); |
1152 | snprintf(name, sizeof(name), "%s_llcp_tx_wq", dev_name(dev)); | ||
1153 | local->tx_wq = | ||
1154 | alloc_workqueue(name, | ||
1155 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1156 | 1); | ||
1157 | if (local->tx_wq == NULL) { | ||
1158 | err = -ENOMEM; | ||
1159 | goto err_local; | ||
1160 | } | ||
1161 | 1198 | ||
1162 | local->rx_pending = NULL; | 1199 | local->rx_pending = NULL; |
1163 | INIT_WORK(&local->rx_work, nfc_llcp_rx_work); | 1200 | INIT_WORK(&local->rx_work, nfc_llcp_rx_work); |
1164 | snprintf(name, sizeof(name), "%s_llcp_rx_wq", dev_name(dev)); | ||
1165 | local->rx_wq = | ||
1166 | alloc_workqueue(name, | ||
1167 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1168 | 1); | ||
1169 | if (local->rx_wq == NULL) { | ||
1170 | err = -ENOMEM; | ||
1171 | goto err_tx_wq; | ||
1172 | } | ||
1173 | 1201 | ||
1174 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); | 1202 | INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work); |
1175 | snprintf(name, sizeof(name), "%s_llcp_timeout_wq", dev_name(dev)); | ||
1176 | local->timeout_wq = | ||
1177 | alloc_workqueue(name, | ||
1178 | WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, | ||
1179 | 1); | ||
1180 | if (local->timeout_wq == NULL) { | ||
1181 | err = -ENOMEM; | ||
1182 | goto err_rx_wq; | ||
1183 | } | ||
1184 | 1203 | ||
1185 | local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock); | 1204 | rwlock_init(&local->sockets.lock); |
1186 | local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock); | 1205 | rwlock_init(&local->connecting_sockets.lock); |
1206 | rwlock_init(&local->raw_sockets.lock); | ||
1187 | 1207 | ||
1188 | nfc_llcp_build_gb(local); | 1208 | nfc_llcp_build_gb(local); |
1189 | 1209 | ||
@@ -1193,17 +1213,6 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1193 | list_add(&llcp_devices, &local->list); | 1213 | list_add(&llcp_devices, &local->list); |
1194 | 1214 | ||
1195 | return 0; | 1215 | return 0; |
1196 | |||
1197 | err_rx_wq: | ||
1198 | destroy_workqueue(local->rx_wq); | ||
1199 | |||
1200 | err_tx_wq: | ||
1201 | destroy_workqueue(local->tx_wq); | ||
1202 | |||
1203 | err_local: | ||
1204 | kfree(local); | ||
1205 | |||
1206 | return 0; | ||
1207 | } | 1216 | } |
1208 | 1217 | ||
1209 | void nfc_llcp_unregister_device(struct nfc_dev *dev) | 1218 | void nfc_llcp_unregister_device(struct nfc_dev *dev) |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 83b8bba5a280..fdb2d24e60bd 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -56,12 +56,9 @@ struct nfc_llcp_local { | |||
56 | 56 | ||
57 | struct timer_list link_timer; | 57 | struct timer_list link_timer; |
58 | struct sk_buff_head tx_queue; | 58 | struct sk_buff_head tx_queue; |
59 | struct workqueue_struct *tx_wq; | ||
60 | struct work_struct tx_work; | 59 | struct work_struct tx_work; |
61 | struct workqueue_struct *rx_wq; | ||
62 | struct work_struct rx_work; | 60 | struct work_struct rx_work; |
63 | struct sk_buff *rx_pending; | 61 | struct sk_buff *rx_pending; |
64 | struct workqueue_struct *timeout_wq; | ||
65 | struct work_struct timeout_work; | 62 | struct work_struct timeout_work; |
66 | 63 | ||
67 | u32 target_idx; | 64 | u32 target_idx; |
@@ -89,6 +86,7 @@ struct nfc_llcp_local { | |||
89 | /* sockets array */ | 86 | /* sockets array */ |
90 | struct llcp_sock_list sockets; | 87 | struct llcp_sock_list sockets; |
91 | struct llcp_sock_list connecting_sockets; | 88 | struct llcp_sock_list connecting_sockets; |
89 | struct llcp_sock_list raw_sockets; | ||
92 | }; | 90 | }; |
93 | 91 | ||
94 | struct nfc_llcp_sock { | 92 | struct nfc_llcp_sock { |
@@ -187,6 +185,8 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | |||
187 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); | 185 | u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local); |
188 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); | 186 | void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap); |
189 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); | 187 | int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock); |
188 | void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, | ||
189 | struct sk_buff *skb, u8 direction); | ||
190 | 190 | ||
191 | /* Sock API */ | 191 | /* Sock API */ |
192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); | 192 | struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index ddeb9aa398f0..40f056debf9a 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -142,6 +142,60 @@ error: | |||
142 | return ret; | 142 | return ret; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr, | ||
146 | int alen) | ||
147 | { | ||
148 | struct sock *sk = sock->sk; | ||
149 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
150 | struct nfc_llcp_local *local; | ||
151 | struct nfc_dev *dev; | ||
152 | struct sockaddr_nfc_llcp llcp_addr; | ||
153 | int len, ret = 0; | ||
154 | |||
155 | if (!addr || addr->sa_family != AF_NFC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
159 | |||
160 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | ||
161 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | ||
162 | memcpy(&llcp_addr, addr, len); | ||
163 | |||
164 | lock_sock(sk); | ||
165 | |||
166 | if (sk->sk_state != LLCP_CLOSED) { | ||
167 | ret = -EBADFD; | ||
168 | goto error; | ||
169 | } | ||
170 | |||
171 | dev = nfc_get_device(llcp_addr.dev_idx); | ||
172 | if (dev == NULL) { | ||
173 | ret = -ENODEV; | ||
174 | goto error; | ||
175 | } | ||
176 | |||
177 | local = nfc_llcp_find_local(dev); | ||
178 | if (local == NULL) { | ||
179 | ret = -ENODEV; | ||
180 | goto put_dev; | ||
181 | } | ||
182 | |||
183 | llcp_sock->dev = dev; | ||
184 | llcp_sock->local = nfc_llcp_local_get(local); | ||
185 | llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; | ||
186 | |||
187 | nfc_llcp_sock_link(&local->raw_sockets, sk); | ||
188 | |||
189 | sk->sk_state = LLCP_BOUND; | ||
190 | |||
191 | put_dev: | ||
192 | nfc_put_device(dev); | ||
193 | |||
194 | error: | ||
195 | release_sock(sk); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
145 | static int llcp_sock_listen(struct socket *sock, int backlog) | 199 | static int llcp_sock_listen(struct socket *sock, int backlog) |
146 | { | 200 | { |
147 | struct sock *sk = sock->sk; | 201 | struct sock *sk = sock->sk; |
@@ -300,9 +354,6 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, | |||
300 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, | 354 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, |
301 | llcp_sock->dsap, llcp_sock->ssap); | 355 | llcp_sock->dsap, llcp_sock->ssap); |
302 | 356 | ||
303 | if (llcp_sock == NULL || llcp_sock->dev == NULL) | ||
304 | return -EBADFD; | ||
305 | |||
306 | uaddr->sa_family = AF_NFC; | 357 | uaddr->sa_family = AF_NFC; |
307 | 358 | ||
308 | *len = sizeof(struct sockaddr_nfc_llcp); | 359 | *len = sizeof(struct sockaddr_nfc_llcp); |
@@ -421,7 +472,10 @@ static int llcp_sock_release(struct socket *sock) | |||
421 | 472 | ||
422 | release_sock(sk); | 473 | release_sock(sk); |
423 | 474 | ||
424 | nfc_llcp_sock_unlink(&local->sockets, sk); | 475 | if (sock->type == SOCK_RAW) |
476 | nfc_llcp_sock_unlink(&local->raw_sockets, sk); | ||
477 | else | ||
478 | nfc_llcp_sock_unlink(&local->sockets, sk); | ||
425 | 479 | ||
426 | out: | 480 | out: |
427 | sock_orphan(sk); | 481 | sock_orphan(sk); |
@@ -617,7 +671,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
617 | if (!(flags & MSG_PEEK)) { | 671 | if (!(flags & MSG_PEEK)) { |
618 | 672 | ||
619 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ | 673 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ |
620 | if (sk->sk_type == SOCK_STREAM) { | 674 | if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) { |
621 | skb_pull(skb, copied); | 675 | skb_pull(skb, copied); |
622 | if (skb->len) { | 676 | if (skb->len) { |
623 | skb_queue_head(&sk->sk_receive_queue, skb); | 677 | skb_queue_head(&sk->sk_receive_queue, skb); |
@@ -658,6 +712,26 @@ static const struct proto_ops llcp_sock_ops = { | |||
658 | .mmap = sock_no_mmap, | 712 | .mmap = sock_no_mmap, |
659 | }; | 713 | }; |
660 | 714 | ||
715 | static const struct proto_ops llcp_rawsock_ops = { | ||
716 | .family = PF_NFC, | ||
717 | .owner = THIS_MODULE, | ||
718 | .bind = llcp_raw_sock_bind, | ||
719 | .connect = sock_no_connect, | ||
720 | .release = llcp_sock_release, | ||
721 | .socketpair = sock_no_socketpair, | ||
722 | .accept = sock_no_accept, | ||
723 | .getname = llcp_sock_getname, | ||
724 | .poll = llcp_sock_poll, | ||
725 | .ioctl = sock_no_ioctl, | ||
726 | .listen = sock_no_listen, | ||
727 | .shutdown = sock_no_shutdown, | ||
728 | .setsockopt = sock_no_setsockopt, | ||
729 | .getsockopt = sock_no_getsockopt, | ||
730 | .sendmsg = sock_no_sendmsg, | ||
731 | .recvmsg = llcp_sock_recvmsg, | ||
732 | .mmap = sock_no_mmap, | ||
733 | }; | ||
734 | |||
661 | static void llcp_sock_destruct(struct sock *sk) | 735 | static void llcp_sock_destruct(struct sock *sk) |
662 | { | 736 | { |
663 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 737 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -735,10 +809,15 @@ static int llcp_sock_create(struct net *net, struct socket *sock, | |||
735 | 809 | ||
736 | pr_debug("%p\n", sock); | 810 | pr_debug("%p\n", sock); |
737 | 811 | ||
738 | if (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM) | 812 | if (sock->type != SOCK_STREAM && |
813 | sock->type != SOCK_DGRAM && | ||
814 | sock->type != SOCK_RAW) | ||
739 | return -ESOCKTNOSUPPORT; | 815 | return -ESOCKTNOSUPPORT; |
740 | 816 | ||
741 | sock->ops = &llcp_sock_ops; | 817 | if (sock->type == SOCK_RAW) |
818 | sock->ops = &llcp_rawsock_ops; | ||
819 | else | ||
820 | sock->ops = &llcp_sock_ops; | ||
742 | 821 | ||
743 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); | 822 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); |
744 | if (sk == NULL) | 823 | if (sk == NULL) |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index f81efe13985a..acf9abb7d99b 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -176,6 +176,27 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt) | |||
176 | (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); | 176 | (1 + ((*num) * sizeof(struct disc_map_config))), &cmd); |
177 | } | 177 | } |
178 | 178 | ||
179 | struct nci_set_config_param { | ||
180 | __u8 id; | ||
181 | size_t len; | ||
182 | __u8 *val; | ||
183 | }; | ||
184 | |||
185 | static void nci_set_config_req(struct nci_dev *ndev, unsigned long opt) | ||
186 | { | ||
187 | struct nci_set_config_param *param = (struct nci_set_config_param *)opt; | ||
188 | struct nci_core_set_config_cmd cmd; | ||
189 | |||
190 | BUG_ON(param->len > NCI_MAX_PARAM_LEN); | ||
191 | |||
192 | cmd.num_params = 1; | ||
193 | cmd.param.id = param->id; | ||
194 | cmd.param.len = param->len; | ||
195 | memcpy(cmd.param.val, param->val, param->len); | ||
196 | |||
197 | nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd); | ||
198 | } | ||
199 | |||
179 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | 200 | static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) |
180 | { | 201 | { |
181 | struct nci_rf_disc_cmd cmd; | 202 | struct nci_rf_disc_cmd cmd; |
@@ -388,6 +409,32 @@ static int nci_dev_down(struct nfc_dev *nfc_dev) | |||
388 | return nci_close_device(ndev); | 409 | return nci_close_device(ndev); |
389 | } | 410 | } |
390 | 411 | ||
412 | static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) | ||
413 | { | ||
414 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
415 | struct nci_set_config_param param; | ||
416 | __u8 local_gb[NFC_MAX_GT_LEN]; | ||
417 | int i, rc = 0; | ||
418 | |||
419 | param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); | ||
420 | if ((param.val == NULL) || (param.len == 0)) | ||
421 | return rc; | ||
422 | |||
423 | if (param.len > NCI_MAX_PARAM_LEN) | ||
424 | return -EINVAL; | ||
425 | |||
426 | for (i = 0; i < param.len; i++) | ||
427 | local_gb[param.len-1-i] = param.val[i]; | ||
428 | |||
429 | param.id = NCI_PN_ATR_REQ_GEN_BYTES; | ||
430 | param.val = local_gb; | ||
431 | |||
432 | rc = nci_request(ndev, nci_set_config_req, (unsigned long)¶m, | ||
433 | msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); | ||
434 | |||
435 | return rc; | ||
436 | } | ||
437 | |||
391 | static int nci_start_poll(struct nfc_dev *nfc_dev, | 438 | static int nci_start_poll(struct nfc_dev *nfc_dev, |
392 | __u32 im_protocols, __u32 tm_protocols) | 439 | __u32 im_protocols, __u32 tm_protocols) |
393 | { | 440 | { |
@@ -415,6 +462,14 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, | |||
415 | return -EBUSY; | 462 | return -EBUSY; |
416 | } | 463 | } |
417 | 464 | ||
465 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { | ||
466 | rc = nci_set_local_general_bytes(nfc_dev); | ||
467 | if (rc) { | ||
468 | pr_err("failed to set local general bytes\n"); | ||
469 | return rc; | ||
470 | } | ||
471 | } | ||
472 | |||
418 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, | 473 | rc = nci_request(ndev, nci_rf_discover_req, im_protocols, |
419 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); | 474 | msecs_to_jiffies(NCI_RF_DISC_TIMEOUT)); |
420 | 475 | ||
@@ -509,7 +564,7 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
509 | { | 564 | { |
510 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | 565 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); |
511 | 566 | ||
512 | pr_debug("target_idx %d\n", target->idx); | 567 | pr_debug("entry\n"); |
513 | 568 | ||
514 | if (!ndev->target_active_prot) { | 569 | if (!ndev->target_active_prot) { |
515 | pr_err("unable to deactivate target, no active target\n"); | 570 | pr_err("unable to deactivate target, no active target\n"); |
@@ -524,6 +579,38 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, | |||
524 | } | 579 | } |
525 | } | 580 | } |
526 | 581 | ||
582 | |||
583 | static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, | ||
584 | __u8 comm_mode, __u8 *gb, size_t gb_len) | ||
585 | { | ||
586 | struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); | ||
587 | int rc; | ||
588 | |||
589 | pr_debug("target_idx %d, comm_mode %d\n", target->idx, comm_mode); | ||
590 | |||
591 | rc = nci_activate_target(nfc_dev, target, NFC_PROTO_NFC_DEP); | ||
592 | if (rc) | ||
593 | return rc; | ||
594 | |||
595 | rc = nfc_set_remote_general_bytes(nfc_dev, ndev->remote_gb, | ||
596 | ndev->remote_gb_len); | ||
597 | if (!rc) | ||
598 | rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_PASSIVE, | ||
599 | NFC_RF_INITIATOR); | ||
600 | |||
601 | return rc; | ||
602 | } | ||
603 | |||
604 | static int nci_dep_link_down(struct nfc_dev *nfc_dev) | ||
605 | { | ||
606 | pr_debug("entry\n"); | ||
607 | |||
608 | nci_deactivate_target(nfc_dev, NULL); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | |||
527 | static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, | 614 | static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, |
528 | struct sk_buff *skb, | 615 | struct sk_buff *skb, |
529 | data_exchange_cb_t cb, void *cb_context) | 616 | data_exchange_cb_t cb, void *cb_context) |
@@ -557,6 +644,8 @@ static struct nfc_ops nci_nfc_ops = { | |||
557 | .dev_down = nci_dev_down, | 644 | .dev_down = nci_dev_down, |
558 | .start_poll = nci_start_poll, | 645 | .start_poll = nci_start_poll, |
559 | .stop_poll = nci_stop_poll, | 646 | .stop_poll = nci_stop_poll, |
647 | .dep_link_up = nci_dep_link_up, | ||
648 | .dep_link_down = nci_dep_link_down, | ||
560 | .activate_target = nci_activate_target, | 649 | .activate_target = nci_activate_target, |
561 | .deactivate_target = nci_deactivate_target, | 650 | .deactivate_target = nci_deactivate_target, |
562 | .im_transceive = nci_transceive, | 651 | .im_transceive = nci_transceive, |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index af7a93b04393..b2aa98ef0927 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -176,6 +176,8 @@ static int nci_add_new_protocol(struct nci_dev *ndev, | |||
176 | protocol = NFC_PROTO_ISO14443_B_MASK; | 176 | protocol = NFC_PROTO_ISO14443_B_MASK; |
177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) | 177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) |
178 | protocol = NFC_PROTO_FELICA_MASK; | 178 | protocol = NFC_PROTO_FELICA_MASK; |
179 | else if (rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) | ||
180 | protocol = NFC_PROTO_NFC_DEP_MASK; | ||
179 | else | 181 | else |
180 | protocol = 0; | 182 | protocol = 0; |
181 | 183 | ||
@@ -361,6 +363,33 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, | |||
361 | return NCI_STATUS_OK; | 363 | return NCI_STATUS_OK; |
362 | } | 364 | } |
363 | 365 | ||
366 | static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, | ||
367 | struct nci_rf_intf_activated_ntf *ntf, __u8 *data) | ||
368 | { | ||
369 | struct activation_params_poll_nfc_dep *poll; | ||
370 | int i; | ||
371 | |||
372 | switch (ntf->activation_rf_tech_and_mode) { | ||
373 | case NCI_NFC_A_PASSIVE_POLL_MODE: | ||
374 | case NCI_NFC_F_PASSIVE_POLL_MODE: | ||
375 | poll = &ntf->activation_params.poll_nfc_dep; | ||
376 | poll->atr_res_len = min_t(__u8, *data++, 63); | ||
377 | pr_debug("atr_res_len %d\n", poll->atr_res_len); | ||
378 | if (poll->atr_res_len > 0) { | ||
379 | for (i = 0; i < poll->atr_res_len; i++) | ||
380 | poll->atr_res[poll->atr_res_len-1-i] = data[i]; | ||
381 | } | ||
382 | break; | ||
383 | |||
384 | default: | ||
385 | pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", | ||
386 | ntf->activation_rf_tech_and_mode); | ||
387 | return NCI_STATUS_RF_PROTOCOL_ERROR; | ||
388 | } | ||
389 | |||
390 | return NCI_STATUS_OK; | ||
391 | } | ||
392 | |||
364 | static void nci_target_auto_activated(struct nci_dev *ndev, | 393 | static void nci_target_auto_activated(struct nci_dev *ndev, |
365 | struct nci_rf_intf_activated_ntf *ntf) | 394 | struct nci_rf_intf_activated_ntf *ntf) |
366 | { | 395 | { |
@@ -454,6 +483,11 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev, | |||
454 | &ntf, data); | 483 | &ntf, data); |
455 | break; | 484 | break; |
456 | 485 | ||
486 | case NCI_RF_INTERFACE_NFC_DEP: | ||
487 | err = nci_extract_activation_params_nfc_dep(ndev, | ||
488 | &ntf, data); | ||
489 | break; | ||
490 | |||
457 | case NCI_RF_INTERFACE_FRAME: | 491 | case NCI_RF_INTERFACE_FRAME: |
458 | /* no activation params */ | 492 | /* no activation params */ |
459 | break; | 493 | break; |
@@ -473,6 +507,24 @@ exit: | |||
473 | 507 | ||
474 | /* set the available credits to initial value */ | 508 | /* set the available credits to initial value */ |
475 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); | 509 | atomic_set(&ndev->credits_cnt, ndev->initial_num_credits); |
510 | |||
511 | /* store general bytes to be reported later in dep_link_up */ | ||
512 | if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) { | ||
513 | ndev->remote_gb_len = 0; | ||
514 | |||
515 | if (ntf.activation_params_len > 0) { | ||
516 | /* ATR_RES general bytes at offset 15 */ | ||
517 | ndev->remote_gb_len = min_t(__u8, | ||
518 | (ntf.activation_params | ||
519 | .poll_nfc_dep.atr_res_len | ||
520 | - NFC_ATR_RES_GT_OFFSET), | ||
521 | NFC_MAX_GT_LEN); | ||
522 | memcpy(ndev->remote_gb, | ||
523 | (ntf.activation_params.poll_nfc_dep | ||
524 | .atr_res + NFC_ATR_RES_GT_OFFSET), | ||
525 | ndev->remote_gb_len); | ||
526 | } | ||
527 | } | ||
476 | } | 528 | } |
477 | 529 | ||
478 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { | 530 | if (atomic_read(&ndev->state) == NCI_DISCOVERY) { |
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 3003c3390e49..dd072f38ad00 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c | |||
@@ -119,6 +119,16 @@ exit: | |||
119 | nci_req_complete(ndev, rsp_1->status); | 119 | nci_req_complete(ndev, rsp_1->status); |
120 | } | 120 | } |
121 | 121 | ||
122 | static void nci_core_set_config_rsp_packet(struct nci_dev *ndev, | ||
123 | struct sk_buff *skb) | ||
124 | { | ||
125 | struct nci_core_set_config_rsp *rsp = (void *) skb->data; | ||
126 | |||
127 | pr_debug("status 0x%x\n", rsp->status); | ||
128 | |||
129 | nci_req_complete(ndev, rsp->status); | ||
130 | } | ||
131 | |||
122 | static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, | 132 | static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, |
123 | struct sk_buff *skb) | 133 | struct sk_buff *skb) |
124 | { | 134 | { |
@@ -194,6 +204,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) | |||
194 | nci_core_init_rsp_packet(ndev, skb); | 204 | nci_core_init_rsp_packet(ndev, skb); |
195 | break; | 205 | break; |
196 | 206 | ||
207 | case NCI_OP_CORE_SET_CONFIG_RSP: | ||
208 | nci_core_set_config_rsp_packet(ndev, skb); | ||
209 | break; | ||
210 | |||
197 | case NCI_OP_RF_DISCOVER_MAP_RSP: | 211 | case NCI_OP_RF_DISCOVER_MAP_RSP: |
198 | nci_rf_disc_map_rsp_packet(ndev, skb); | 212 | nci_rf_disc_map_rsp_packet(ndev, skb); |
199 | break; | 213 | break; |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 4bbb70e32d1e..c1b5285cbde7 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -761,31 +761,63 @@ static struct genl_ops nfc_genl_ops[] = { | |||
761 | }, | 761 | }, |
762 | }; | 762 | }; |
763 | 763 | ||
764 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | 764 | |
765 | unsigned long event, void *ptr) | 765 | struct urelease_work { |
766 | struct work_struct w; | ||
767 | int portid; | ||
768 | }; | ||
769 | |||
770 | static void nfc_urelease_event_work(struct work_struct *work) | ||
766 | { | 771 | { |
767 | struct netlink_notify *n = ptr; | 772 | struct urelease_work *w = container_of(work, struct urelease_work, w); |
768 | struct class_dev_iter iter; | 773 | struct class_dev_iter iter; |
769 | struct nfc_dev *dev; | 774 | struct nfc_dev *dev; |
770 | 775 | ||
771 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | 776 | pr_debug("portid %d\n", w->portid); |
772 | goto out; | ||
773 | 777 | ||
774 | pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); | 778 | mutex_lock(&nfc_devlist_mutex); |
775 | 779 | ||
776 | nfc_device_iter_init(&iter); | 780 | nfc_device_iter_init(&iter); |
777 | dev = nfc_device_iter_next(&iter); | 781 | dev = nfc_device_iter_next(&iter); |
778 | 782 | ||
779 | while (dev) { | 783 | while (dev) { |
780 | if (dev->genl_data.poll_req_portid == n->portid) { | 784 | mutex_lock(&dev->genl_data.genl_data_mutex); |
785 | |||
786 | if (dev->genl_data.poll_req_portid == w->portid) { | ||
781 | nfc_stop_poll(dev); | 787 | nfc_stop_poll(dev); |
782 | dev->genl_data.poll_req_portid = 0; | 788 | dev->genl_data.poll_req_portid = 0; |
783 | } | 789 | } |
790 | |||
791 | mutex_unlock(&dev->genl_data.genl_data_mutex); | ||
792 | |||
784 | dev = nfc_device_iter_next(&iter); | 793 | dev = nfc_device_iter_next(&iter); |
785 | } | 794 | } |
786 | 795 | ||
787 | nfc_device_iter_exit(&iter); | 796 | nfc_device_iter_exit(&iter); |
788 | 797 | ||
798 | mutex_unlock(&nfc_devlist_mutex); | ||
799 | |||
800 | kfree(w); | ||
801 | } | ||
802 | |||
803 | static int nfc_genl_rcv_nl_event(struct notifier_block *this, | ||
804 | unsigned long event, void *ptr) | ||
805 | { | ||
806 | struct netlink_notify *n = ptr; | ||
807 | struct urelease_work *w; | ||
808 | |||
809 | if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) | ||
810 | goto out; | ||
811 | |||
812 | pr_debug("NETLINK_URELEASE event from id %d\n", n->portid); | ||
813 | |||
814 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | ||
815 | if (w) { | ||
816 | INIT_WORK((struct work_struct *) w, nfc_urelease_event_work); | ||
817 | w->portid = n->portid; | ||
818 | schedule_work((struct work_struct *) w); | ||
819 | } | ||
820 | |||
789 | out: | 821 | out: |
790 | return NOTIFY_DONE; | 822 | return NOTIFY_DONE; |
791 | } | 823 | } |
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index c275bad12068..a5c952741279 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -270,6 +270,7 @@ static bool __rfkill_set_hw_state(struct rfkill *rfkill, | |||
270 | static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | 270 | static void rfkill_set_block(struct rfkill *rfkill, bool blocked) |
271 | { | 271 | { |
272 | unsigned long flags; | 272 | unsigned long flags; |
273 | bool prev, curr; | ||
273 | int err; | 274 | int err; |
274 | 275 | ||
275 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | 276 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) |
@@ -284,6 +285,8 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
284 | rfkill->ops->query(rfkill, rfkill->data); | 285 | rfkill->ops->query(rfkill, rfkill->data); |
285 | 286 | ||
286 | spin_lock_irqsave(&rfkill->lock, flags); | 287 | spin_lock_irqsave(&rfkill->lock, flags); |
288 | prev = rfkill->state & RFKILL_BLOCK_SW; | ||
289 | |||
287 | if (rfkill->state & RFKILL_BLOCK_SW) | 290 | if (rfkill->state & RFKILL_BLOCK_SW) |
288 | rfkill->state |= RFKILL_BLOCK_SW_PREV; | 291 | rfkill->state |= RFKILL_BLOCK_SW_PREV; |
289 | else | 292 | else |
@@ -313,10 +316,13 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
313 | } | 316 | } |
314 | rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; | 317 | rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; |
315 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; | 318 | rfkill->state &= ~RFKILL_BLOCK_SW_PREV; |
319 | curr = rfkill->state & RFKILL_BLOCK_SW; | ||
316 | spin_unlock_irqrestore(&rfkill->lock, flags); | 320 | spin_unlock_irqrestore(&rfkill->lock, flags); |
317 | 321 | ||
318 | rfkill_led_trigger_event(rfkill); | 322 | rfkill_led_trigger_event(rfkill); |
319 | rfkill_event(rfkill); | 323 | |
324 | if (prev != curr) | ||
325 | rfkill_event(rfkill); | ||
320 | } | 326 | } |
321 | 327 | ||
322 | #ifdef CONFIG_RFKILL_INPUT | 328 | #ifdef CONFIG_RFKILL_INPUT |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ec7fcee5bad6..8016fee0752b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -612,6 +612,17 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | |||
612 | } | 612 | } |
613 | EXPORT_SYMBOL(cfg80211_del_sta); | 613 | EXPORT_SYMBOL(cfg80211_del_sta); |
614 | 614 | ||
615 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | ||
616 | enum nl80211_connect_failed_reason reason, | ||
617 | gfp_t gfp) | ||
618 | { | ||
619 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
620 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
621 | |||
622 | nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp); | ||
623 | } | ||
624 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
625 | |||
615 | struct cfg80211_mgmt_registration { | 626 | struct cfg80211_mgmt_registration { |
616 | struct list_head list; | 627 | struct list_head list; |
617 | 628 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 139946dc8020..0418a6d5c1a6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -8364,6 +8364,40 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
8364 | nlmsg_free(msg); | 8364 | nlmsg_free(msg); |
8365 | } | 8365 | } |
8366 | 8366 | ||
8367 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | ||
8368 | struct net_device *dev, const u8 *mac_addr, | ||
8369 | enum nl80211_connect_failed_reason reason, | ||
8370 | gfp_t gfp) | ||
8371 | { | ||
8372 | struct sk_buff *msg; | ||
8373 | void *hdr; | ||
8374 | |||
8375 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
8376 | if (!msg) | ||
8377 | return; | ||
8378 | |||
8379 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONN_FAILED); | ||
8380 | if (!hdr) { | ||
8381 | nlmsg_free(msg); | ||
8382 | return; | ||
8383 | } | ||
8384 | |||
8385 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
8386 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr) || | ||
8387 | nla_put_u32(msg, NL80211_ATTR_CONN_FAILED_REASON, reason)) | ||
8388 | goto nla_put_failure; | ||
8389 | |||
8390 | genlmsg_end(msg, hdr); | ||
8391 | |||
8392 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
8393 | nl80211_mlme_mcgrp.id, gfp); | ||
8394 | return; | ||
8395 | |||
8396 | nla_put_failure: | ||
8397 | genlmsg_cancel(msg, hdr); | ||
8398 | nlmsg_free(msg); | ||
8399 | } | ||
8400 | |||
8367 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | 8401 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, |
8368 | const u8 *addr, gfp_t gfp) | 8402 | const u8 *addr, gfp_t gfp) |
8369 | { | 8403 | { |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 9f2616fffb40..f6153516068c 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -91,6 +91,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
91 | struct net_device *dev, const u8 *mac_addr, | 91 | struct net_device *dev, const u8 *mac_addr, |
92 | gfp_t gfp); | 92 | gfp_t gfp); |
93 | 93 | ||
94 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | ||
95 | struct net_device *dev, const u8 *mac_addr, | ||
96 | enum nl80211_connect_failed_reason reason, | ||
97 | gfp_t gfp); | ||
98 | |||
94 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 99 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
95 | struct wireless_dev *wdev, u32 nlpid, | 100 | struct wireless_dev *wdev, u32 nlpid, |
96 | int freq, int sig_dbm, | 101 | int freq, int sig_dbm, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4de18ae18d34..3b8cbbc214db 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -510,9 +510,11 @@ static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, | |||
510 | * | 510 | * |
511 | * This lets us know if a specific frequency rule is or is not relevant to | 511 | * This lets us know if a specific frequency rule is or is not relevant to |
512 | * a specific frequency's band. Bands are device specific and artificial | 512 | * a specific frequency's band. Bands are device specific and artificial |
513 | * definitions (the "2.4 GHz band" and the "5 GHz band"), however it is | 513 | * definitions (the "2.4 GHz band", the "5 GHz band" and the "60GHz band"), |
514 | * safe for now to assume that a frequency rule should not be part of a | 514 | * however it is safe for now to assume that a frequency rule should not be |
515 | * frequency's band if the start freq or end freq are off by more than 2 GHz. | 515 | * part of a frequency's band if the start freq or end freq are off by more |
516 | * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 10 GHz for the | ||
517 | * 60 GHz band. | ||
516 | * This resolution can be lowered and should be considered as we add | 518 | * This resolution can be lowered and should be considered as we add |
517 | * regulatory rule support for other "bands". | 519 | * regulatory rule support for other "bands". |
518 | **/ | 520 | **/ |
@@ -520,9 +522,16 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
520 | u32 freq_khz) | 522 | u32 freq_khz) |
521 | { | 523 | { |
522 | #define ONE_GHZ_IN_KHZ 1000000 | 524 | #define ONE_GHZ_IN_KHZ 1000000 |
523 | if (abs(freq_khz - freq_range->start_freq_khz) <= (2 * ONE_GHZ_IN_KHZ)) | 525 | /* |
526 | * From 802.11ad: directional multi-gigabit (DMG): | ||
527 | * Pertaining to operation in a frequency band containing a channel | ||
528 | * with the Channel starting frequency above 45 GHz. | ||
529 | */ | ||
530 | u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? | ||
531 | 10 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; | ||
532 | if (abs(freq_khz - freq_range->start_freq_khz) <= limit) | ||
524 | return true; | 533 | return true; |
525 | if (abs(freq_khz - freq_range->end_freq_khz) <= (2 * ONE_GHZ_IN_KHZ)) | 534 | if (abs(freq_khz - freq_range->end_freq_khz) <= limit) |
526 | return true; | 535 | return true; |
527 | return false; | 536 | return false; |
528 | #undef ONE_GHZ_IN_KHZ | 537 | #undef ONE_GHZ_IN_KHZ |
@@ -2199,7 +2208,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
2199 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 2208 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
2200 | { | 2209 | { |
2201 | const struct ieee80211_regdomain *intersected_rd = NULL; | 2210 | const struct ieee80211_regdomain *intersected_rd = NULL; |
2202 | struct cfg80211_registered_device *rdev = NULL; | ||
2203 | struct wiphy *request_wiphy; | 2211 | struct wiphy *request_wiphy; |
2204 | /* Some basic sanity checks first */ | 2212 | /* Some basic sanity checks first */ |
2205 | 2213 | ||
@@ -2311,24 +2319,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2311 | return 0; | 2319 | return 0; |
2312 | } | 2320 | } |
2313 | 2321 | ||
2314 | if (!intersected_rd) | 2322 | return -EINVAL; |
2315 | return -EINVAL; | ||
2316 | |||
2317 | rdev = wiphy_to_dev(request_wiphy); | ||
2318 | |||
2319 | rdev->country_ie_alpha2[0] = rd->alpha2[0]; | ||
2320 | rdev->country_ie_alpha2[1] = rd->alpha2[1]; | ||
2321 | rdev->env = last_request->country_ie_env; | ||
2322 | |||
2323 | BUG_ON(intersected_rd == rd); | ||
2324 | |||
2325 | kfree(rd); | ||
2326 | rd = NULL; | ||
2327 | |||
2328 | reset_regdomains(false); | ||
2329 | cfg80211_regdomain = intersected_rd; | ||
2330 | |||
2331 | return 0; | ||
2332 | } | 2323 | } |
2333 | 2324 | ||
2334 | 2325 | ||